<commit_before>"use strict";
angular.module("info.vietnamcode.nampnq.videogular.plugins.youtube", [])
    .run(['$rootScope', '$window',
        function($rootScope, $window) {
            $rootScope.youtubeApiReady = false;
            $window.onYouTubeIframeAPIReady = function() {
                $rootScope.$apply(function() {
                    $rootScope.youtubeApiReady = true;
                });
            };
            var tag = document.createElement('script');
            tag.src = "https://www.youtube.com/iframe_api";
            var firstScriptTag = document.getElementsByTagName('script')[0];
            firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
        }
    ])
    .directive(
        "vgYoutube", ["$rootScope", "$window", "$timeout", "$interval", "VG_STATES",
            function($rootScope, $window, $timeout, $interval, VG_STATES) {
                return {
                    restrict: "A",
                    require: "^videogular",
                    link: function(scope, elem, attr, API) {
                        var ytplayer, updateTimer, optionsArr, playerVars;

                        var youtubeReg = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/;
                        optionsArr = attr.vgYoutube !== null ? attr.vgYoutube.split(";") : null;
                        playerVars = {
                            'controls': 0,
                            'showinfo': 0,
                            'rel': 0,
                            'autoplay': 0, //Switch autoplay to 1 to autoplay videos
                            'start': 0
                        };

                        if (optionsArr !== null) {
                            optionsArr.forEach(function (item) {
                                var keyValuePair = item.split("=");
                                if (playerVars.hasOwnProperty(keyValuePair[0])) {
                                  playerVars[keyValuePair[0]] = keyValuePair[1] || 0;
                                }
                            });
                        }

                        function getYoutubeId(url) {
                            return url.match(youtubeReg)[2];
                        }

                        function initYoutubePlayer(url) {
                            if (ytplayer) {
                                ytplayer.cueVideoById({
                                    videoId: getYoutubeId(url)
                                  });
                            } else {
                                $rootScope.$watch('youtubeApiReady', function(value) {
                                    if (value) {
                                        ytplayer = new YT.Player(API.mediaElement[0], {
                                            videoId: getYoutubeId(url),
                                            playerVars: playerVars,
                                            events: {
                                                'onReady': onVideoReady,
                                                'onStateChange': onVideoStateChange
                                            }
                                        });
                                    }
                                });
                            }
                        }

                        function destroyYoutubePlayer() {
                            ytplayer.destroy();
                        }

                        function onVideoReady() {
                            //Define some property, method for player
                            API.mediaElement[0].__defineGetter__("currentTime", function () {
                                return ytplayer.getCurrentTime();
                            });
                            API.mediaElement[0].__defineSetter__("currentTime", function (seconds) {
                                return ytplayer.seekTo(seconds, true);
                            });
                            API.mediaElement[0].__defineGetter__("duration", function () {
                                return ytplayer.getDuration();
                            });
                            API.mediaElement[0].__defineGetter__("paused", function () {
                                return ytplayer.getPlayerState() != YT.PlayerState.PLAYING;
                            });
                            API.mediaElement[0].__defineGetter__("videoWidth", function () {
                                return ytplayer.a.width;
                            });
                            API.mediaElement[0].__defineGetter__("videoHeight", function () {
                                return ytplayer.a.height;
                            });
                            API.mediaElement[0].__defineGetter__("volume", function () {
                                return ytplayer.getVolume() / 100.0;
                            });
                            API.mediaElement[0].__defineSetter__("volume", function (volume) {
                                return ytplayer.setVolume(volume * 100.0);
                            });
                            API.mediaElement[0].__defineGetter__("playbackRate", function () {
                                return ytplayer.getPlaybackRate();
                            });
                            API.mediaElement[0].__defineSetter__("playbackRate", function (rate) {
                                return ytplayer.setPlaybackRate(rate);
                            });
                            API.mediaElement[0].play = function () {
                                ytplayer.playVideo();
                            };
                            API.mediaElement[0].pause = function () {
                                ytplayer.pauseVideo();
                            };
                            updateTime(); // Initial time update
                            angular.element(ytplayer.getIframe()).css({'width':'100%','height':'100%'});

                            // Trigger canplay event
                            var event = new CustomEvent("canplay");
                            API.mediaElement[0].dispatchEvent(event);
                        }

                        function updateTime() {
                            API.onUpdateTime({
                                target: API.mediaElement[0]
                            });
                        }

                        function startUpdateTimer(interval) {
                            if (updateTimer) {
                                stopUpdateTimer();
                            }
                            updateTimer = setInterval(updateTime, interval);
                        }

                        function stopUpdateTimer() {
                            if (updateTimer) {
                                clearInterval(updateTimer);
                            }
                        }

                        function onVideoStateChange(event) {
                            var player = event.target;

                            switch (event.data) {
                                case YT.PlayerState.ENDED:
                                    stopUpdateTimer();
                                    API.onComplete();
                                break;

                                case YT.PlayerState.PLAYING:
                                    // Trigger onStartPlaying event
                                    var event = new CustomEvent("playing");
                                    API.mediaElement[0].dispatchEvent(event);
                                    API.setState(VG_STATES.PLAY);
                                    startUpdateTimer(600);
                                break;

                                case YT.PlayerState.PAUSED:
                                    // NB Videogular calls pause() on the YouTube player to actually stop a video.
                                    // Avoid jumping from the desired "stop" status to "pause" status:
                                    if (API.currentState == VG_STATES.PLAY) {
                                        API.setState(VG_STATES.PAUSE);
                                    }
                                    stopUpdateTimer();
                                break;

                                case YT.PlayerState.BUFFERING:
                                    // Trigger onStartBuffering event
                                    var event = new CustomEvent("waiting");
                                    API.mediaElement[0].dispatchEvent(event);
                                break;

                                case YT.PlayerState.CUED:
                                    //No appropriate state
                                break;
                            }
                        }

                        function isYoutube(url) {
                            if (url) {
                                return url.match(youtubeReg);
                            }
                            return false;
                        }

                        function onSourceChange(url) {
                            if (isYoutube(url)) {
                                initYoutubePlayer(url);
                            } else {
                                if (ytplayer) {
                                    destroyYoutubePlayer();
                                }
                            }
                        }
                        scope.$watch(
                            function() {
                                return API.sources;
                            },
                            function(newVal, oldVal) {
                                if (newVal && newVal.length > 0 && newVal[0].src) {
                                    onSourceChange(newVal[0].src.toString());
                                }
                                else {
                                    onSourceChange(null);
                                }
                            }
                        );
                        scope.$on('$destroy', function() {
                            stopUpdateTimer();
                        });
                    }
                };
            }
        ]);
<commit_msg>Added iv_load_policy parameter so annotation display can be configured<commit_after>"use strict";
angular.module("info.vietnamcode.nampnq.videogular.plugins.youtube", [])
    .run(['$rootScope', '$window',
        function($rootScope, $window) {
            $rootScope.youtubeApiReady = false;
            $window.onYouTubeIframeAPIReady = function() {
                $rootScope.$apply(function() {
                    $rootScope.youtubeApiReady = true;
                });
            };
            var tag = document.createElement('script');
            tag.src = "https://www.youtube.com/iframe_api";
            var firstScriptTag = document.getElementsByTagName('script')[0];
            firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
        }
    ])
    .directive(
        "vgYoutube", ["$rootScope", "$window", "$timeout", "$interval", "VG_STATES",
            function($rootScope, $window, $timeout, $interval, VG_STATES) {
                return {
                    restrict: "A",
                    require: "^videogular",
                    link: function(scope, elem, attr, API) {
                        var ytplayer, updateTimer, optionsArr, playerVars;

                        var youtubeReg = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/;
                        optionsArr = attr.vgYoutube !== null ? attr.vgYoutube.split(";") : null;
                        playerVars = {
                            'controls': 0,
                            'showinfo': 0,
                            'rel': 0,
                            'autoplay': 0, //Switch autoplay to 1 to autoplay videos
                            'start': 0,
                            'iv_load_policy': 1
                        };

                        if (optionsArr !== null) {
                            optionsArr.forEach(function (item) {
                                var keyValuePair = item.split("=");
                                if (playerVars.hasOwnProperty(keyValuePair[0])) {
                                  playerVars[keyValuePair[0]] = keyValuePair[1] || 0;
                                }
                            });
                        }

                        function getYoutubeId(url) {
                            return url.match(youtubeReg)[2];
                        }

                        function initYoutubePlayer(url) {
                            if (ytplayer) {
                                ytplayer.cueVideoById({
                                    videoId: getYoutubeId(url)
                                  });
                            } else {
                                $rootScope.$watch('youtubeApiReady', function(value) {
                                    if (value) {
                                        ytplayer = new YT.Player(API.mediaElement[0], {
                                            videoId: getYoutubeId(url),
                                            playerVars: playerVars,
                                            events: {
                                                'onReady': onVideoReady,
                                                'onStateChange': onVideoStateChange
                                            }
                                        });
                                    }
                                });
                            }
                        }

                        function destroyYoutubePlayer() {
                            ytplayer.destroy();
                        }

                        function onVideoReady() {
                            //Define some property, method for player
                            API.mediaElement[0].__defineGetter__("currentTime", function () {
                                return ytplayer.getCurrentTime();
                            });
                            API.mediaElement[0].__defineSetter__("currentTime", function (seconds) {
                                return ytplayer.seekTo(seconds, true);
                            });
                            API.mediaElement[0].__defineGetter__("duration", function () {
                                return ytplayer.getDuration();
                            });
                            API.mediaElement[0].__defineGetter__("paused", function () {
                                return ytplayer.getPlayerState() != YT.PlayerState.PLAYING;
                            });
                            API.mediaElement[0].__defineGetter__("videoWidth", function () {
                                return ytplayer.a.width;
                            });
                            API.mediaElement[0].__defineGetter__("videoHeight", function () {
                                return ytplayer.a.height;
                            });
                            API.mediaElement[0].__defineGetter__("volume", function () {
                                return ytplayer.getVolume() / 100.0;
                            });
                            API.mediaElement[0].__defineSetter__("volume", function (volume) {
                                return ytplayer.setVolume(volume * 100.0);
                            });
                            API.mediaElement[0].__defineGetter__("playbackRate", function () {
                                return ytplayer.getPlaybackRate();
                            });
                            API.mediaElement[0].__defineSetter__("playbackRate", function (rate) {
                                return ytplayer.setPlaybackRate(rate);
                            });
                            API.mediaElement[0].play = function () {
                                ytplayer.playVideo();
                            };
                            API.mediaElement[0].pause = function () {
                                ytplayer.pauseVideo();
                            };
                            updateTime(); // Initial time update
                            angular.element(ytplayer.getIframe()).css({'width':'100%','height':'100%'});

                            // Trigger canplay event
                            var event = new CustomEvent("canplay");
                            API.mediaElement[0].dispatchEvent(event);
                        }

                        function updateTime() {
                            API.onUpdateTime({
                                target: API.mediaElement[0]
                            });
                        }

                        function startUpdateTimer(interval) {
                            if (updateTimer) {
                                stopUpdateTimer();
                            }
                            updateTimer = setInterval(updateTime, interval);
                        }

                        function stopUpdateTimer() {
                            if (updateTimer) {
                                clearInterval(updateTimer);
                            }
                        }

                        function onVideoStateChange(event) {
                            var player = event.target;

                            switch (event.data) {
                                case YT.PlayerState.ENDED:
                                    stopUpdateTimer();
                                    API.onComplete();
                                break;

                                case YT.PlayerState.PLAYING:
                                    // Trigger onStartPlaying event
                                    var event = new CustomEvent("playing");
                                    API.mediaElement[0].dispatchEvent(event);
                                    API.setState(VG_STATES.PLAY);
                                    startUpdateTimer(600);
                                break;

                                case YT.PlayerState.PAUSED:
                                    // NB Videogular calls pause() on the YouTube player to actually stop a video.
                                    // Avoid jumping from the desired "stop" status to "pause" status:
                                    if (API.currentState == VG_STATES.PLAY) {
                                        API.setState(VG_STATES.PAUSE);
                                    }
                                    stopUpdateTimer();
                                break;

                                case YT.PlayerState.BUFFERING:
                                    // Trigger onStartBuffering event
                                    var event = new CustomEvent("waiting");
                                    API.mediaElement[0].dispatchEvent(event);
                                break;

                                case YT.PlayerState.CUED:
                                    //No appropriate state
                                break;
                            }
                        }

                        function isYoutube(url) {
                            if (url) {
                                return url.match(youtubeReg);
                            }
                            return false;
                        }

                        function onSourceChange(url) {
                            if (isYoutube(url)) {
                                initYoutubePlayer(url);
                            } else {
                                if (ytplayer) {
                                    destroyYoutubePlayer();
                                }
                            }
                        }
                        scope.$watch(
                            function() {
                                return API.sources;
                            },
                            function(newVal, oldVal) {
                                if (newVal && newVal.length > 0 && newVal[0].src) {
                                    onSourceChange(newVal[0].src.toString());
                                }
                                else {
                                    onSourceChange(null);
                                }
                            }
                        );
                        scope.$on('$destroy', function() {
                            stopUpdateTimer();
                        });
                    }
                };
            }
        ]);
<|endoftext|>


<commit_before>/* This file has been generated by ox-ui-module generator.
 * Please only apply minor changes (better no changes at all) to this file
 * if you want to be able to run the generator again without much trouble.
 *
 * If you really have to change this file for whatever reason, try to contact
 * the core team and describe your use-case. May be, your changes can be
 * integrated into the templates to be of use for everybody.
 */
'use strict';

module.exports = function (grunt) {

    if (!grunt.isPeerDependencyInstalled('grunt-karma')) {
        grunt.verbose.warn('Skipping karma optional tasks');
        return;
    }

    grunt.config.extend('karma', {

        options: {
            configFile: 'karma.conf.js',
            builddir: 'build/'
        },
        unit: {
            background: true,
            autoWatch: false
        },
        serve: {
            backgrount: false,
            autoWatch: false
        },
        //continuous integration mode: run tests once in PhantomJS browser.
        continuous: {
            singleRun: true,
            browsers: ['PhantomJS'],
            reporters: ['junit']
        }

    });

    grunt.config.extend('copy', {
        specs: {
            files: [{
                expand: true,
                src: ['spec/**/*'],
                dest: 'build/'
            }]
        }
    });

    // testing stuff
    grunt.registerTask('test', ['karma:unit:start']);

    grunt.registerTask('testrun', 'Run the tests, if test server is running', function () {
        var done = this.async();

        var net = require('net');
        var server = net.createServer();
        server.on('error', function () {
            grunt.verbose.writeln('Karma server running, running specs');
            grunt.task.run(['newer:copy:specs', 'karma:unit:run']);
            done();
        });
        server.listen(9876, function () {
            grunt.verbose.warn('No karma server running, skipping specs');
            server.close();
            done();
        });

    });

    grunt.loadNpmTasks('grunt-karma');
};
<commit_msg>expose some local configuration to karma config<commit_after>/* This file has been generated by ox-ui-module generator.
 * Please only apply minor changes (better no changes at all) to this file
 * if you want to be able to run the generator again without much trouble.
 *
 * If you really have to change this file for whatever reason, try to contact
 * the core team and describe your use-case. May be, your changes can be
 * integrated into the templates to be of use for everybody.
 */
'use strict';

module.exports = function (grunt) {

    if (!grunt.isPeerDependencyInstalled('grunt-karma')) {
        grunt.verbose.warn('Skipping karma optional tasks');
        return;
    }

    grunt.config.extend('karma', {

        options: {
            configFile: 'karma.conf.js',
            builddir: 'build/',
            appserver: grunt.config('local.appserver'),
            coreDir: grunt.config('local.coreDir')
        },
        unit: {
            background: true,
            autoWatch: false
        },
        serve: {
            backgrount: false,
            autoWatch: false
        },
        //continuous integration mode: run tests once in PhantomJS browser.
        continuous: {
            singleRun: true,
            browsers: ['PhantomJS'],
            reporters: ['junit']
        }

    });

    grunt.config.extend('copy', {
        specs: {
            files: [{
                expand: true,
                src: ['spec/**/*'],
                dest: 'build/'
            }]
        }
    });

    // testing stuff
    grunt.registerTask('test', ['karma:unit:start']);

    grunt.registerTask('testrun', 'Run the tests, if test server is running', function () {
        var done = this.async();

        var net = require('net');
        var server = net.createServer();
        server.on('error', function () {
            grunt.verbose.writeln('Karma server running, running specs');
            grunt.task.run(['newer:copy:specs', 'karma:unit:run']);
            done();
        });
        server.listen(9876, function () {
            grunt.verbose.warn('No karma server running, skipping specs');
            server.close();
            done();
        });

    });

    grunt.loadNpmTasks('grunt-karma');
};
<|endoftext|>


<commit_before>/*
 * grunt-split-styles
 *
 * Copyright (c) 2014 Dan Bissonnet
 * Licensed under the MIT license.
 */

'use strict';
var postcss = require('postcss');

module.exports = function(grunt) {
	grunt.registerMultiTask('split_styles', 'Split a CSS file based on selectors.', function() {
		// Merge task-specific and/or target-specific options with these defaults.
		var options = this.options({
			pattern: {
				match: false, // The RegExp to match selectors with
				matchParent: false // Should child declarations (eg. in @media blocks) include their parent node.
			},
			remove: true, // Should we strip the matched rules from the src style sheet?
			mediaPattern: false, // RegExp to match @media rules with
			mediaPatternUnwrap: false, // Extract the rules from a matched @media block
		});

		var pattern = {};
		var newCSS = postcss.root();

		if ( options.pattern instanceof RegExp ) {
			pattern.match = options.pattern;
			pattern.matchParent = false;
		} else {
			pattern = options.pattern;
		}

		// Our postCSS processor
		var processor = postcss(function (css) {
			if ( pattern.match ) {
				css.eachRule(function (rule) {
						var parent;

						if ( rule.selector.match(pattern.match) ) {
								if ( options.remove ) {
									rule.removeSelf();
								}

								if ( pattern.matchParent ) {
									parent = rule.parent.clone();

									if ( 'media' === parent.name ) {
										parent.eachRule(function (childRule) {
											childRule.removeSelf();
										});

										parent.append(rule);
										newCSS.append(parent);
									} else {
										newCSS.append(rule);
									}
								} else {
									newCSS.append(rule);
								}
						}
				});
			}

			if (options.mediaPattern) {
				css.eachAtRule(function (atRule) {
					if ( 'media' === atRule.name && atRule.params.match(options.mediaPattern) ) {

						if ( options.remove ) {
							atRule.removeSelf();
						}

						if ( options.mediaPatternUnwrap ) {
							atRule.eachRule(function (rule) {
								newCSS.append(rule);
							});
						} else {
							newCSS.append(atRule);
						}
					}
				});
			}
		});

		// Iterate over all specified file groups.
		this.files.forEach(function(f) {
			var src = f.src.filter(function(filepath) {
				// Warn on and remove invalid source files (if nonull was set).
				if (!grunt.file.exists(filepath)) {
					grunt.log.warn('Source file "' + filepath + '" not found.');
					return false;
				} else {
					return true;
				}
			}).map(function(filepath) {
				// Read file source.
				var css =  grunt.file.read(filepath),
						processOptions = {},
						output;

				processOptions.from = filepath;
				processOptions.to = f.dest;

				// Run the postprocessor
				output = processor.process(css, processOptions);

				if ( options.output && output.map && output.map.length > 0 ) {
					grunt.log.writeln('Sourcemap "' + options.output + '" created.');
					grunt.file.write( f.dest + '.map' , output.map);
				}

				return output.css;
			});

			// Write the newly split file.
			if(options.output) {
				grunt.file.write(options.output, newCSS);
			}

			// Write the destination file
			grunt.file.write(f.dest, src);

			// Print a success message.
			if(options.output) {
				grunt.log.writeln('File "' + options.output + '" created.');
			}
			grunt.log.writeln('File "' + f.dest + '" created.');
		});
	});
};
<commit_msg>Make 'output' optional and fix 'matchParent' option ignoring rules without parent<commit_after>/*
 * grunt-split-styles
 *
 * Copyright (c) 2014 Dan Bissonnet
 * Licensed under the MIT license.
 */

'use strict';
var postcss = require('postcss');

module.exports = function(grunt) {
	grunt.registerMultiTask('split_styles', 'Split a CSS file based on selectors.', function() {
		// Merge task-specific and/or target-specific options with these defaults.
		var options = this.options({
			pattern: {
				match: false, // The RegExp to match selectors with
				matchParent: false // Should child declarations (eg. in @media blocks) include their parent node.
			},
			remove: true, // Should we strip the matched rules from the src style sheet?
			mediaPattern: false, // RegExp to match @media rules with
			mediaPatternUnwrap: false, // Extract the rules from a matched @media block
			output: false // output file 'false' by default
		});

		var pattern = {};
		var newCSS = postcss.root();

		if ( options.pattern instanceof RegExp ) {
			pattern.match = options.pattern;
			pattern.matchParent = false;
		} else {
			pattern = options.pattern;
		}

		// Our postCSS processor
		var processor = postcss(function (css) {
			if ( pattern.match ) {
				css.eachRule(function (rule) {
						var parent;
						if ( rule.selector.match(pattern.match) ) {
							if ( options.remove ) {
								rule.removeSelf();
							}
							if ( pattern.matchParent ) {
								parent = rule.parent.clone();

								if ( 'media' === parent.name ) {
									parent.eachRule(function (childRule) {
										childRule.removeSelf();
									});
									parent.append(rule);
									newCSS.append(parent);
								} else {
									newCSS.append(rule);
								}
							} else {
								newCSS.append(rule);
							}
						}
				});
			}

			if (options.mediaPattern) {
				css.eachAtRule(function (atRule) {
					if ( 'media' === atRule.name && atRule.params.match(options.mediaPattern) ) {
						if ( options.remove ) {
							atRule.removeSelf();
						}
						if ( options.mediaPatternUnwrap ) {
							atRule.eachRule(function (rule) {
								newCSS.append(rule);
							});
						} else {
							newCSS.append(atRule);
						}
					}
				});
			}
		});

		// Iterate over all specified file groups.
		this.files.forEach(function(f) {
			var src = f.src.filter(function(filepath) {
				// Warn on and remove invalid source files (if nonull was set).
				if (!grunt.file.exists(filepath)) {
					grunt.log.warn('Source file "' + filepath + '" not found.');
					return false;
				} else {
					return true;
				}
			}).map(function(filepath) {
				// Read file source.
				var css =  grunt.file.read(filepath),
						processOptions = {},
						output;

				processOptions.from = filepath;
				processOptions.to = f.dest;

				// Run the postprocessor
				output = processor.process(css, processOptions);

				if ( options.output && output.map && output.map.length > 0 ) {
					grunt.log.writeln('Sourcemap "' + options.output + '" created.');
					grunt.file.write( f.dest + '.map' , output.map);
				}

				return output.css;
			});

			// Write the newly split file.
			if(options.output) {
				grunt.file.write(options.output, newCSS);
			}

			// Write the destination file
			grunt.file.write(f.dest, src);

			// Print a success message.
			if(options.output) {
				grunt.log.writeln('File "' + options.output + '" created.');
			}
			grunt.log.writeln('File "' + f.dest + '" created.');
		});
	});
};
<|endoftext|>


<commit_before>/*
 * Grunt Task File
 * ---------------
 *
 * Task: dependencygraph
 * Description: Generate graph for CommonJS or AMD module dependencies.
 *
 */

module.exports = function(grunt) {

  var madge = require('madge');
  var path = require('path');
  var config = this.config.get('dependencygraph');

  var _ = grunt.utils._;
  var log = grunt.log;

  grunt.registerTask("dependencygraph", "Generate graph for CommonJS or AMD module dependencies.", function(prop) {
    var options;
    var args = this.args;

    // Find dependencies
    var dependencies = findDependencies();

    // Convert data
    var graphData = generateGraphOutput(dependencies);

    // Template
    writeHtml(graphData);

    // Fail task if errors were logged
    if (grunt.errors) { return false; }

    log.writeln("Booya. I'm out of here. Bye.");

  });

  function findDependencies() {

    var isPathAbsolute = grunt.file.isPathAbsolute(config.targetPath);
    var targetPath = isPathAbsolute ? config.targetPath : path.resolve(config.targetPath);

    var res = madge(config.targetPath, {
      format : config.format,
      exclude : config.exclude
    });

    log.writeln("Extracted dependencies. Check");
    log.ok();

    return res.obj();
  }

  function generateGraphOutput(dependencies) {

    // Read data
    var components = _.uniq(_.flatten(_.map(dependencies, function(values, item) {
      var data = [];
      data.push(item);
      data = data.concat(values);

      return data;
    })));

    // Mapped nodes
    var nodes = _.map(components, function(component) {
      return {
        id: component
      }
    });

    // Figure out links
    var links = [];
    _.each(dependencies, function(dependencies, component, index) {
      _.each(dependencies, function(dependency) {

        var sourceIndex = _.indexOf(components, dependency);
        var targetIndex = _.indexOf(components, component);

        var link = {
          source: _.indexOf(components, component),
          target: _.indexOf(components, dependency),
        };

        if(sourceIndex > -1 && targetIndex > -1) {
          links.push(link);
        }
      })
    });

    var graph = {
      "directed" : true,
      "multigraph" : false,
      "graph" : [],
      "nodes" : nodes,
      "links" : links
    }

    log.writeln("Converted data. Check.");
    log.ok();

    return graph;

  };

  function writeHtml(graphData) {

    var template = grunt.file.read(__dirname + '/lib/template.html');
    var css = grunt.file.read(__dirname + '/lib/style.css');
    var js = grunt.file.read(__dirname + '/lib/d3-graph.js');

    var html = grunt.template.process(template, {
      css : css,
      js : js,
      title : 'dependencyGraph',
      graphData: JSON.stringify(graphData, null)
    })

    var isPathAbsolute = grunt.file.isPathAbsolute(config.outputPath);
    var baseOutputPath = isPathAbsolute ? config.outputPath : path.resolve(config.outputPath);

    var outputPath = path.join(baseOutputPath, 'index.html');
    grunt.file.write(outputPath, html);

    log.writeln("Generated graph into " + outputPath + " - Check.");
    log.ok();

  }

};
<commit_msg>updated to grunt 0.4 api<commit_after>/*
 * Grunt Task File
 * ---------------
 *
 * Task: dependencygraph
 * Description: Generate graph for CommonJS or AMD module dependencies.
 *
 */

module.exports = function(grunt) {

  var madge = require('madge');
  var path = require('path');
  var config = this.config.get('dependencygraph');

  var _ = grunt.util._;
  var log = grunt.log;

  grunt.registerTask("dependencygraph", "Generate graph for CommonJS or AMD module dependencies.", function(prop) {
    var options;
    var args = this.args;

    // Find dependencies
    var dependencies = findDependencies();

    // Convert data
    var graphData = generateGraphOutput(dependencies);

    // Template
    writeHtml(graphData);

    // Fail task if errors were logged
    if (grunt.errors) { return false; }

    log.writeln("Booya. I'm out of here. Bye.");

  });

  function findDependencies() {

    var isPathAbsolute = grunt.file.isPathAbsolute(config.targetPath);
    var targetPath = isPathAbsolute ? config.targetPath : path.resolve(config.targetPath);

    var res = madge(config.targetPath, {
      format : config.format,
      exclude : config.exclude
    });

    log.writeln("Extracted dependencies. Check");
    log.ok();

    return res.obj();
  }

  function generateGraphOutput(dependencies) {

    // Read data
    var components = _.uniq(_.flatten(_.map(dependencies, function(values, item) {
      var data = [];
      data.push(item);
      data = data.concat(values);

      return data;
    })));

    // Mapped nodes
    var nodes = _.map(components, function(component) {
      return {
        id: component
      }
    });

    // Figure out links
    var links = [];
    _.each(dependencies, function(dependencies, component, index) {
      _.each(dependencies, function(dependency) {

        var sourceIndex = _.indexOf(components, dependency);
        var targetIndex = _.indexOf(components, component);

        var link = {
          source: _.indexOf(components, component),
          target: _.indexOf(components, dependency),
        };

        if(sourceIndex > -1 && targetIndex > -1) {
          links.push(link);
        }
      })
    });

    var graph = {
      "directed" : true,
      "multigraph" : false,
      "graph" : [],
      "nodes" : nodes,
      "links" : links
    }

    log.writeln("Converted data. Check.");
    log.ok();

    return graph;

  };

  function writeHtml(graphData) {

    var template = grunt.file.read(__dirname + '/lib/template.html');
    var css = grunt.file.read(__dirname + '/lib/style.css');
    var js = grunt.file.read(__dirname + '/lib/d3-graph.js');

	var values = {
      css : css,
      js : js,
      title : 'dependencyGraph',
      graphData: JSON.stringify(graphData, null)
    };

    var html = grunt.template.process(template, {data: values});

    var isPathAbsolute = grunt.file.isPathAbsolute(config.outputPath);
    var baseOutputPath = isPathAbsolute ? config.outputPath : path.resolve(config.outputPath);

    var outputPath = path.join(baseOutputPath, 'index.html');
    grunt.file.write(outputPath, html);

    log.writeln("Generated graph into " + outputPath + " - Check.");
    log.ok();

  }

};
<|endoftext|>


<commit_before>
/**
 * set the responseBody JSON here. each response is named with a transactionId.
 * i.e. when a user send a query string with transactionId=good the response
 * under "good" will be returned
 */

module.exports = {

  good: {
    companyId: "ResaleWeekly",
    itemId: "259853",
    itemUrl: "http:\/\/www.resaleweekly.com\/catalog\/product\/view\/id\/259853",
    mobileItemUrl: "http:\/\/www.resaleweekly.com\/catalog\/product\/view\/id\/259853",
    transactionId: "9b2797f7b1a3bc4b27b85b0cfe610eca",
    currencyCode: "GBP",
    description: "IN VERY GOOD WORKING CONDITION NEW DASH MONITOR BEING FITTED NEW TRACK SPADS BEING FITTEDNEW IDLERS BEING FITTED FULLY SERVICED LARGE ROCK BUCKETTRACK CHAINS 80% SPROCKETS 80% NO CRACKS OR WELDING ON BOOM OR DIPPER FIXED FRAME UNDER CARRIAGE MACHINE WHEN WE ARE FINISHED WILL BE AS GOOD AS NEW AND READY FOR WORK ",
    imageUrl: "http:\/\/www.resaleweekly.com\/media\/catalog\/product\/1\/4\/14c146d681087b6_1408116116.jpg",
    listPrice: 55000.00,
    minimumPrice: 0,
    terms: "",
    title: "CATERPILLAR 375L"
  },
  bad :{
    companyId: null,
    //itemId: "259853",
    itemUrl: "http:\/\/www.resaleweekly.com\/catalog\/product\/view\/id\/259853",
    mobileItemUrl: "http:\/\/www.resaleweekly.com\/catalog\/product\/view\/id\/259853",
    transactionId: "9b2797f7b1a3bc4b27b85b0cfe610eca",
    //currencyCode: "GBP",
    description: "IN VERY GOOD WORKING CONDITION NEW DASH MONITOR BEING FITTED NEW TRACK SPADS BEING FITTEDNEW IDLERS BEING FITTED FULLY SERVICED LARGE ROCK BUCKETTRACK CHAINS 80% SPROCKETS 80% NO CRACKS OR WELDING ON BOOM OR DIPPER FIXED FRAME UNDER CARRIAGE MACHINE WHEN WE ARE FINISHED WILL BE AS GOOD AS NEW AND READY FOR WORK ",
    imageUrl: "http:\/\/www.resaleweekly.com\/media\/catalog\/product\/1\/4\/14c146d681087b6_1408116116.jpg",
    listPrice: 55000.00,
    minimumPrice: 0,
    terms: "",
    title: "CATERPILLAR 375L"
  }
};<commit_msg>TransactionId will now be unique per request (up to 1000 per second). forgot to update canned responses<commit_after>
/**
 * set the responseBody JSON here. each response is named with a transactionId.
 * i.e. when a user send a query string with transactionId=good the response
 * under "good" will be returned
 */

module.exports = {

  good: {
    companyId: "ResaleWeekly",
    itemId: "259853",
    itemUrl: "http:\/\/www.resaleweekly.com\/catalog\/product\/view\/id\/259853",
    mobileItemUrl: "http:\/\/www.resaleweekly.com\/catalog\/product\/view\/id\/259853",
    transactionId: "random",
    currencyCode: "GBP",
    description: "IN VERY GOOD WORKING CONDITION NEW DASH MONITOR BEING FITTED NEW TRACK SPADS BEING FITTEDNEW IDLERS BEING FITTED FULLY SERVICED LARGE ROCK BUCKETTRACK CHAINS 80% SPROCKETS 80% NO CRACKS OR WELDING ON BOOM OR DIPPER FIXED FRAME UNDER CARRIAGE MACHINE WHEN WE ARE FINISHED WILL BE AS GOOD AS NEW AND READY FOR WORK ",
    imageUrl: "http:\/\/www.resaleweekly.com\/media\/catalog\/product\/1\/4\/14c146d681087b6_1408116116.jpg",
    listPrice: 55000.00,
    minimumPrice: 0,
    terms: "",
    title: "CATERPILLAR 375L"
  },
  bad :{
    companyId: null,
    //itemId: "259853",
    itemUrl: "http:\/\/www.resaleweekly.com\/catalog\/product\/view\/id\/259853",
    mobileItemUrl: "http:\/\/www.resaleweekly.com\/catalog\/product\/view\/id\/259853",
    transactionId: "random",
    //currencyCode: "GBP",
    description: "IN VERY GOOD WORKING CONDITION NEW DASH MONITOR BEING FITTED NEW TRACK SPADS BEING FITTEDNEW IDLERS BEING FITTED FULLY SERVICED LARGE ROCK BUCKETTRACK CHAINS 80% SPROCKETS 80% NO CRACKS OR WELDING ON BOOM OR DIPPER FIXED FRAME UNDER CARRIAGE MACHINE WHEN WE ARE FINISHED WILL BE AS GOOD AS NEW AND READY FOR WORK ",
    imageUrl: "http:\/\/www.resaleweekly.com\/media\/catalog\/product\/1\/4\/14c146d681087b6_1408116116.jpg",
    listPrice: 55000.00,
    minimumPrice: 0,
    terms: "",
    title: "CATERPILLAR 375L"
  }
};<|endoftext|>


<commit_before>function withDelay(d){
    var bindings = {"test": 1},
        endCont = function(){},
        delay = typeof(d) === "number" ? d : 0;

    // capabilities offered in 'do' block:
    var doEnv = {
        // get or set delay:
        delay: function(d){
            if(d === undefined){
                return delay;
            } else {
                delay = d;
                return d;
            }
        },
        // retrieve the value of a bound loop "variable":
        var: function(nm){
            return bindings[nm];
        }
    }

    // superLoopStep is a function that performs a nested loop iteration and
    // returns a Bool indicating if we should run the body:
    function DLoop(superLoopStep){
        // the fact that loops like while(false) and forrange(1:0) might never
        // run, makes the initial case a bit messy. We define a helper
        function handlingInitialCase(f){
            return superLoopStep() ? f : function(){ return false }
        }
        return {
            do: function(f){
                function doL(){
                    // step loop first to support 'while'. This means first loop
                    // step in 'for' must initialize things and return true:
                    if( superLoopStep() ){
                        // call user-supplied function in 'doEnv' environment
                        f.call(doEnv);
                        setTimeout(doL , delay);
                    } else {
                        endCont();
                    }
                }
                doL();
            },
            // pass a function returning a boolean val
            while: function(pf){
                // initialize parent loop, returning a new superLoopStep with
                // while functionality rolled in
                var slsN = handlingInitialCase(function(){
                    // TODO: run pf in context doEnv
                    // if while predicate returns True, signal go-ahead to loop body:
                    if ( pf() ){
                        return true;
                    // otherwise run the next iteration of the outer-loop:
                    } else {
                        return superLoopStep();
                    }
                });
                return DLoop(slsN);
            },
            // pass a string to be used as bound name, and just an array for a
            // foreach-style loop, or two or three numbers for range-style loop.
            //
            // We'll take after ruby in that for 1..0 does nothing.
            for: function(nm , x , y , z){
                var slsN;
                // range-style:
                if(typeof(x) === "number" && typeof(y) === "number"){
                    var step, n0 = x, nN;
                    if(typeof(z) === "number"){
                        step = y - x;
                        nN = z;
                    } else {
                        step = 1;
                        nN = y;
                    }
                    var i = n0; // incremented and reset below
                                // will be out of range on last loop check
                    slsN = handlingInitialCase(function(){
                        if(i <= nN){
                            bindings[nm] = i;
                            i += step;
                            return true;
                        } else {
                            i = n0;
                            if( superLoopStep() ){
                                return slsN();
                            } else {
                                return false;
                            }
                        }
                    });
                // foreach style:
                } else {
                    slsN = function(){
                    }
                }
                return DLoop(slsN);
            }
        }
    }
    // define a function that runs child loops, for initialization:
    var go = true;
    var singletonLoop = function(){
        var b = go;
        go = false;
        return b;
    }
    o = DLoop(singletonLoop);
    // add a method to set final continuation, returning another DLoop object
    // but without `endingWith`
    o.endingWith = function(f){
        endCont = f;
        return DLoop(singletonLoop);
    }
    return o;
}
// TODO: return some object we can use to control loop

// THEN: while is stupid in this setting: instead do foreach and range-style for
// THEN, make DLoop proper object, with updateable 'delay' as method of 'do'
// THEN, add 'foreach' and 'while'
// THEN play with passing a dictionary of "bound" names

<commit_msg>implement foreach<commit_after>function withDelay(d){
    var bindings = {"test": 1},
        endCont = function(){},
        delay = typeof(d) === "number" ? d : 0;

    // capabilities offered in 'do' block:
    var doEnv = {
        // get or set delay:
        delay: function(d){
            if(d === undefined){
                return delay;
            } else {
                delay = d;
                return d;
            }
        },
        // retrieve the value of a bound loop "variable":
        var: function(nm){
            return bindings[nm];
        }
    }

    // superLoopStep is a function that performs a nested loop iteration and
    // returns a Bool indicating if we should run the body:
    function DLoop(superLoopStep){
        // the fact that loops like while(false) and forrange(1:0) might never
        // run, makes the initial case a bit messy. We define a helper
        function handlingInitialCase(f){
            return superLoopStep() ? f : function(){ return false }
        }
        return {
            do: function(f){
                function doL(){
                    // step loop first to support 'while'. This means first loop
                    // step in 'for' must initialize things and return true:
                    if( superLoopStep() ){
                        // call user-supplied function in 'doEnv' environment
                        f.call(doEnv);
                        setTimeout(doL , delay);
                    } else {
                        endCont();
                    }
                }
                doL();
            },
            // pass a function returning a boolean val
            while: function(pf){
                // initialize parent loop, returning a new superLoopStep with
                // while functionality rolled in
                var slsN = handlingInitialCase(function(){
                    // TODO: run pf in context doEnv
                    // if while predicate returns True, signal go-ahead to loop body:
                    if ( pf() ){
                        return true;
                    // otherwise run the next iteration of the outer-loop:
                    } else {
                        return superLoopStep();
                    }
                });
                return DLoop(slsN);
            },
            // pass a string to be used as bound name, and just an array for a
            // foreach-style loop, or two or three numbers for range-style loop.
            //
            // We'll take after ruby in that for 1..0 does nothing.
            for: function(nm , x , y , z){
                var slsN;
                // range-style:
                if(typeof(x) === "number" && typeof(y) === "number"){
                    var step, n0 = x, nN;
                    if(typeof(z) === "number"){
                        step = y - x;
                        nN = z;
                    } else {
                        step = 1;
                        nN = y;
                    }
                    var i = n0; // incremented and reset below
                                // will be out of range on last loop check
                    slsN = handlingInitialCase(function(){
                        if(i <= nN){
                            bindings[nm] = i;
                            i += step;
                            return true;
                        } else {
                            i = n0;
                            // TODO: this could use handlingInitialCase: (also below)
                            if( superLoopStep() ){
                                return slsN();
                            } else {
                                return false;
                            }
                        }
                    });
                // foreach style:
                } else {
                    var arr = x,
                        i = 0,
                        nN = arr.length - 1;
                    slsN = handlingInitialCase(function(){
                        if(i <= nN){
                            bindings[nm] = arr[i];
                            i++;
                            return true;
                        } else {
                            i = 0;
                            if( superLoopStep() ){
                                return slsN();
                            } else {
                                return false;
                            }
                        }
                    });
                }
                return DLoop(slsN);
            }
        }
    }
    // define a function that runs child loops, for initialization:
    var go = true;
    var singletonLoop = function(){
        var b = go;
        go = false;
        return b;
    }
    o = DLoop(singletonLoop);
    // add a method to set final continuation, returning another DLoop object
    // but without `endingWith`
    o.endingWith = function(f){
        endCont = f;
        return DLoop(singletonLoop);
    }
    return o;
}
// TODO: return some object we can use to control loop

// THEN: while is stupid in this setting: instead do foreach and range-style for
// THEN, make DLoop proper object, with updateable 'delay' as method of 'do'
// THEN, add 'foreach' and 'while'
// THEN play with passing a dictionary of "bound" names

<|endoftext|>


<commit_before>// Copyright (c) 2015, Evan Summers (twitter.com/evanxsummers)
// ISC license, see http://github.com/evanx/redex/LICENSE

import nodemailer from 'nodemailer';

const logger = Loggers.create(module.filename);

module.exports = {

   create(config) {

      let that = {};

      that.transport = nodemailer.createTransport();

      const those = {

         sendAlert(subject, message) {
            logger.info('sendAlert', {subject, message});
            if (lodash.isEmpty(message)) {
               logger.info('sendAlert empty message', subject);
               message = subject;
            }
            if (lodash.includes(config.disableHostnames, config.hostname)) {
               logger.info('sendAlert excluded', subject, config.hostname);
               return;
            }
            let options = {
               from: config.alert.fromEmail,
               to: config.alert.admins[0].email,
               subject: 'Chronica ' + subject
            };
            if (message) {
               options.text = message;
            }
            return new Promise((resolve, reject) => {
               that.transport.sendMail(options, (error, response) => {
                  if (error) {
                     reject(error);
                  } else {
                     let info = {to: response.envelope.to, subject};
                     logger.info('Message sent', info);
                     resolve(response);
                  }
               }
            });
         }
      };
      return those;
   }
};
<commit_msg>scripts<commit_after>// Copyright (c) 2015, Evan Summers (twitter.com/evanxsummers)
// ISC license, see http://github.com/evanx/redex/LICENSE

import nodemailer from 'nodemailer';

const logger = Loggers.create(module.filename);

module.exports = {

   create(config) {

      let that = {};

      that.transport = nodemailer.createTransport();

      const those = {

         sendAlert(subject, message) {
            logger.info('sendAlert', {subject, message});
            if (lodash.isEmpty(message)) {
               logger.info('sendAlert empty message', subject);
               message = subject;
            }
            if (lodash.includes(config.disableHostnames, config.hostname)) {
               logger.info('sendAlert excluded', subject, config.hostname);
               return;
            }
            let options = {
               from: config.fromEmail,
               to: config.admins[0].email,
               subject: 'Chronica ' + subject
            };
            if (message) {
               options.text = message;
            }
            return new Promise((resolve, reject) => {
               that.transport.sendMail(options, (error, response) => {
                  if (error) {
                     reject(error);
                  } else {
                     let info = {to: response.envelope.to, subject};
                     logger.info('Message sent', info);
                     resolve(response);
                  }
               });
            });
         }
      };
      return those;
   }
};
<|endoftext|>


<commit_before><commit_msg>Restrict new error messages to modal function editor levels<commit_after><|endoftext|>


<commit_before>/**
 * Disable bitcode in xcode builds
 * Credit to akofman's initial version: https://gist.github.com/akofman/b53124f76ec309160e08
 */

var xcode = require('xcode');
var fs = require('fs');

module.exports = function(ctx) {
  if (ctx.opts.platforms.indexOf('ios') < 0) {
    return;
  }

  var deferral = ctx.requireCordovaModule('q').defer();
  var common = ctx.requireCordovaModule('cordova-common');
  var util = ctx.requireCordovaModule('cordova-lib/src/cordova/util');

  var projectName = new common.ConfigParser(util.projectConfig(util.isCordova())).name();
  var projectPath = './platforms/ios/' + projectName + '.xcodeproj/project.pbxproj';
  var p = xcode.project(projectPath);

  p.parse(function(err) {
    if (err) {
      console.error(err);
      deferral.reject('xcode could not parse project');
    } else{
      p.updateBuildProperty('ENABLE_BITCODE', 'NO');
      fs.writeFileSync(projectPath, p.writeSync());
      deferral.resolve();
    }
  });

  return deferral.promise;
};
<commit_msg>Descriptiveness<commit_after>/**
 * Disable bitcode in xcode builds
 * Credit to akofman's initial version: https://gist.github.com/akofman/b53124f76ec309160e08
 */

var xcode = require('xcode');
var fs = require('fs');

module.exports = function(ctx) {
  if (ctx.opts.platforms.indexOf('ios') < 0) {
    return;
  }

  var deferral = ctx.requireCordovaModule('q').defer();
  var common = ctx.requireCordovaModule('cordova-common');
  var util = ctx.requireCordovaModule('cordova-lib/src/cordova/util');

  var projectName = new common.ConfigParser(util.projectConfig(util.isCordova())).name();
  var projectPath = './platforms/ios/' + projectName + '.xcodeproj/project.pbxproj';
  var project = xcode.project(projectPath);

  project.parse(function(err) {
    if (err) {
      console.error(err);
      deferral.reject('xcode could not parse project');
    } else{
      project.updateBuildProperty('ENABLE_BITCODE', 'NO');
      fs.writeFileSync(projectPath, project.writeSync());
      deferral.resolve();
    }
  });

  return deferral.promise;
};
<|endoftext|>


<commit_before>import { NativeModules } from 'react-native';

const NativeClient = NativeModules.BugsnagReactNative;

/**
 * A Bugsnag monitoring and reporting client
 */
export class Client {

  /**
   * Creates a new Bugsnag client
   */
  constructor(apiKeyOrConfig) {
    if (apiKeyOrConfig.constructor === String) {
      this.config = new Configuration(apiKeyOrConfig);
    } else if (apiKeyOrConfig instanceof Configuration) {
      this.config = apiKeyOrConfig;
    } else {
      throw new Error('Bugsnag: A client must be constructed with an API key or Configuration');
    }

    if (NativeClient) {
      NativeClient.startWithOptions(this.config.toJSON());
      this.handleUncaughtErrors();
      if (this.config.handlePromiseRejections)
        this.handlePromiseRejections();
    } else {
      throw new Error('Bugsnag: No native client found. Is BugsnagReactNative installed in your native code project?');
    }
  }

  /**
   * Registers a global error handler which sends any uncaught error to
   * Bugsnag before invoking the previous handler, if any.
   */
  handleUncaughtErrors = () => {
    if (ErrorUtils) {
      const previousHandler = ErrorUtils.getGlobalHandler();

      ErrorUtils.setGlobalHandler((error, isFatal) => {
        if (this.config.autoNotify) {
          this.notify(error, report => {report.severity = 'error'}, !!NativeClient.notifyBlocking, () => {
            if (previousHandler) {
              previousHandler(error, isFatal);
            }
          });
        } else if (previousHandler) {
          previousHandler(error, isFatal);
        }
      });
    }
  }

  handlePromiseRejections = () => {
    const tracking = require('promise/setimmediate/rejection-tracking'),
          client = this;
    tracking.enable({
      allRejections: true,
      onUnhandled: function(id, error) { client.notify(error); },
      onHandled: function() {}
    });
  }

  /**
   * Sends an error report to Bugsnag
   * @param error               The error instance to report
   * @param beforeSendCallback  A callback invoked before the report is sent
   *                            so additional information can be added
   * @param blocking            When true, blocks the native thread execution
   *                            until complete. If unspecified, sends the
   *                            request asynchronously
   * @param postSendCallback    Callback invoked after request is queued
   */
  notify = async (error, beforeSendCallback, blocking, postSendCallback) => {
    if (!(error instanceof Error)) {
      console.warn('Bugsnag could not notify: error must be of type Error');
      return;
    }
    if (!this.config.shouldNotify()) {
      return;
    }

    const report = new Report(this.config.apiKey, error);

    for (callback of this.config.beforeSendCallbacks) {
      if (callback(report) === false) {
        return;
      }
    }
    if (beforeSendCallback) {
      beforeSendCallback(report);
    }

    if (blocking) {
      NativeClient.notifyBlocking(report.toJSON(), blocking, postSendCallback);
    } else {
      NativeClient.notify(report.toJSON());
      if (postSendCallback)
        postSendCallback();
    }
  }

  setUser = (id, name, email) => {
    NativeClient.setUser({id, name, email});
  }

  /**
   * Clear custom user data and reset to the default device identifier
   */
  clearUser = () => {
    NativeClient.clearUser();
  }

  /**
   * Leaves a 'breadcrumb' log message. The most recent breadcrumbs
   * are attached to subsequent error reports.
   */
  leaveBreadcrumb = (name, metadata) => {
    if (name.constructor !== String) {
      console.warn('Breadcrumb name must be a String');
      return;
    }
    if (metadata == undefined) {
      metadata = {};
    }
    if (metadata.constructor === String) {
      metadata = {'message': metadata };
    }
    if (!metadata instanceof Object) {
      console.warn('Breadcrumb metadata is not an Object or String, discarding');
      metadata = {};
    }
    let type = metadata['type'] || 'manual';
    delete metadata['type'];
    NativeClient.leaveBreadcrumb({
      name,
      type,
      metadata: typedMap(metadata)
    });
  }
}

/**
 * Configuration options for a Bugsnag client
 */
export class Configuration {

  constructor(apiKey) {
    const metadata = require('../package.json')
    this.version = metadata['version'];
    this.apiKey = apiKey;
    this.delivery = new StandardDelivery()
    this.beforeSendCallbacks = [];
    this.notifyReleaseStages = undefined;
    this.releaseStage = undefined;
    this.appVersion = undefined;
    this.autoNotify = true;
    this.handlePromiseRejections = !__DEV__; // prefer banner in dev mode
  }

  /**
   * Whether reports should be sent to Bugsnag, based on the release stage
   * configuration
   */
  shouldNotify = () => {
    return !this.releaseStage ||
      !this.notifyReleaseStages ||
      this.notifyReleaseStages.includes(this.releaseStage);
  }

  /**
   * Adds a function which is invoked after an error is reported but before
   * it is sent to Bugsnag. The function takes a single parameter which is
   * an instance of Report.
   */
  registerBeforeSendCallback = (callback) => {
    this.beforeSendCallbacks.push(callback)
  }

  /**
   * Remove a callback from the before-send pipeline
   */
  unregisterBeforeSendCallback = (callback) => {
    const index = this.beforeSendCallbacks.indexOf(callback);
    if (index != -1) {
      this.beforeSendCallbacks.splice(index, 1);
    }
  }

  /**
   * Remove all callbacks invoked before reports are sent to Bugsnag
   */
  clearBeforeSendCallbacks = () => {
    this.beforeSendCallbacks = []
  }

  toJSON = () => {
    return {
      apiKey: this.apiKey,
      releaseStage: this.releaseStage,
      notifyReleaseStages: this.notifyReleaseStages,
      endpoint: this.delivery.endpoint,
      appVersion: this.appVersion,
      version: this.version
    };
  }
}

export class StandardDelivery {

  constructor(endpoint) {
    this.endpoint = endpoint || 'https://notify.bugsnag.com';
  }
}

/**
 * A report generated from an error
 */
export class Report {

  constructor(apiKey, error) {
    this.apiKey = apiKey;
    this.errorClass = error.constructor.name;
    this.errorMessage = error.message;
    this.context = undefined;
    this.groupingHash = undefined;
    this.metadata = {};
    this.severity = 'warning';
    this.stacktrace = error.stack;
    this.user = {};
  }

  /**
   * Attach additional diagnostic data to the report. The key/value pairs
   * are grouped into sections.
   */
  addMetadata = (section, key, value) => {
    if (!this.metadata[section]) {
      this.metadata[section] = {};
    }
    this.metadata[section][key] = value;
  }

  toJSON = () => {
    return {
      apiKey: this.apiKey,
      context: this.context,
      errorClass: this.errorClass,
      errorMessage: this.errorMessage,
      groupingHash: this.groupingHash,
      metadata: typedMap(this.metadata),
      severity: this.severity,
      stacktrace: this.stacktrace,
      user: this.user
    }
  }
}

const allowedMapObjectTypes = ['string', 'number', 'boolean'];

/**
 * Convert an object into a structure with types suitable for serializing
 * across to native code.
 */
const typedMap = function(map) {
  const output = {};
  for (const key in map) {
    const value = map[key];
    if (value instanceof Object) {
      output[key] = {type: 'map', value: typedMap(value)};
    } else {
      const type = typeof value;
      if (allowedMapObjectTypes.includes(type)) {
        output[key] = {type: type, value: value};
      }
    }
  }
  return output;
}
<commit_msg>Check 'hasOwnProperty' before adding to typedMap output<commit_after>import { NativeModules } from 'react-native';

const NativeClient = NativeModules.BugsnagReactNative;

/**
 * A Bugsnag monitoring and reporting client
 */
export class Client {

  /**
   * Creates a new Bugsnag client
   */
  constructor(apiKeyOrConfig) {
    if (apiKeyOrConfig.constructor === String) {
      this.config = new Configuration(apiKeyOrConfig);
    } else if (apiKeyOrConfig instanceof Configuration) {
      this.config = apiKeyOrConfig;
    } else {
      throw new Error('Bugsnag: A client must be constructed with an API key or Configuration');
    }

    if (NativeClient) {
      NativeClient.startWithOptions(this.config.toJSON());
      this.handleUncaughtErrors();
      if (this.config.handlePromiseRejections)
        this.handlePromiseRejections();
    } else {
      throw new Error('Bugsnag: No native client found. Is BugsnagReactNative installed in your native code project?');
    }
  }

  /**
   * Registers a global error handler which sends any uncaught error to
   * Bugsnag before invoking the previous handler, if any.
   */
  handleUncaughtErrors = () => {
    if (ErrorUtils) {
      const previousHandler = ErrorUtils.getGlobalHandler();

      ErrorUtils.setGlobalHandler((error, isFatal) => {
        if (this.config.autoNotify) {
          this.notify(error, report => {report.severity = 'error'}, !!NativeClient.notifyBlocking, () => {
            if (previousHandler) {
              previousHandler(error, isFatal);
            }
          });
        } else if (previousHandler) {
          previousHandler(error, isFatal);
        }
      });
    }
  }

  handlePromiseRejections = () => {
    const tracking = require('promise/setimmediate/rejection-tracking'),
          client = this;
    tracking.enable({
      allRejections: true,
      onUnhandled: function(id, error) { client.notify(error); },
      onHandled: function() {}
    });
  }

  /**
   * Sends an error report to Bugsnag
   * @param error               The error instance to report
   * @param beforeSendCallback  A callback invoked before the report is sent
   *                            so additional information can be added
   * @param blocking            When true, blocks the native thread execution
   *                            until complete. If unspecified, sends the
   *                            request asynchronously
   * @param postSendCallback    Callback invoked after request is queued
   */
  notify = async (error, beforeSendCallback, blocking, postSendCallback) => {
    if (!(error instanceof Error)) {
      console.warn('Bugsnag could not notify: error must be of type Error');
      return;
    }
    if (!this.config.shouldNotify()) {
      return;
    }

    const report = new Report(this.config.apiKey, error);

    for (callback of this.config.beforeSendCallbacks) {
      if (callback(report) === false) {
        return;
      }
    }
    if (beforeSendCallback) {
      beforeSendCallback(report);
    }

    if (blocking) {
      NativeClient.notifyBlocking(report.toJSON(), blocking, postSendCallback);
    } else {
      NativeClient.notify(report.toJSON());
      if (postSendCallback)
        postSendCallback();
    }
  }

  setUser = (id, name, email) => {
    NativeClient.setUser({id, name, email});
  }

  /**
   * Clear custom user data and reset to the default device identifier
   */
  clearUser = () => {
    NativeClient.clearUser();
  }

  /**
   * Leaves a 'breadcrumb' log message. The most recent breadcrumbs
   * are attached to subsequent error reports.
   */
  leaveBreadcrumb = (name, metadata) => {
    if (name.constructor !== String) {
      console.warn('Breadcrumb name must be a String');
      return;
    }
    if (metadata == undefined) {
      metadata = {};
    }
    if (metadata.constructor === String) {
      metadata = {'message': metadata };
    }
    if (!metadata instanceof Object) {
      console.warn('Breadcrumb metadata is not an Object or String, discarding');
      metadata = {};
    }
    let type = metadata['type'] || 'manual';
    delete metadata['type'];
    NativeClient.leaveBreadcrumb({
      name,
      type,
      metadata: typedMap(metadata)
    });
  }
}

/**
 * Configuration options for a Bugsnag client
 */
export class Configuration {

  constructor(apiKey) {
    const metadata = require('../package.json')
    this.version = metadata['version'];
    this.apiKey = apiKey;
    this.delivery = new StandardDelivery()
    this.beforeSendCallbacks = [];
    this.notifyReleaseStages = undefined;
    this.releaseStage = undefined;
    this.appVersion = undefined;
    this.autoNotify = true;
    this.handlePromiseRejections = !__DEV__; // prefer banner in dev mode
  }

  /**
   * Whether reports should be sent to Bugsnag, based on the release stage
   * configuration
   */
  shouldNotify = () => {
    return !this.releaseStage ||
      !this.notifyReleaseStages ||
      this.notifyReleaseStages.includes(this.releaseStage);
  }

  /**
   * Adds a function which is invoked after an error is reported but before
   * it is sent to Bugsnag. The function takes a single parameter which is
   * an instance of Report.
   */
  registerBeforeSendCallback = (callback) => {
    this.beforeSendCallbacks.push(callback)
  }

  /**
   * Remove a callback from the before-send pipeline
   */
  unregisterBeforeSendCallback = (callback) => {
    const index = this.beforeSendCallbacks.indexOf(callback);
    if (index != -1) {
      this.beforeSendCallbacks.splice(index, 1);
    }
  }

  /**
   * Remove all callbacks invoked before reports are sent to Bugsnag
   */
  clearBeforeSendCallbacks = () => {
    this.beforeSendCallbacks = []
  }

  toJSON = () => {
    return {
      apiKey: this.apiKey,
      releaseStage: this.releaseStage,
      notifyReleaseStages: this.notifyReleaseStages,
      endpoint: this.delivery.endpoint,
      appVersion: this.appVersion,
      version: this.version
    };
  }
}

export class StandardDelivery {

  constructor(endpoint) {
    this.endpoint = endpoint || 'https://notify.bugsnag.com';
  }
}

/**
 * A report generated from an error
 */
export class Report {

  constructor(apiKey, error) {
    this.apiKey = apiKey;
    this.errorClass = error.constructor.name;
    this.errorMessage = error.message;
    this.context = undefined;
    this.groupingHash = undefined;
    this.metadata = {};
    this.severity = 'warning';
    this.stacktrace = error.stack;
    this.user = {};
  }

  /**
   * Attach additional diagnostic data to the report. The key/value pairs
   * are grouped into sections.
   */
  addMetadata = (section, key, value) => {
    if (!this.metadata[section]) {
      this.metadata[section] = {};
    }
    this.metadata[section][key] = value;
  }

  toJSON = () => {
    return {
      apiKey: this.apiKey,
      context: this.context,
      errorClass: this.errorClass,
      errorMessage: this.errorMessage,
      groupingHash: this.groupingHash,
      metadata: typedMap(this.metadata),
      severity: this.severity,
      stacktrace: this.stacktrace,
      user: this.user
    }
  }
}

const allowedMapObjectTypes = ['string', 'number', 'boolean'];

/**
 * Convert an object into a structure with types suitable for serializing
 * across to native code.
 */
const typedMap = function(map) {
  const output = {};
  for (const key in map) {
    if (!{}.hasOwnProperty.call(map, key)) continue;

    const value = map[key];
    if (value instanceof Object) {
      output[key] = {type: 'map', value: typedMap(value)};
    } else {
      const type = typeof value;
      if (allowedMapObjectTypes.includes(type)) {
        output[key] = {type: type, value: value};
      }
    }
  }
  return output;
}
<|endoftext|>


<commit_before>var api = null,
    networkCode = '',
    applicationName = '';

var DfpUser = function (netCode, appName) {

  networkCode = netCode;
  applicationName = appName;
  this.loadConfig();

  return this;
};

DfpUser.prototype.loadConfig = function (file) {

  if (!file) {
    api = require('../api.properties');
  } else {
    api = require(file);
  }

  return this;
};

DfpUser.prototype.setSettings = function(settings) {
  api.settings = settings;
  return this;
}

DfpUser.prototype.getSOAPHeader = function (token) {

  return {
    RequestHeader : {
      attributes: {
        'soapenv:actor':            "http://schemas.xmlsoap.org/soap/actor/next",
        'soapenv:mustUnderstand':   0,
        'xsi:type':                 "ns1:SoapRequestHeader",
        'xmlns:ns1':                "https://www.google.com/apis/ads/publisher/" + api.version,
        'xmlns:xsi':                "http://www.w3.org/2001/XMLSchema-instance",
        'xmlns:soapenv':            "http://schemas.xmlsoap.org/soap/envelope/"
      },
      networkCode: networkCode,
      applicationName: applicationName,
      authentication: {
        attributes: {
          'xsi:type': 'ns1:OAuth',
          'xmlns:xsd': "http://www.w3.org/2001/XMLSchema"
        },
        parameters: token.token_type + ' ' + token.access_token
      }
    }
  };

};

DfpUser.prototype.getService = function (service, callback, version) {

  var soap = require('soap');
  var gapi = require('googleapis');
  var Oath = gapi.auth.OAuth2;
  var soap_wsdl = '';
  var dfpUser = this;
  var useVersion;

  if (!version) {

    if (!api.services[service]) {
      throw new Error('Service not found');
    }

    useVersion = api.version;
    soap_wsdl = api.services[service];

  } else {

    useVersion = version;
    soap_wsdl = api.base_api_url + '/' + version + '/' + service + '?wsdl';

  }

  var oathClient = new Oath(api.settings.client_id, api.settings.client_secret, api.settings.redirect_url);
  oathClient.credentials = { refresh_token: api.settings.refresh_token };

  oathClient.refreshAccessToken(function (err, tokens) {

    if (err) {
      console.log('Refresh Token Error ' + err);
      throw new Error('Unable to get token');
    }

    soap.createClient(soap_wsdl, function (err, client) {
      if (err) {
        console.log('Create Client Error ' + err);
        throw new Error('Unable to get token');
      }

      var instService = require('./' + useVersion + '/' + service);

      client.addSoapHeader(dfpUser.getSOAPHeader(tokens), 'RequestHeader', 'tns', '');
      callback(new instService(client[service][service + 'InterfacePort']));

    });

  });

  return this;
};

module.exports = DfpUser;
<commit_msg>JSLint<commit_after>var api = null,
  networkCode = '',
  applicationName = '';

var DfpUser = function (netCode, appName) {

  networkCode = netCode;
  applicationName = appName;
  this.loadConfig();

  return this;
};

DfpUser.prototype.loadConfig = function (file) {

  if (!file) {
    api = require('../api.properties');
  } else {
    api = require(file);
  }

  return this;
};

DfpUser.prototype.setSettings = function (settings) {
  api.settings = settings;
  return this;
};

DfpUser.prototype.getSOAPHeader = function (token) {

  return {
    RequestHeader : {
      attributes: {
        'soapenv:actor':            "http://schemas.xmlsoap.org/soap/actor/next",
        'soapenv:mustUnderstand':   0,
        'xsi:type':                 "ns1:SoapRequestHeader",
        'xmlns:ns1':                "https://www.google.com/apis/ads/publisher/" + api.version,
        'xmlns:xsi':                "http://www.w3.org/2001/XMLSchema-instance",
        'xmlns:soapenv':            "http://schemas.xmlsoap.org/soap/envelope/"
      },
      networkCode: networkCode,
      applicationName: applicationName,
      authentication: {
        attributes: {
          'xsi:type': 'ns1:OAuth',
          'xmlns:xsd': "http://www.w3.org/2001/XMLSchema"
        },
        parameters: token.token_type + ' ' + token.access_token
      }
    }
  };

};

DfpUser.prototype.getService = function (service, callback, version) {

  var soap = require('soap');
  var gapi = require('googleapis');
  var Oath = gapi.auth.OAuth2;
  var soap_wsdl = '';
  var dfpUser = this;
  var useVersion;

  if (!version) {

    if (!api.services[service]) {
      throw new Error('Service not found');
    }

    useVersion = api.version;
    soap_wsdl = api.services[service];

  } else {

    useVersion = version;
    soap_wsdl = api.base_api_url + '/' + version + '/' + service + '?wsdl';

  }

  var oathClient = new Oath(api.settings.client_id, api.settings.client_secret, api.settings.redirect_url);
  oathClient.credentials = { refresh_token: api.settings.refresh_token };

  oathClient.refreshAccessToken(function (err, tokens) {

    if (err) {
      console.log('Refresh Token Error ' + err);
      throw new Error('Unable to get token');
    }

    soap.createClient(soap_wsdl, function (err, client) {
      if (err) {
        console.log('Create Client Error ' + err);
        throw new Error('Unable to get token');
      }

      var InstService = require('./' + useVersion + '/' + service);

      client.addSoapHeader(dfpUser.getSOAPHeader(tokens), 'RequestHeader', 'tns', '');
      callback(new InstService(client[service][service + 'InterfacePort']));

    });

  });

  return this;
};

module.exports = DfpUser;
<|endoftext|>


<commit_before>var express = require('express');
var router = express.Router();

// Login a user with basic auth
router.post('/', function (req, res, next) {});

module.exports = router;
<commit_msg>Add section 6.1 code to provide login for users<commit_after>var express = require('express');
var router = express.Router();
var auth = require('../../utils/auth');
var _ = require('lodash');
var JsonDB = require('node-json-db');
var crypto = require('crypto');

// Login a user with basic auth
router.post('/', auth.basic, function (req, res, next) {
  var db = new JsonDB('db', false, true);
  var users = db.getData('/users');

  function sendError() {
    res.status(500).json({
      success: false,
      message: 'Unable to authenticate user.'
    });
  }

  // Find the auth user to update last login
  var i = _.findIndex(users, {username: req.user.username});
  crypto.randomBytes(16, function(err, buf) {
    if (!err) {
      var ret = _.attempt(db.push.bind(db), '/users['+i+']', {
        last_login: _.now(),
        token: buf.toString('hex')
      }, false);

      if (!_.isError(ret)) {
        res.json({
          success: true,
          message: 'Successfully authenticated user.',
          token: buf.toString('hex')
        });
      }
      else {
        sendError();
      }
    }
    else {
      sendError();
    }
  });
});

module.exports = router;
<|endoftext|>


<commit_before>/**
 * Created by huiji001 on 2015/9/10.
 */
function copyWiki(){
    this.init();
}

function getFormattedDate() {
    var date = new Date();
    var str = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate() + " " +  date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds();
    return str;
}

copyWiki.prototype ={
    init: function(){
        this._addListener();
        this._addModal();
    },
    _addListener: function(){
        $('#ca-fork a').on('click', $.proxy(this._getFollow, this));
        $('body').on('click','.copy-modal .copy', $.proxy(this._wikiSelect, this));
    },
    _getFollow: function(){
        var user_name = mw.config.get('wgUserName');
        $('.copy-modal').modal();
        if(user_name == null){
            e.preventDefault();
            $('.wiki-copy .dropdown-menu').empty().append('请登录');
            $('.user-login').modal();
        }else {
            $.post(
                mw.util.wikiScript(), {
                    action: 'ajax',
                    rs: 'wfUserSiteFollowsDetailsResponse',
                    rsargs: [user_name, user_name]
                },
                function (data) {
                    var res = $.parseJSON(data);
                    var content = '';
                    if (res.success == true) {
                        if (res.result.length == 0) {
                            content = '您要把这个页面搬运到哪里呢？不妨先关注那个维基吧';
                            $('.copy-modal .modal-body').empty().append(content);
                        }
                        $.each(res.result,
                            function (i, item) {
                                content += '
' + item.val + '
'
                            }
                        );
                        $('.copy-modal .modal-body').empty().append(content);
                    }
                }
            );
        }
    },
    _addModal: function(){
        var modal = '
'+
            '
'+
            '
'+
                '
'+
                    '<button type="button" class="close" data-dismiss="modal" aria-label="Close">×</button>'+
                    '
把这个页面搬运到哪？
'+
                    '
根据页面历史长短和嵌套的模板数量，搬运会需要相应的等候时间。
'+
                '
'+
                '
'+
                ''+
                '
'+
            '
'+
        '
'+
        '
';
        $("body").append(modal);
    },
    _wikiSelect: function(e){
        e.stopPropagation();
        var ajaxurl = 'http://'+$(e.target).data('src')+'.huiji.wiki/api.php';
        var redirectUrl = 'http://'+$(e.target).data('src')+'.huiji.wiki/wiki/'+mw.config.get('wgPageName');
        $(e.target).append('');
        this.ajaxurl = ajaxurl;
        this.redirectUrl = redirectUrl;
        this._getToken();
    },
    _getToken: function(){
        $.ajax({
            url: this.ajaxurl,
            data: {
                action: 'query',
                meta: 'tokens',
                format: 'json',
                origin:'http://'+mw.config.get('wgHuijiPrefix')+'.huiji.wiki'
            },
            xhrFields: {
                withCredentials: true
            },
            dataType: 'json',
            type: 'POST',
            context: this,
            success: function( data ){
                var token = data.query.tokens.csrftoken;
                this._queryPage(token);
            },
            error: function( error ){
                console.log( error );
            }
        })
    },
    _queryData: function(){
        var _this = copyWiki.prototype;
        console.log(_this);
//        $.ajax({
//            url:'api.php?action=query&titles=API&export&exportnowrap',
//            title: mw.config.get( "wgPageName" )
//        })
        $.ajax({
            url: mw.util.wikiScript( 'api' ),
            data: {
                format: 'xml',
                action: 'query',
                titles: '首页',
                prop: 'revisions',
                rvprop: 'content'
            },
            type: 'POST',
            success: function( data ) {
                console.log(data);
                this._importData(data);
            },
            error: function( xhr ) {
                alert( 'Error: Request failed.' );
            }
        });
    },
    _copyContent: function(){

    },
    _queryPage: function(token){
        $.ajax({
            url:this.ajaxurl,
            data:{
                action: 'query',
                titles: mw.config.get('wgPageName'),
                format: 'json',
                origin:'http://'+mw.config.get('wgHuijiPrefix')+'.huiji.wiki'
            },
            xhrFields: {
                withCredentials: true
            },
            type: 'post',
            success: $.proxy(function(data){

                for (var key in data.query.pages){
                    if (key < 0){
                        this._importWiki(token);
                    }else{

                        var warn = '
' +
                            '<button type="button" class="close" data-dismiss="alert" aria-label="Close">×</button>' +
                            '
页面已存在!
' +
                            '
点击覆盖，将覆盖您维基已有的同名页面内容。否则请关闭。
' +
                            '
<button type="button" class="btn btn-danger" data-loading-text="搬运中" autocomplete="off">覆盖</button>
' +
                            '
';
                        $('body').append(warn).on('click', '.copy-warn .btn', $.proxy(this._importWiki, this, token));
                        $('body').append(warn).on('click', '.copy-warn .close',function(){
                            $('.copy-modal').modal('hide');
                            $('.copy-warn').remove();
                        });

                    }
                }
            },this),
            error: function(error){
                console.log(error)
            }
        })
    },
    _importWiki: function(token){
        var $btn = $('.copy-warn .btn').button('loading');
        $.ajax({
            url: this.ajaxurl+'?origin=http://'+mw.config.get('wgHuijiPrefix')+'.huiji.wiki',
            data: {
                action: 'import',
                interwikisource: mw.config.get('wgHuijiPrefix'),
                interwikipage: mw.config.get('wgPageName'),
                token: token,
                format:'json',
                // fullhistory: true,
                templates: true,
                createonly: true
            },
            type: 'post',
            xhrFields: {
                withCredentials: true
            },
            success: $.proxy(function(data){
                var result = data.import||[];
                var error = data.error||'';
                $('.copy .fa-spinner').remove();
                if(result.length>0) {
                    $btn.button('reset');
                    $('.copy-warn .close').trigger('click');
                    alertime();
                    alertp.text('搬运成功');
                    $('.copy-modal').modal('hide');
                    this._addSource(token);

                }else if(error.code == 'cantimport'){
                    alertime();
                    alertp.text('您在目标维基没有管理员权限');
                }else if(error.code == 'unknown_interwikisource'){
                    alertime();
                    alertp.text('您选择的维基不能为当前维基');
                }else{
                    console.log(data);
                }
            },this),
            error: function( error ){
                console.log( error );
            }
        });

    },
    _addSource: function(token){
        $.ajax({
            url: this.ajaxurl+'?origin=http://'+mw.config.get('wgHuijiPrefix')+'.huiji.wiki',
            data:{
                action: "edit",
                title: mw.config.get('wgTitle'),
                summary: "注明出处",
                format:"json",
                appendtext: "{{raw:templatemanager:ForkCredit|time="+getFormattedDate()+"|source_page=[["+mw.config.get('wgHuijiPrefix')+":"+mw.config.get('wgTitle')+"]]"+"|carrier=[[User:"+mw.config.get('wgUserName')+"]]}}",
                token: token
            },
            type: 'post',
            xhrFields: {
                withCredentials: true
            },
            success: $.proxy(function(data){
                window.location = this.redirectUrl;
            },this)
        });
    }
};

$(function(){
   return new copyWiki();
});
<commit_msg>new hello<commit_after>/**
 * Created by huiji001 on 2015/9/10.
 */
function copyWiki(){
    this.init();
}

function getFormattedDate() {
    var date = new Date();
    var str = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate() + " " +  date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds();
    return str;
}

copyWiki.prototype ={
    init: function(){
        this._addListener();
        this._addModal();
    },
    _addListener: function(){
        $('#ca-fork a').on('click', $.proxy(this._getFollow, this));
        $('body').on('click','.copy-modal .copy', $.proxy(this._wikiSelect, this));
    },
    _getFollow: function(){
        var user_name = mw.config.get('wgUserName');
        $('.copy-modal').modal();
        if(user_name == null){
            e.preventDefault();
            $('.wiki-copy .dropdown-menu').empty().append('请登录');
            $('.user-login').modal();
        }else {
            $.post(
                mw.util.wikiScript(), {
                    action: 'ajax',
                    rs: 'wfUserSiteFollowsDetailsResponse',
                    rsargs: [user_name, user_name]
                },
                function (data) {
                    var res = $.parseJSON(data);
                    var content = '';
                    if (res.success == true) {
                        if (res.result.length == 0) {
                            content = '您要把这个页面搬运到哪里呢？不妨先关注那个维基吧';
                            $('.copy-modal .modal-body').empty().append(content);
                        }
                        $.each(res.result,
                            function (i, item) {
                                content += '
' + item.val + '
'
                            }
                        );
                        $('.copy-modal .modal-body').empty().append(content);
                    }
                }
            );
        }
    },
    _addModal: function(){
        var modal = '
'+
            '
'+
            '
'+
                '
'+
                    '<button type="button" class="close" data-dismiss="modal" aria-label="Close">×</button>'+
                    '
把这个页面搬运到哪？
'+
                    '
根据页面历史长短和嵌套的模板数量，搬运会需要相应的等候时间。
'+
                '
'+
                '
'+
                ''+
                '
'+
            '
'+
        '
'+
        '
';
        $("body").append(modal);
    },
    _wikiSelect: function(e){
        e.stopPropagation();
        var ajaxurl = 'http://'+$(e.target).data('src')+'.huiji.wiki/api.php';
        var redirectUrl = 'http://'+$(e.target).data('src')+'.huiji.wiki/wiki/'+mw.config.get('wgPageName');
        $(e.target).append('');
        this.ajaxurl = ajaxurl;
        this.redirectUrl = redirectUrl;
        this._getToken();
    },
    _getToken: function(){
        $.ajax({
            url: this.ajaxurl,
            data: {
                action: 'query',
                meta: 'tokens',
                format: 'json',
                origin:'http://'+mw.config.get('wgHuijiPrefix')+'.huiji.wiki'
            },
            xhrFields: {
                withCredentials: true
            },
            dataType: 'json',
            type: 'POST',
            context: this,
            success: function( data ){
                var token = data.query.tokens.csrftoken;
                this._queryPage(token);
            },
            error: function( error ){
                console.log( error );
            }
        })
    },
    _queryData: function(){
        var _this = copyWiki.prototype;
        console.log(_this);
//        $.ajax({
//            url:'api.php?action=query&titles=API&export&exportnowrap',
//            title: mw.config.get( "wgPageName" )
//        })
        $.ajax({
            url: mw.util.wikiScript( 'api' ),
            data: {
                format: 'xml',
                action: 'query',
                titles: '首页',
                prop: 'revisions',
                rvprop: 'content'
            },
            type: 'POST',
            success: function( data ) {
                console.log(data);
                this._importData(data);
            },
            error: function( xhr ) {
                alert( 'Error: Request failed.' );
            }
        });
    },
    _copyContent: function(){

    },
    _queryPage: function(token){
        $.ajax({
            url:this.ajaxurl,
            data:{
                action: 'query',
                titles: mw.config.get('wgPageName'),
                format: 'json',
                origin:'http://'+mw.config.get('wgHuijiPrefix')+'.huiji.wiki'
            },
            xhrFields: {
                withCredentials: true
            },
            type: 'post',
            success: $.proxy(function(data){

                for (var key in data.query.pages){
                    if (key < 0){
                        this._importWiki(token);
                    }else{

                        var warn = '
' +
                            '<button type="button" class="close" data-dismiss="alert" aria-label="Close">×</button>' +
                            '
页面已存在!
' +
                            '
点击覆盖，将覆盖您维基已有的同名页面内容。否则请关闭。
' +
                            '
<button type="button" class="btn btn-danger" data-loading-text="搬运中" autocomplete="off">覆盖</button>
' +
                            '
';
                        $('body').append(warn).on('click', '.copy-warn .btn', $.proxy(this._importWiki, this, token));
                        $('body').append(warn).on('click', '.copy-warn .close',function(){
                            $('.copy-modal').modal('hide');
                            $('.copy-warn').remove();
                        });

                    }
                }
            },this),
            error: function(error){
                console.log(error)
            }
        })
    },
    _importWiki: function(token){
        var $btn = $('.copy-warn .btn').button('loading');
        $.ajax({
            url: this.ajaxurl+'?origin=http://'+mw.config.get('wgHuijiPrefix')+'.huiji.wiki',
            data: {
                action: 'import',
                interwikisource: mw.config.get('wgHuijiPrefix'),
                interwikipage: mw.config.get('wgPageName'),
                token: token,
                format:'json',
                // fullhistory: true,
                templates: true,
                createonly: true
            },
            type: 'post',
            xhrFields: {
                withCredentials: true
            },
            success: $.proxy(function(data){
                var result = data.import||[];
                var error = data.error||'';
                $('.copy .fa-spinner').remove();
                if(result.length>0) {
                    $btn.button('reset');
                    $('.copy-warn .close').trigger('click');
                    alertime();
                    alertp.text('搬运成功');
                    $('.copy-modal').modal('hide');
                    this._addSource(token);

                }else if(error.code == 'cantimport'){
                    alertime();
                    alertp.text('您在目标维基没有管理员权限');
                }else if(error.code == 'unknown_interwikisource'){
                    alertime();
                    alertp.text('您选择的维基不能为当前维基');
                }else{
                    console.log(data);
                }
            },this),
            error: function( error ){
                console.log( error );
            }
        });

    },
    _addSource: function(token){
        $.ajax({
            url: this.ajaxurl+'?origin=http://'+mw.config.get('wgHuijiPrefix')+'.huiji.wiki',
            data:{
                action: "edit",
                title: mw.config.get('wgPageName'),
                summary: "注明出处",
                format:"json",
                appendtext: "{{raw:templatemanager:ForkCredit|time="+getFormattedDate()+"|source_page=[["+mw.config.get('wgHuijiPrefix')+":"+mw.config.get('wgPageName')+"]]"+"|carrier=[[User:"+mw.config.get('wgUserName')+"]]}}",
                token: token
            },
            type: 'post',
            xhrFields: {
                withCredentials: true
            },
            success: $.proxy(function(data){
                window.location = this.redirectUrl;
            },this)
        });
    }
};

$(function(){
   return new copyWiki();
});
<|endoftext|>


<commit_before><commit_msg>Cleaned up<commit_after><|endoftext|>


<commit_before>if (process.env.NODE_ENV !== 'production') require('dotenv').config()

const express = require('express');
const bluebird = require('bluebird');
const redis = require('redis');
const contentful = require('contentful');

const router = express.Router();

bluebird.promisifyAll(redis.RedisClient.prototype);
bluebird.promisifyAll(redis.Multi.prototype);

const redisClient = redis.createClient(process.env.REDIS_URL);

const client = contentful.createClient({
  space: process.env.SPACE,
  accessToken: process.env.ACCESS_TOKEN
});

function fetchData (req, res, next) {
  client.getEntries()
    .then(data => {
      const dataToSend = data.items.map(item => {
          return item.fields;
      });

      redisClient.flushall();

      const promisesArr = dataToSend.map(entry => {
           return redisClient.setAsync(entry.date, entry.type);
      });

      bluebird.all(promisesArr)
        .then(() => {
            console.log('all promises done');

            next();
        });
    })
    .catch(err => console.log(err));
}

router.use(fetchData);

router.post('/', function(req, res) {
    res.send('ok');
});

module.exports = router;
<commit_msg>Tiny styling refactor<commit_after>if (process.env.NODE_ENV !== 'production') require('dotenv').config()

const express = require('express');
const bluebird = require('bluebird');
const redis = require('redis');
const contentful = require('contentful');

const router = express.Router();

bluebird.promisifyAll(redis.RedisClient.prototype);
bluebird.promisifyAll(redis.Multi.prototype);

const redisClient = redis.createClient(process.env.REDIS_URL);

const client = contentful.createClient({
  space: process.env.SPACE,
  accessToken: process.env.ACCESS_TOKEN
});

function fetchData (req, res, next) {
  client.getEntries()
    .then(data => {
      const dataToSend = data.items.map(item => {
          return item.fields;
      });

      redisClient.flushall();

      bluebird.all(dataToSend.map(entry => {
        return redisClient.setAsync(entry.date, entry.type);
      }))
      .then(() => {
        next();
      });
    })
    .catch(err => console.log(err));
}

router.use(fetchData);

router.post('/', function(req, res) {
    res.send('ok');
});

module.exports = router;
<|endoftext|>