<commit_before>/**
Hook is executed when plugin is added to the project.
It will check all necessary module dependencies and install the missing ones locally.
Also, it will suggest to user to install CLI client for that plugin.
It can be found in https://github.com/nordnet/cordova-hot-code-push-cli
*/

var exec = require('child_process').exec,
  path = require('path'),
  modules = ['read-package-json'],
  chcpCliPackageName = 'cordova-hot-code-push-cli',
  packageJsonFilePath;

// region NPM specific

/**
 * Discovers module dependencies in plugin's package.json and installs them.
 */
function getPackagesFromJson() {
  var readJson = require('read-package-json');
  readJson(packageJsonFilePath, console.error, false, function(err, data) {
    if (err) {
      console.error('Can\'t read package.json file: ' + err);
      return;
    }

    var dependencies = data['dependencies'];
    if (dependencies) {
      for (var module in dependencies) {
        modules.push(module);
      }
      installRequiredNodeModules(function() {
        console.log('All dependency modules are installed.');
        checkCliDependency();
      });
    }
  });
}

/**
 * Check if node package is installed.
 *
 * @param {String} moduleName
 * @return {Boolean} true if package already installed
 */
function isNodeModuleInstalled(moduleName) {
  var installed = true;
  try {
    require.resolve(moduleName);
  } catch (err) {
    installed = false;
  }

  return installed;
}

/**
 * Install node module locally.
 * Basically, it runs 'npm install module_name'.
 *
 * @param {String} moduleName
 * @param {Callback(error)} callback
 */
function installNodeModule(moduleName, callback) {
  if (isNodeModuleInstalled(moduleName)) {
    console.log('Node module ' + moduleName + ' is found');
    callback(null);
    return;
  }
  console.log('Can\'t find module ' + moduleName + ', running npm install');

  var cmd = 'npm install ' + moduleName;
  exec(cmd, function(err, stdout, stderr) {
    callback(err);
  });
}

/**
 * Install all required node packages.
 */
function installRequiredNodeModules(callback) {
  if (modules.length == 0) {
    callback();
    return;
  }

  var moduleName = modules.shift();
  installNodeModule(moduleName, function(err) {
    if (err) {
      console.log('Failed to install module ' + moduleName);
      console.log(err);
      return;
    }

    console.log('Module ' + moduleName + ' is installed');
    installRequiredNodeModules(callback);
  });
}

// endregion

// region CLI specific

/**
 * Check if cordova-hcp utility is installed. If not - suggest user to install it.
 */
function checkCliDependency() {
  checkIfChcpInstalled(function(err) {
    if (err) {
      suggestCliInstallation();
    }

    logEnd();
  });
}

/**
 * Check if cordova-hcp utility is installed.
 *
 * @param {Callback(error)} callback
 */
function checkIfChcpInstalled(callback) {
  var cmd = 'npm -g list ' + chcpCliPackageName;
  exec(cmd, function(err, stdout, stderr) {
    callback(err);
  });
}

/**
 * Show message, that developer should install CLI client for the plugin, so it would be easier to use.
 */
function suggestCliInstallation() {
  console.log('');
  console.log('To make the development process easier for you - we developed a CLI client for our plugin.');
  console.log('To install it, please, use command:');
  console.log('npm install -g ' + chcpCliPackageName);
  console.log('For more information please visit https://github.com/nordnet/cordova-hot-code-push-cli');
}

// endregion

function logStart() {
  console.log("======== CHCP after plugin add process ========");
}

function logEnd() {
  console.log("=================================================");
}

/**
 * Perform initialization before any execution.
 *
 * @param {Object} ctx - cordova context object
 */
function init(ctx) {
  packageJsonFilePath = path.join(ctx.opts.projectRoot, 'plugins', ctx.opts.plugin.id, 'package.json');
}

module.exports = function(ctx) {
  logStart();

  init(ctx);
  installRequiredNodeModules(getPackagesFromJson);
};
<commit_msg>Changes in detecting if node module is installed.<commit_after>/**
Hook is executed when plugin is added to the project.
It will check all necessary module dependencies and install the missing ones locally.
Also, it will suggest to user to install CLI client for that plugin.
It can be found in https://github.com/nordnet/cordova-hot-code-push-cli
*/

var exec = require('child_process').exec,
  path = require('path'),
  modules = ['read-package-json'],
  chcpCliPackageName = 'cordova-hot-code-push-cli',
  packageJsonFilePath;

// region NPM specific

/**
 * Discovers module dependencies in plugin's package.json and installs them.
 */
function getPackagesFromJson() {
  var readJson = require('read-package-json');
  readJson(packageJsonFilePath, console.error, false, function(err, data) {
    if (err) {
      console.error('Can\'t read package.json file: ' + err);
      return;
    }

    var dependencies = data['dependencies'];
    if (dependencies) {
      for (var module in dependencies) {
        modules.push(module);
      }
      installRequiredNodeModules(function() {
        console.log('All dependency modules are installed.');
        checkCliDependency();
      });
    }
  });
}

/**
 * Check if node package is installed.
 *
 * @param {String} moduleName
 * @return {Boolean} true if package already installed
 */
function isNodeModuleInstalled(moduleName) {
  var installed = true;
  try {
    var module = require(moduleName);
  } catch (err) {
    installed = false;
  }

  return installed;
}

/**
 * Install node module locally.
 * Basically, it runs 'npm install module_name'.
 *
 * @param {String} moduleName
 * @param {Callback(error)} callback
 */
function installNodeModule(moduleName, callback) {
  if (isNodeModuleInstalled(moduleName)) {
    console.log('Node module ' + moduleName + ' is found');
    callback(null);
    return;
  }
  console.log('Can\'t find module ' + moduleName + ', running npm install');

  var cmd = 'npm install -D ' + moduleName;
  exec(cmd, function(err, stdout, stderr) {
    callback(err);
  });
}

/**
 * Install all required node packages.
 */
function installRequiredNodeModules(callback) {
  if (modules.length == 0) {
    callback();
    return;
  }

  var moduleName = modules.shift();
  installNodeModule(moduleName, function(err) {
    if (err) {
      console.log('Failed to install module ' + moduleName);
      console.log(err);
      return;
    }

    console.log('Module ' + moduleName + ' is installed');
    installRequiredNodeModules(callback);
  });
}

// endregion

// region CLI specific

/**
 * Check if cordova-hcp utility is installed. If not - suggest user to install it.
 */
function checkCliDependency() {
  checkIfChcpInstalled(function(err) {
    if (err) {
      suggestCliInstallation();
    }

    logEnd();
  });
}

/**
 * Check if cordova-hcp utility is installed.
 *
 * @param {Callback(error)} callback
 */
function checkIfChcpInstalled(callback) {
  var cmd = 'npm -g list ' + chcpCliPackageName;
  exec(cmd, function(err, stdout, stderr) {
    callback(err);
  });
}

/**
 * Show message, that developer should install CLI client for the plugin, so it would be easier to use.
 */
function suggestCliInstallation() {
  console.log('');
  console.log('To make the development process easier for you - we developed a CLI client for our plugin.');
  console.log('To install it, please, use command:');
  console.log('npm install -g ' + chcpCliPackageName);
  console.log('For more information please visit https://github.com/nordnet/cordova-hot-code-push-cli');
}

// endregion

function logStart() {
  console.log("======== CHCP after plugin add process ========");
}

function logEnd() {
  console.log("=================================================");
}

/**
 * Perform initialization before any execution.
 *
 * @param {Object} ctx - cordova context object
 */
function init(ctx) {
  packageJsonFilePath = path.join(ctx.opts.projectRoot, 'plugins', ctx.opts.plugin.id, 'package.json');
}

module.exports = function(ctx) {
  logStart();

  init(ctx);
  installRequiredNodeModules(getPackagesFromJson);
};
<|endoftext|>


<commit_before>(function($) {

    $.Redactor.prototype.iframely = function() {
        return {

            langs: {
                en: {
                    'iframely': 'Embed',
                    'enter-url': 'Enter URL you want to embed'
                }
            },

            getTemplate: function() {
				return String()
				+ '
'
					+ '
'
						+ '' + this.lang.get('enter-url') + ''
						+ '<input type="text" id="redactor-insert-iframely-area" />'
					+ '
'
                    + '
'
                        + ' '
                    + '
'
					+ '
'
						+ '<button id="redactor-modal-button-action">Insert</button>'
						+ '<button id="redactor-modal-button-cancel">Cancel</button>'
					+ '
'
				+ '
';
            },

            init: function() {

                this.iframely.cache = {};

                var button = this.button.addAfter('image', 'iframely', this.lang.get('iframely'));
                this.button.addCallback(button, this.iframely.show);

                this.core.element().on('linkify.callback.redactor', this.iframely.linkify);
                this.core.element().on('syncBefore.callback.redactor', this.iframely.syncBefore);
            },

            syncBefore: function(html) {
                // Restore original embed code from embed wrapper attribute value.
                var $data = $('
').html(html);
                $data.find('[data-embed-code]').each(function() {
                    var $this = $(this);
                    $this.html($this.attr('data-embed-code'));
                });

                return $data.html();
            },

            linkify: function($elements) {

                var that = this;

                $elements.each(function(i, el) {

                    var $el = $(el);
                    if ($el.is('a')) {
                        var uri = $el.attr('href');

                        var otherParagraphElements = $el.parent().contents().filter(function() {
                            var text = $.trim(this.textContent);
                            if (text.length === 1 && text.charCodeAt(0) === 8203) {
                                // Clear ZERO WIDTH SPACE.
                                text = '';
                            }
                            if (text) {
                                var href = this.getAttribute && this.getAttribute('href');
                                if (href !== uri) {
                                    // Paragraph has another links.
                                    return true;
                                }
                                if (!href) {
                                    // Paragraph has another text.
                                    return true;
                                }
                            }
                        });

                        if (otherParagraphElements.length) {
                            // Prevent insert inside paragraph with text.
                            return;
                        }

                        that.iframely.fetchUrl(uri, function(error, html) {

                            // buffer
                            that.buffer.set();

                            // insert
                            that.air.collapsed();
                            $el.parent().html(html);
                        });
                    }
                });
            },

            show: function() {

                var that = this;

                this.modal.addTemplate('iframely', this.iframely.getTemplate());

                this.modal.load('iframely', this.lang.get('iframely'), 700);

                // action button
                this.modal.getActionButton().text(this.lang.get('insert')).on('click', this.iframely.insert);
                this.modal.show();

                // Move modal to top.
                setTimeout(function() {

                    var $modalParent = $(that.modal.getModal()).parent();
                    var previewHeight = $(window).height() - $modalParent.height() - 16;

                    $modalParent.css('margin-top', '16px');

                    $('#redactor-modal-iframely-preview').css('max-height', previewHeight + 'px');

                }, 1);

                var $input = $('#redactor-insert-iframely-area');

                var keyupTimeout = null;
                $input.keyup(function() {

                    if (keyupTimeout) {

                        // Wait for next preview.

                        clearTimeout(keyupTimeout);

                        keyupTimeout = setTimeout(function() {
                            that.iframely.preview();
                            keyupTimeout = null;
                        }, 1000);

                    } else {

                        // First preview start immediately.

                        keyupTimeout = setTimeout(function() {
                            keyupTimeout = null;
                        }, 1000);

                        that.iframely.preview();
                    }
                });

                // focus
                if (this.detect.isDesktop()) {
                    setTimeout(function() {
                        $input.focus();
                    }, 1);
                }
            },

            preview: function() {

                var $input = $('#redactor-insert-iframely-area');

                var uri = $.trim($input.val());
                var previousUri = $.trim($input.attr('data-previous-value'));

                if (uri === previousUri) {
                    return;
                }

                $input.removeAttr('data-preview-html');
                $input.attr('data-previous-value', uri);

                var $preview = $('#redactor-modal-iframely-preview');

                var loadingTimeout = setTimeout(function() {
                    $preview.text('Loading...');
                }, 1500);

                this.iframely.fetchUrl(uri, function(error, html) {

                    clearTimeout(loadingTimeout);

                    if (error || !html) {

                        $preview.html(' ');

                    } else {

                        // Store result for later use.
                        $input.attr('data-preview-html', html);

                        $preview.html(html);
                    }
                });
            },

            insert: function() {

                var that = this;
                var $input = $('#redactor-insert-iframely-area');
                var uri = $.trim($input.val());
                var previewHtml = $input.attr('data-preview-html');

                function insert(html) {
                    that.modal.close();
                    that.placeholder.hide();

                    // buffer
                    that.buffer.set();

                    // insert
                    that.air.collapsed();
                    that.insert.html(html);
                }

                if (previewHtml) {

                    insert(previewHtml);

                } else {

                    this.iframely.fetchUrl(uri, function(error, html) {

                        if (error || !html) {

                            var $preview = $('#redactor-modal-iframely-preview');
                            $preview.text('Sorry, no embeds for this URL');

                        } else {

                            insert(html);
                        }
                    });
                }
            },

            fetchUrl: function(uri, cb) {

                if (!uri.match(/(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)\.(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/i)) {
                    return cb();
                }

                var that = this;

                var data = that.iframely.cache[uri];

                if (data) {
                    return cb(data.error, data.html);
                }

                $.ajax({
                    url: this.opts.oembedEndpoint || 'http://open.iframe.ly/api/oembed',
                    dataType: "json",
                    data: {
                        url: uri,
                        origin: 'redactor'
                    },
                    success: function(data, textStatus, jqXHR) {

                        var html;

                        if (data && data.html) {
                            html = data.html;
                        } else if (data && !data.html && data.type === 'photo' && data.url) {
                            html = '';
                        }

                        that.iframely.cache[uri] = {
                            html: html
                        };

                        var $div = $('
')
                            .attr('data-oembed-url', uri)
                            .attr('data-embed-code', html)
                            .html(html);

                        html = $('
').append($div).html();

                        cb(null, html);
                    },
                    error: function(jqXHR, textStatus, errorThrown) {
                        console.error(jqXHR && jqXHR.responseText || textStatus);

                        // TODO: parse responseText.
                        var error = jqXHR && jqXHR.responseText || textStatus;

                        that.iframely.cache[uri] = {
                            error: error
                        };

                        cb(error);
                    }
                });
            }

        };
    };
})(jQuery);<commit_msg>fix caret position after insert<commit_after>(function($) {

    $.Redactor.prototype.iframely = function() {
        return {

            langs: {
                en: {
                    'iframely': 'Embed',
                    'enter-url': 'Enter URL you want to embed'
                }
            },

            getTemplate: function() {
				return String()
				+ '
'
					+ '
'
						+ '' + this.lang.get('enter-url') + ''
						+ '<input type="text" id="redactor-insert-iframely-area" />'
					+ '
'
                    + '
'
                        + ' '
                    + '
'
					+ '
'
						+ '<button id="redactor-modal-button-action">Insert</button>'
						+ '<button id="redactor-modal-button-cancel">Cancel</button>'
					+ '
'
				+ '
';
            },

            init: function() {

                this.iframely.cache = {};

                var button = this.button.addAfter('image', 'iframely', this.lang.get('iframely'));
                this.button.addCallback(button, this.iframely.show);

                this.core.element().on('linkify.callback.redactor', this.iframely.linkify);
                this.core.element().on('syncBefore.callback.redactor', this.iframely.syncBefore);
            },

            syncBefore: function(html) {
                // Restore original embed code from embed wrapper attribute value.
                var $data = $('
').html(html);
                $data.find('[data-embed-code]').each(function() {
                    var $this = $(this);
                    $this.html($this.attr('data-embed-code'));
                });

                return $data.html();
            },

            linkify: function($elements) {

                var that = this;

                $elements.each(function(i, el) {

                    var $el = $(el);
                    if ($el.is('a')) {
                        var uri = $el.attr('href');

                        var otherParagraphElements = $el.parent().contents().filter(function() {
                            var text = $.trim(this.textContent);
                            if (text.length === 1 && text.charCodeAt(0) === 8203) {
                                // Clear ZERO WIDTH SPACE.
                                text = '';
                            }
                            if (text) {
                                var href = this.getAttribute && this.getAttribute('href');
                                if (href !== uri) {
                                    // Paragraph has another links.
                                    return true;
                                }
                                if (!href) {
                                    // Paragraph has another text.
                                    return true;
                                }
                            }
                        });

                        if (otherParagraphElements.length) {
                            // Prevent insert inside paragraph with text.
                            return;
                        }

                        that.iframely.fetchUrl(uri, function(error, html) {

                            // buffer
                            that.buffer.set();

                            // insert
                            that.air.collapsed();
                            $el.parent().html(html);
                        });
                    }
                });
            },

            show: function() {

                var that = this;

                this.modal.addTemplate('iframely', this.iframely.getTemplate());

                this.modal.load('iframely', this.lang.get('iframely'), 700);

                // action button
                this.modal.getActionButton().text(this.lang.get('insert')).on('click', this.iframely.insert);
                this.modal.show();

                // Move modal to top.
                setTimeout(function() {

                    var $modalParent = $(that.modal.getModal()).parent();
                    var previewHeight = $(window).height() - $modalParent.height() - 16;

                    $modalParent.css('margin-top', '16px');

                    $('#redactor-modal-iframely-preview').css('max-height', previewHeight + 'px');

                }, 1);

                var $input = $('#redactor-insert-iframely-area');

                var keyupTimeout = null;
                $input.keyup(function() {

                    if (keyupTimeout) {

                        // Wait for next preview.

                        clearTimeout(keyupTimeout);

                        keyupTimeout = setTimeout(function() {
                            that.iframely.preview();
                            keyupTimeout = null;
                        }, 1000);

                    } else {

                        // First preview start immediately.

                        keyupTimeout = setTimeout(function() {
                            keyupTimeout = null;
                        }, 1000);

                        that.iframely.preview();
                    }
                });

                // focus
                if (this.detect.isDesktop()) {
                    setTimeout(function() {
                        $input.focus();
                    }, 1);
                }
            },

            preview: function() {

                var $input = $('#redactor-insert-iframely-area');

                var uri = $.trim($input.val());
                var previousUri = $.trim($input.attr('data-previous-value'));

                if (uri === previousUri) {
                    return;
                }

                $input.removeAttr('data-preview-html');
                $input.attr('data-previous-value', uri);

                var $preview = $('#redactor-modal-iframely-preview');

                var loadingTimeout = setTimeout(function() {
                    $preview.text('Loading...');
                }, 1500);

                this.iframely.fetchUrl(uri, function(error, html) {

                    clearTimeout(loadingTimeout);

                    if (error || !html) {

                        $preview.html(' ');

                    } else {

                        // Store result for later use.
                        $input.attr('data-preview-html', html);

                        $preview.html(html);
                    }
                });
            },

            insert: function() {

                var that = this;
                var $input = $('#redactor-insert-iframely-area');
                var uri = $.trim($input.val());
                var previewHtml = $input.attr('data-preview-html');

                function insert(html) {
                    that.modal.close();
                    that.placeholder.hide();

                    // buffer
                    that.buffer.set();

                    // insert
                    that.air.collapsed();

                    var $node = $(html);
                    that.insert.node($node);

                    // place cursor after inserted node
                    that.caret.after($node);
                }

                if (previewHtml) {

                    insert(previewHtml);

                } else {

                    this.iframely.fetchUrl(uri, function(error, html) {

                        if (error || !html) {

                            var $preview = $('#redactor-modal-iframely-preview');
                            $preview.text('Sorry, no embeds for this URL');

                        } else {

                            insert(html);
                        }
                    });
                }
            },

            fetchUrl: function(uri, cb) {

                if (!uri.match(/(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)\.(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/i)) {
                    return cb();
                }

                var that = this;

                var data = that.iframely.cache[uri];

                if (data) {
                    return cb(data.error, data.html);
                }

                $.ajax({
                    url: this.opts.oembedEndpoint || 'http://open.iframe.ly/api/oembed',
                    dataType: "json",
                    data: {
                        url: uri,
                        origin: 'redactor'
                    },
                    success: function(data, textStatus, jqXHR) {

                        var html;

                        if (data && data.html) {
                            html = data.html;
                        } else if (data && !data.html && data.type === 'photo' && data.url) {
                            html = '';
                        }

                        that.iframely.cache[uri] = {
                            html: html
                        };

                        var $div = $('
')
                            .attr('data-oembed-url', uri)
                            .attr('data-embed-code', html)
                            .html(html);

                        html = $('
').append($div).html();

                        cb(null, html);
                    },
                    error: function(jqXHR, textStatus, errorThrown) {
                        console.error(jqXHR && jqXHR.responseText || textStatus);

                        // TODO: parse responseText.
                        var error = jqXHR && jqXHR.responseText || textStatus;

                        that.iframely.cache[uri] = {
                            error: error
                        };

                        cb(error);
                    }
                });
            }

        };
    };
})(jQuery);<|endoftext|>


<commit_before>/**
 * Created by solee on 12/4/15.
 */

'use strict';

var koa = require('koa');
var app = koa();
var compress = require('koa-compress');
var serve = require('koa-static');
var bodyParser = require('koa-bodyparser');
var jwt = require('koa-jwt');
var cors = require('koa-cors');
var path = require('path');

//middlewares
var xResponseTime = require('./middlewares/x-response-time');
var log4jsMiddleware = require('./middlewares/koa-log4js');
var logger = require('./logger');
var requestId = require('./middlewares/common/request_id.js');

app.use(cors());
// Serve static files
app.use(serve(path.join(__dirname, '../public')));

app.use(requestId());
app.use(xResponseTime);
app.use(log4jsMiddleware);

//Please handle error here
//app.use(errorHandler());

app.use(bodyParser());

require('./routes')(app);

if (!module.parent) {
  app.listen(process.env.PORT || 3333);
  logger.info('listening on port %s', process.env.PORT || 3333);
}

module.exports = app;
<commit_msg>fix cannot find modules<commit_after>/**
 * Created by solee on 12/4/15.
 */

'use strict';

var koa = require('koa');
var app = koa();
var compress = require('koa-compress');
var serve = require('koa-static');
var bodyParser = require('koa-bodyparser');
var jwt = require('koa-jwt');
var cors = require('koa-cors');
var path = require('path');

//middlewares
var xResponseTime = require('./middlewares/common/x-response-time');
var log4jsMiddleware = require('./middlewares/common/koa-log4js');
var logger = require('./logger');
var requestId = require('./middlewares/common/request_id.js');

app.use(cors());
// Serve static files
app.use(serve(path.join(__dirname, '../public')));

app.use(requestId());
app.use(xResponseTime);
app.use(log4jsMiddleware);

//Please handle error here
//app.use(errorHandler());

app.use(bodyParser());

require('./routes')(app);

if (!module.parent) {
  app.listen(process.env.PORT || 3333);
  logger.info('listening on port %s', process.env.PORT || 3333);
}

module.exports = app;
<|endoftext|>


<commit_before>// ==UserScript==
// @author      Jan Kaiser
// @name        Imgur redirect to image
// @namespace   https://github.com/Azlond/Imgur-redirect-to-image
// @include     https://imgur.com/*
// @exclude     https://imgur.com/privacy
// @version     1.0
// @grant       none
// ==/UserScript==

var URL = window.location + ""; // current URL
var path = URL.slice(18, URL.length - 1); //strip the https://imgur.com/
if (path.length > 4) { //hacky workaround so I don't have to manually exclude all github pages like /jobs or /about
	if (!(/\?+/.test(path))) { // see if the path contains "?" or "/" - if yes, we're not interested
		try { // try to catch potential errors
			var linkElements = document.getElementsByTagName("link"); // collect all <link>-elements from the source code
			for (var i = 0; i < linkElements.length; i++) { // go through all object we just collected
				var element = linkElements[i]; // current link object
				if (element.rel == "image_src") { // if the current objects rel-attribute equals image_src, we have found the link to the image
					window.location = element.href; // redirect the current window to the image
				}
			}
		} catch (e) {
			console.log("If this script throws an error, please report it to me at the github location of this script at:");
			console.log("https://github.com/Azlond/Imgur-redirect-to-image");
			console.log("The error message is: " + e);
			console.log("Thank you.");
		}
	}
}
<commit_msg>bugfix to deal with galleries<commit_after>// ==UserScript==
// @author      Jan Kaiser
// @name        Imgur redirect to image
// @namespace   https://github.com/Azlond/Imgur-redirect-to-image
// @include     https://imgur.com/*
// @exclude     https://imgur.com/privacy
// @version     1.1
// @grant       none
// ==/UserScript==

var URL = window.location + ""; // current URL
var path = URL.slice(18, URL.length - 1); //strip the https://imgur.com/
if (path.length > 4) { //hacky workaround so I don't have to manually exclude all github pages like /jobs or /about
	if (!(/\?+|\//.test(path))) { // see if the path contains "?" or "/" - if yes, we're not interested
		try { // try to catch potential errors
			var linkElements = document.getElementsByTagName("link"); // collect all <link>-elements from the source code
			for (var i = 0; i < linkElements.length; i++) { // go through all object we just collected
				var element = linkElements[i]; // current link object
				if (element.rel == "image_src") { // if the current objects rel-attribute equals image_src, we have found the link to the image
					window.location = element.href; // redirect the current window to the image
				}
			}
		} catch (e) {
			console.log("If this script throws an error, please report it to me at the github location of this script at:");
			console.log("https://github.com/Azlond/Imgur-redirect-to-image");
			console.log("The error message is: " + e);
			console.log("Thank you.");
		}
	}
}
<|endoftext|>


<commit_before><commit_msg>Fix /profilehelp<commit_after><|endoftext|>


<commit_before>// ==========================================================================
// Project:   SproutCore - JavaScript Application Framework
// Copyright: ©2006-2009 Sprout Systems, Inc. and contributors.
//            Portions ©2008-2009 Apple, Inc. All rights reserved.
// License:   Licened under MIT license (see license.js)
// ==========================================================================

sc_require('data_sources/data_source');
sc_require('models/record');

/** @class

  TODO: Describe Class

  @extends SC.DataSource
  @since SproutCore 1.0
*/
SC.FixturesDataSource = SC.DataSource.extend( {

  // ..........................................................
  // STANDARD DATA SOURCE METHODS
  //

  /**

    Invoked by the store whenever it needs to load a fresh new batch or
    records or simply refresh based on their storeKeys. This method is
    invoked from the store methods 'findAll' and 'retrieveRecords'.

    findAll() will request all records and load them using
    store.loadRecords(). retrieveRecords() checks if the record is already
    loaded and in a clean state to then just materialize it or if is in an
    empty state, it will call this method to load the required record to
    then materialize it.

    @param {SC.Store} store the requesting store
    @param {Object} fetchKey key describing the request, may be SC.Record
    @param {Hash} params optional additonal fetch params
    @returns {SC.Array} result set with storeKeys.
  */
  fetch: function(store, fetchKey, params) {

    var ret = [], fixtures;

    // TODO: this currently only supports one recordType per SC.Query
    if(SC.instanceOf(fetchKey, SC.Query)) {
      fetchKey = fetchKey.recordType;
    }

    if(SC.typeOf(fetchKey)===SC.T_STRING) {
      fetchKey = SC.objectForPropertyPath(fetchKey);
    }

    if(fetchKey === SC.Record || SC.Record.hasSubclass(fetchKey)) {
      this.loadFixturesFor(store, fetchKey, ret);
    }

    return ret;
  },

  /**
    Load fixtures for a given fetchKey into the store
    and push it to the ret array.

    @param {SC.Store} store
    @param {SC.Record} fetchKey
    @param {SC.Array} ret
  */
  loadFixturesFor: function(store, fetchKey, ret) {
    var dataHashes, i, storeKey, hashes = [];

    dataHashes = this.fixturesFor(fetchKey);

    for(i in dataHashes){
      storeKey = fetchKey.storeKeyFor(i);
      hashes.push(dataHashes[i]);
      ret.push(storeKey);
    }

    // before loading fixtures again, make sure they have not been
    // loaded already, so that SC.Query does not end up in
    // infinite loop
    if(!this.fixturesLoadedFor(fetchKey)) {
      store.loadRecords(fetchKey, hashes);
    }

  },

  /**
    Retrieve a record from fixtures.

    @param {SC.Store} store
    @param {Number} storeKey
    @param {SC.Array} ret
  */
  retrieveRecord: function(store, storeKey) {
    var ret = [], recordType = SC.Store.recordTypeFor(storeKey),
        id = store.idFor(storeKey),
        hash = this.fixtureForStoreKey(store, storeKey);
    ret.push(storeKey);
    store.dataSourceDidComplete(storeKey, hash, id);

    return ret;
  },

  /**
    Fixture operations complete immediately so you cannot cancel them.

    @param {SC.Store} store
    @param {SC.Array} storeKeys
    @returns {Boolean} YES if handled
  */
  cancel: function(store, storeKeys) {
    return NO;
  },

  /**
    Update the dataHash in this._fixtures

    @param {SC.Store} store
    @param {Number} storeKey
    @returns {Boolean} YES if handled
  */
  updateRecord: function(store, storeKey) {
    this.setFixtureForStoreKey(store, storeKey, store.readDataHash(storeKey));
    store.dataSourceDidComplete(storeKey);
    return YES ;
  },

  /**
    Adds records to this._fixtures.  If the record does not have an id yet,
    then then calls generateIdFor() and sets that.

    @param {SC.Store} store the store
    @param {Number} storeKey the store key
    @returns {Boolean} YES if successful
  */
  createRecord: function(store, storeKey) {
    var id         = store.idFor(storeKey),
        recordType = store.recordTypeFor(storeKey),
        dataHash   = store.readDataHash(storeKey),
        fixtures   = this.fixturesFor(recordType);

    if (!id) id = this.generateIdFor(recordType, dataHash, store, storeKey);
    this._invalidateCachesFor(recordType, storeKey, id);
    fixtures[id] = dataHash;

    store.dataSourceDidComplete(storeKey, null, id);
    return YES ;
  },

  /**
    Removes the data from the fixtures.

    @param {SC.Store} store the store
    @param {Number} storeKey the store key
    @returns {Boolean} YES if successful
  */
  destroyRecord: function(store, storeKey) {
    var id         = store.idFor(storeKey),
        recordType = store.recordTypeFor(storeKey),
        fixtures   = this.fixturesFor(recordType);

    this._invalidateCachesFor(recordType, storeKey, id);
    if (id) delete fixtures[id];
    store.dataSourceDidDestroy(storeKey);
    return YES ;
  },

  // ..........................................................
  // INTERNAL METHODS
  //

  /**
    Generates an id for the passed record type.  You can override this if
    needed.  The default generates a storekey and formats it as a string.
  */
  generateIdFor: function(recordType, dataHash, store, storeKey) {
    return "@id%@".fmt(SC.Store.generateStoreKey());
  },

  /**
    Based on the storeKey it returns the specified fixtures

    @param {SC.Store} store the store
    @param {Number} storeKey the storeKey
    @returns {Hash} data hash or null
  */
  fixtureForStoreKey: function(store, storeKey) {
    var id         = store.idFor(storeKey),
        recordType = store.recordTypeFor(storeKey),
        fixtures   = this.fixturesFor(recordType);
    return fixtures ? fixtures[id] : null;
  },

  /**
    Sets the data hash fixture for the named store key.

    @param {SC.Store} store the store
    @param {Number} storeKey the storeKey
    @param {Hash} dataHash
    @returns {SC.FixturesDataSource} receiver
  */
  setFixtureForStoreKey: function(store, storeKey, dataHash) {
    var id         = store.idFor(storeKey),
        recordType = store.recordTypeFor(storeKey),
        fixtures   = this.fixturesFor(recordType);
    this._invalidateCachesFor(recordType, storeKey, id);
    fixtures[id] = dataHash;
    return this ;
  },

  /**
    Invoked methods to ensure fixtures for a particular record type have been
    loaded.

    @param {SC.Record} recordType
    @returns {Hash} data hashes
  */
  fixturesFor: function(recordType) {
    // get basic fixtures hash.
    if (!this._fixtures) this._fixtures = {};
    var fixtures = this._fixtures[SC.guidFor(recordType)];
    if (fixtures) return fixtures ;

    // need to load fixtures.
    var dataHashes = recordType ? recordType.FIXTURES : null,
        len        = dataHashes ? dataHashes.length : 0,
        primaryKey = recordType ? recordType.prototype.primaryKey : 'guid',
        idx, dataHash, id ;

    this._fixtures[SC.guidFor(recordType)] = fixtures = {} ;
    for(idx=0;idx<len;idx++) {
      dataHash = dataHashes[idx];
      id = dataHash[primaryKey];
      if (!id) id = this.generateIdFor(recordType, dataHash);
      fixtures[id] = dataHash;
    }
    return fixtures;
  },

  /**
    Returns YES is fixtures for a given recordType have already been loaded

    @param {SC.Record} recordType
    @returns {Boolean} storeKeys
  */
  fixturesLoadedFor: function(recordType) {
    if (!this._fixtures) return NO;
    var ret = [], fixtures = this._fixtures[SC.guidFor(recordType)];
    return fixtures ? YES: NO;
  },

  /**
    Invalidates any internal caches based on the recordType and optional
    other parameters.  Currently this only invalidates the storeKeyCache used
    for fetch, but it could invalidate others later as well.

    @param {SC.Record} recordType the type of record modified
    @param {Number} storeKey optional store key
    @param {String} id optional record id
    @returns {SC.FixturesDataSource} receiver
  */
  _invalidateCachesFor: function(recordType, storeKey, id) {
    var cache = this._storeKeyCache;
    if (cache) delete cache[SC.guidFor(recordType)]
    return this ;
  }

});

// create default instance for use when configuring
SC.Record.fixtures = SC.FixturesDataSource.create();
<commit_msg>Fixes to FixturesDataSource, making it work with SC.Query<commit_after>// ==========================================================================
// Project:   SproutCore - JavaScript Application Framework
// Copyright: ©2006-2009 Sprout Systems, Inc. and contributors.
//            Portions ©2008-2009 Apple, Inc. All rights reserved.
// License:   Licened under MIT license (see license.js)
// ==========================================================================

sc_require('data_sources/data_source');
sc_require('models/record');

/** @class

  TODO: Describe Class

  @extends SC.DataSource
  @since SproutCore 1.0
*/
SC.FixturesDataSource = SC.DataSource.extend( {

  // ..........................................................
  // STANDARD DATA SOURCE METHODS
  //

  /**

    Invoked by the store whenever it needs to load a fresh new batch or
    records or simply refresh based on their storeKeys. This method is
    invoked from the store methods 'findAll' and 'retrieveRecords'.

    findAll() will request all records and load them using
    store.loadRecords(). retrieveRecords() checks if the record is already
    loaded and in a clean state to then just materialize it or if is in an
    empty state, it will call this method to load the required record to
    then materialize it.

    @param {SC.Store} store the requesting store
    @param {Object} fetchKey key describing the request, may be SC.Record
    @param {Hash} params optional additonal fetch params
    @returns {SC.Array} result set with storeKeys.
  */
  fetch: function(store, fetchKey, params) {

    var ret = [], fixtures;

    // TODO: this currently only supports one recordType per SC.Query
    if(SC.instanceOf(fetchKey, SC.Query)) {
      fetchKey = fetchKey.recordType;
    }

    if(SC.typeOf(fetchKey)===SC.T_STRING) {
      fetchKey = SC.objectForPropertyPath(fetchKey);
    }

    if(fetchKey === SC.Record || SC.Record.hasSubclass(fetchKey)) {
      this.loadFixturesFor(store, fetchKey, ret);
    }

    return ret;
  },

  /**
    Load fixtures for a given fetchKey into the store
    and push it to the ret array.

    @param {SC.Store} store
    @param {SC.Record} fetchKey
    @param {SC.Array} ret
  */
  loadFixturesFor: function(store, fetchKey, ret) {
    var dataHashes, i, storeKey, hashes = [];

    dataHashes = this.fixturesFor(fetchKey);

    for(i in dataHashes){
      storeKey = fetchKey.storeKeyFor(i);
      hashes.push(dataHashes[i]);
      ret.push(storeKey);
    }

    // before loading fixtures again, make sure they have not been
    // loaded already, so that SC.Query does not end up in
    // infinite loop
    if(!this.fixturesLoadedFor(fetchKey)) {
      store.loadRecords(fetchKey, hashes);
    }

  },

  /**
    Load fixtures for a given fetchKey into the store
    and push it to the ret array.

    @param {SC.Store} store
    @param {SC.Record} fetchKey
    @param {SC.Array} ret
  */
  loadFixturesFor: function(store, fetchKey, ret) {
    var dataHashes, i, storeKey, hashes = [];
    dataHashes = this.fixturesFor(fetchKey);
    for(i in dataHashes){
      storeKey = fetchKey.storeKeyFor(i);
      hashes.push(dataHashes[i]);
      ret.push(storeKey);
    }
    store.loadRecords(fetchKey, hashes);
  },

  /**
    Retrieve a record from fixtures.

    @param {SC.Store} store
    @param {Number} storeKey
    @param {SC.Array} ret
  */
  retrieveRecord: function(store, storeKey) {
    var ret = [], recordType = SC.Store.recordTypeFor(storeKey),
        id = store.idFor(storeKey),
        hash = this.fixtureForStoreKey(store, storeKey);
    ret.push(storeKey);
    store.dataSourceDidComplete(storeKey, hash, id);

    return ret;
  },

  /**
    Fixture operations complete immediately so you cannot cancel them.

    @param {SC.Store} store
    @param {SC.Array} storeKeys
    @returns {Boolean} YES if handled
  */
  cancel: function(store, storeKeys) {
    return NO;
  },

  /**
    Update the dataHash in this._fixtures

    @param {SC.Store} store
    @param {Number} storeKey
    @returns {Boolean} YES if handled
  */
  updateRecord: function(store, storeKey) {
    this.setFixtureForStoreKey(store, storeKey, store.readDataHash(storeKey));
    store.dataSourceDidComplete(storeKey);
    return YES ;
  },

  /**
    Adds records to this._fixtures.  If the record does not have an id yet,
    then then calls generateIdFor() and sets that.

    @param {SC.Store} store the store
    @param {Number} storeKey the store key
    @returns {Boolean} YES if successful
  */
  createRecord: function(store, storeKey) {
    var id         = store.idFor(storeKey),
        recordType = store.recordTypeFor(storeKey),
        dataHash   = store.readDataHash(storeKey),
        fixtures   = this.fixturesFor(recordType);

    if (!id) id = this.generateIdFor(recordType, dataHash, store, storeKey);
    this._invalidateCachesFor(recordType, storeKey, id);
    fixtures[id] = dataHash;

    store.dataSourceDidComplete(storeKey, null, id);
    return YES ;
  },

  /**
    Removes the data from the fixtures.

    @param {SC.Store} store the store
    @param {Number} storeKey the store key
    @returns {Boolean} YES if successful
  */
  destroyRecord: function(store, storeKey) {
    var id         = store.idFor(storeKey),
        recordType = store.recordTypeFor(storeKey),
        fixtures   = this.fixturesFor(recordType);

    this._invalidateCachesFor(recordType, storeKey, id);
    if (id) delete fixtures[id];
    store.dataSourceDidDestroy(storeKey);
    return YES ;
  },

  // ..........................................................
  // INTERNAL METHODS
  //

  /**
    Generates an id for the passed record type.  You can override this if
    needed.  The default generates a storekey and formats it as a string.
  */
  generateIdFor: function(recordType, dataHash, store, storeKey) {
    return "@id%@".fmt(SC.Store.generateStoreKey());
  },

  /**
    Based on the storeKey it returns the specified fixtures

    @param {SC.Store} store the store
    @param {Number} storeKey the storeKey
    @returns {Hash} data hash or null
  */
  fixtureForStoreKey: function(store, storeKey) {
    var id         = store.idFor(storeKey),
        recordType = store.recordTypeFor(storeKey),
        fixtures   = this.fixturesFor(recordType);
    return fixtures ? fixtures[id] : null;
  },

  /**
    Sets the data hash fixture for the named store key.

    @param {SC.Store} store the store
    @param {Number} storeKey the storeKey
    @param {Hash} dataHash
    @returns {SC.FixturesDataSource} receiver
  */
  setFixtureForStoreKey: function(store, storeKey, dataHash) {
    var id         = store.idFor(storeKey),
        recordType = store.recordTypeFor(storeKey),
        fixtures   = this.fixturesFor(recordType);
    this._invalidateCachesFor(recordType, storeKey, id);
    fixtures[id] = dataHash;
    return this ;
  },

  /**
    Invoked methods to ensure fixtures for a particular record type have been
    loaded.

    @param {SC.Record} recordType
    @returns {Hash} data hashes
  */
  fixturesFor: function(recordType) {
    // get basic fixtures hash.
    if (!this._fixtures) this._fixtures = {};
    var fixtures = this._fixtures[SC.guidFor(recordType)];
    if (fixtures) return fixtures ;

    // need to load fixtures.
    var dataHashes = recordType ? recordType.FIXTURES : null,
        len        = dataHashes ? dataHashes.length : 0,
        primaryKey = recordType ? recordType.prototype.primaryKey : 'guid',
        idx, dataHash, id ;

    this._fixtures[SC.guidFor(recordType)] = fixtures = {} ;
    for(idx=0;idx<len;idx++) {
      dataHash = dataHashes[idx];
      id = dataHash[primaryKey];
      if (!id) id = this.generateIdFor(recordType, dataHash);
      fixtures[id] = dataHash;
    }
    return fixtures;
  },

  /**
    Returns YES is fixtures for a given recordType have already been loaded

    @param {SC.Record} recordType
    @returns {Boolean} storeKeys
  */
  fixturesLoadedFor: function(recordType) {
    if (!this._fixtures) return NO;
    var ret = [], fixtures = this._fixtures[SC.guidFor(recordType)];
    return fixtures ? YES: NO;
  },

  /**
    Invalidates any internal caches based on the recordType and optional
    other parameters.  Currently this only invalidates the storeKeyCache used
    for fetch, but it could invalidate others later as well.

    @param {SC.Record} recordType the type of record modified
    @param {Number} storeKey optional store key
    @param {String} id optional record id
    @returns {SC.FixturesDataSource} receiver
  */
  _invalidateCachesFor: function(recordType, storeKey, id) {
    var cache = this._storeKeyCache;
    if (cache) delete cache[SC.guidFor(recordType)]
    return this ;
  }

});

// create default instance for use when configuring
SC.Record.fixtures = SC.FixturesDataSource.create();
<|endoftext|>


<commit_before>'use strict';

(function (angular) {
  angular.module('eventsFeedPluginWidget')
    .controller('WidgetFeedCtrl', ['$scope', 'DataStore', 'TAG_NAMES', 'STATUS_CODE', 'Location', 'LAYOUTS', 'CalenderFeedApi','PAGINATION',
      function ($scope, DataStore, TAG_NAMES, STATUS_CODE, Location, LAYOUTS, CalenderFeedApi,PAGINATION) {
        var WidgetFeed = this;

        WidgetFeed.data = null;
        WidgetFeed.events = [];
        WidgetFeed.busy = false;
        WidgetFeed.offset = 0;
          $scope.today = function() {
              $scope.dt = new Date();
          };
          $scope.today();
          $scope.disabled = function(date, mode) {
              return ( mode === 'day' && ( date.getDay() === 0 || date.getDay() === 6 ) );
          };
          $scope.toggleMin = function() {
              $scope.minDate = $scope.minDate ? null : new Date();
          };
          $scope.toggleMin();
          $scope.maxDate = new Date(2020, 5, 22);

          /*
           * Fetch user's data from datastore
           */
        var init = function () {
          var success = function (result) {
              WidgetFeed.data = result.data;
              if (!WidgetFeed.data.content)
                WidgetFeed.data.content = {};
              if (!WidgetFeed.data.design)
                WidgetFeed.data.design = {};
              if (!WidgetFeed.data.design.itemDetailsLayout) {
                WidgetFeed.data.design.itemDetailsLayout = LAYOUTS.itemDetailsLayout[0].name;
              }
            }
            , error = function (err) {
              if (err && err.code !== STATUS_CODE.NOT_FOUND) {
                console.error('Error while getting data', err);
              }
            };
          DataStore.get(TAG_NAMES.EVENTS_FEED_INFO).then(success, error);
        };
        init();

        var getFeedEvents = function (url) {
          var success = function (result) {
              console.log("??????????????????????", result);
              WidgetFeed.events = WidgetFeed.events.length ? WidgetFeed.events.concat(result.events) : result.events;
              WidgetFeed.offset = WidgetFeed.offset + PAGINATION.eventsCount ;
              if (WidgetFeed.events.length < result.totalEvents) {
                WidgetFeed.busy = false;
              }
            }
            , error = function (err) {
              console.error('Error In Fetching events', err);
            };
          CalenderFeedApi.getFeedEvents(url,WidgetFeed.offset ).then(success, error);
        };

        WidgetFeed.loadMore = function () {
          if (WidgetFeed.busy) return;
          WidgetFeed.busy = true;
          getFeedEvents(WidgetFeed.data.content.feedUrl);
        };
      }])
})(window.angular);
<commit_msg>Added condition for feed fetching in case there is no url<commit_after>'use strict';

(function (angular) {
  angular.module('eventsFeedPluginWidget')
    .controller('WidgetFeedCtrl', ['$scope', 'DataStore', 'TAG_NAMES', 'STATUS_CODE', 'Location', 'LAYOUTS', 'CalenderFeedApi', 'PAGINATION',
      function ($scope, DataStore, TAG_NAMES, STATUS_CODE, Location, LAYOUTS, CalenderFeedApi, PAGINATION) {
        var WidgetFeed = this;

        WidgetFeed.data = null;
        WidgetFeed.events = [];
        WidgetFeed.busy = false;
        WidgetFeed.offset = 0;
        $scope.today = function () {
          $scope.dt = new Date();
        };
        $scope.today();
        $scope.disabled = function (date, mode) {
          return ( mode === 'day' && ( date.getDay() === 0 || date.getDay() === 6 ) );
        };
        $scope.toggleMin = function () {
          $scope.minDate = $scope.minDate ? null : new Date();
        };
        $scope.toggleMin();
        $scope.maxDate = new Date(2020, 5, 22);

        /*
         * Fetch user's data from datastore
         */
        var init = function () {
          var success = function (result) {
              WidgetFeed.data = result.data;
              if (!WidgetFeed.data.content)
                WidgetFeed.data.content = {};
              if (!WidgetFeed.data.design)
                WidgetFeed.data.design = {};
              if (!WidgetFeed.data.design.itemDetailsLayout) {
                WidgetFeed.data.design.itemDetailsLayout = LAYOUTS.itemDetailsLayout[0].name;
              }
            }
            , error = function (err) {
              if (err && err.code !== STATUS_CODE.NOT_FOUND) {
                console.error('Error while getting data', err);
              }
            };
          DataStore.get(TAG_NAMES.EVENTS_FEED_INFO).then(success, error);
        };
        init();

        var getFeedEvents = function (url) {
          var success = function (result) {
              console.log("??????????????????????", result);
              WidgetFeed.events = WidgetFeed.events.length ? WidgetFeed.events.concat(result.events) : result.events;
              WidgetFeed.offset = WidgetFeed.offset + PAGINATION.eventsCount;
              if (WidgetFeed.events.length < result.totalEvents) {
                WidgetFeed.busy = false;
              }
            }
            , error = function (err) {
              console.error('Error In Fetching events', err);
            };
          CalenderFeedApi.getFeedEvents(url, WidgetFeed.offset).then(success, error);
        };

        WidgetFeed.loadMore = function () {
          if (WidgetFeed.busy) return;
          WidgetFeed.busy = true;
          if (WidgetFeed.data.content.feedUrl)
            getFeedEvents(WidgetFeed.data.content.feedUrl);
        };
      }])
})(window.angular);
<|endoftext|>


<commit_before>/**
 * E2E tests for /providers.
 */
var helper = require('../../protractor-help');

'use strict';

describe('providers test', function () {
  var ptor = protractor.getInstance();
  var formfields;
  var providersList;

  it('should log in', function () {
    helper.loginAsAdmin();
  });

  it('should show the correct fields for provider type', function() {
    browser.get('/providers/create');

    expect(
      browser.getLocationAbsUrl()
    ).toMatch(/\/providers\/create$/);

    browser.waitForAngular();

    element(by.cssContainingText('option', 'google')).click();
    formfields = element.all(by.repeater('(name,fieldData) in config.fields'));
    expect(formfields.count()).toEqual(7);

    element(by.cssContainingText('option', 'aws')).click();
    formfields = element.all(by.repeater('(name,fieldData) in config.fields'));
    expect(formfields.count()).toEqual(15);
  });

  it('should fill in default values', function () {
    element(by.cssContainingText('option', 'google')).click();
    formfields = element.all(by.repeater('(name,fieldData) in config.fields'));
    var size = formfields.get(2).element(by.css('input')).getAttribute('value');
    expect(size).toEqual('10');
    var zone = formfields.get(6).element(by.css('select')).getAttribute('value');
    expect(zone).toEqual('5');
  });

  it('should create a provider', function () {
    element(by.name('name')).sendKeys('Testprovider');
    element(by.css('#inputProviderDescription')).sendKeys('Test description');
    element(by.cssContainingText('option', 'google')).click();
    formfields = element.all(by.repeater('(name,fieldData) in config.fields'));
    formfields.first().element(by.css('input')).sendKeys('Test resource');
    formfields.get(5).element(by.css('input')).sendKeys('Test username');
    formfields.get(1).element(by.css('input')).sendKeys('Test email');
    formfields.get(3).element(by.css('input')).sendKeys('Test project id');
    formfields.get(4).element(by.css('input')).sendKeys('Test keyname');
    element(by.partialButtonText('Create')).click();

    browser.waitForAngular();

    expect(
      browser.getLocationAbsUrl()
    ).toMatch(/\/providers$/);

    providersList = element.all(by.repeater('item in list'));
    expect(providersList.count()).toEqual(8);
    var providerText = providersList.last().getText();
    expect(providerText).toMatch('Testprovider Test description Edit\nDelete');
  });

  it('should delete provider upon clicking delete', function () {
    providersList.last().element(by.css('.delete-btn')).click();
    ptor.switchTo().alert().accept();
    providersList = element.all(by.repeater('item in list'));
    expect(providersList.count()).toEqual(7);
  });

  it('should navigate to provider edit page and show fields.', function () {
    browser.get('/providers/edit/google');

    expect(
      browser.getLocationAbsUrl()
    ).toMatch(/\/providers\/edit\/google$/);

    expect(element(by.css('#inputProviderName')).getAttribute('value')).toBe('google');
    expect(element(by.css('#inputProviderDescription')).getAttribute('value')).toBe('Google Compute Engine');
    expect(element(by.css('#inputProviderType')).getAttribute('value')).toBe('1');
    formfields = element.all(by.repeater('(name,fieldData) in config.fields'));
    var size = formfields.get(2).element(by.css('input')).getAttribute('value');
    expect(size).toEqual('10');
    var zone = formfields.get(6).element(by.css('select')).getAttribute('value');
    expect(zone).toEqual('5');
  });

  // !TODO Add these tests once reset endpoint becomes available.

  // it('should submit provider update form', function () {
  //   formfields.first().element(by.css('input')).clear().sendKeys('apifoo');
  //   formfields.get(1).element(by.css('input')).clear().sendKeys('emailfoo');
  //   formfields.get(2).element(by.css('input')).clear().sendKeys(12);
  //   formfields.get(3).element(by.css('input')).clear().sendKeys('idfoo');
  //   formfields.get(4).element(by.css('input')).clear().sendKeys('sshfoo');
  //   formfields.get(5).element(by.css('input')).clear().sendKeys('resourcefoo');
  //   element(by.partialButtonText('Update')).click();

  //   expect(
  //     browser.getLocationAbsUrl()
  //   ).toMatch(/\/providers$/);
  // });

  // it('should show new provider data', function () {
  //   browser.get('/providers/edit/google');

  //   expect(
  //     browser.getLocationAbsUrl()
  //   ).toMatch(/\/providers\/edit\/google$/);

  //   formfields = element.all(by.repeater('(name,fieldData) in config.fields'));
  //   expect(formfields.first().element(by.css('input')).getAttribute('value')).toBe('apifoo');
  //   expect(formfields.get(1).element(by.css('input')).getAttribute('value')).toBe('emailfoo');
  //   expect(formfields.get(2).element(by.css('input')).getAttribute('value')).toBe('12');
  //   expect(formfields.get(3).element(by.css('input')).getAttribute('value')).toBe('idfoo');
  //   expect(formfields.get(4).element(by.css('input')).getAttribute('value')).toBe('sshfoo');
  //   expect(formfields.get(5).element(by.css('input')).getAttribute('value')).toBe('resourcefoo');

  //   // !TODO call /reset to get default data back to normal once default data has been implemented.
  //   // browser.get('/reset');
  // });

  it('should show a list of providers', function () {
    browser.get('/providers');

    expect(
      browser.getLocationAbsUrl()
    ).toMatch(/\/providers$/);

    providersList = element.all(by.repeater('item in list'));
    expect(providersList.count()).toEqual(7);
    expect(providersList.first().getText()).toMatch('aws-us-east-1 Amazon Web Services - US East 1 region Edit\nDelete');
  });

  it('should link to the right pages', function () {
    providersList = element.all(by.repeater('item in list'));
    var edithref = providersList.first().element(by.css('.edit-btn')).getAttribute('href');
    expect(edithref).toMatch(/\/providers\/edit\/aws-us-east-1$/);
  });

  it('should logout', function () {
    helper.logout();
  });

});

<commit_msg>fix provider tests for changes in loadedd defaults<commit_after>/**
 * E2E tests for /providers.
 */
var helper = require('../../protractor-help');

'use strict';

describe('providers test', function () {
  var ptor = protractor.getInstance();
  var formfields;
  var providersList;

  it('should log in', function () {
    helper.loginAsAdmin();
  });

  it('should show the correct fields for provider type', function() {
    browser.get('/providers/create');

    expect(
      browser.getLocationAbsUrl()
    ).toMatch(/\/providers\/create$/);

    browser.waitForAngular();

    element(by.cssContainingText('option', 'google')).click();
    formfields = element.all(by.repeater('(name,fieldData) in config.fields'));
    expect(formfields.count()).toEqual(7);

    element(by.cssContainingText('option', 'aws')).click();
    formfields = element.all(by.repeater('(name,fieldData) in config.fields'));
    expect(formfields.count()).toEqual(15);
  });

  it('should fill in default values', function () {
    element(by.cssContainingText('option', 'google')).click();
    formfields = element.all(by.repeater('(name,fieldData) in config.fields'));
    var size = formfields.get(2).element(by.css('input')).getAttribute('value');
    expect(size).toEqual('10');
    var zone = formfields.get(6).element(by.css('select')).getAttribute('value');
    expect(zone).toEqual('5');
  });

  it('should create, store and delete a provider', function () {
    // Create
    element(by.name('name')).sendKeys('Testprovider');
    element(by.css('#inputProviderDescription')).sendKeys('Test description');
    element(by.cssContainingText('option', 'google')).click();
    formfields = element.all(by.repeater('(name,fieldData) in config.fields'));
    formfields.first().element(by.css('input')).sendKeys('Test resource');
    formfields.get(5).element(by.css('input')).sendKeys('Test username');
    formfields.get(1).element(by.css('input')).sendKeys('Test email');
    formfields.get(3).element(by.css('input')).sendKeys('Test project id');
    formfields.get(4).element(by.css('input')).sendKeys('Test keyname');
    element(by.partialButtonText('Create')).click();
    expect(
      browser.getLocationAbsUrl()
    ).toMatch(/\/providers$/);

    // List
    providersList = element.all(by.repeater('item in list'));
    expect(providersList.count()).toEqual(1);
    var providerText = providersList.first().getText();
    expect(providerText).toMatch('Testprovider Test description Edit\nDelete');
    providersList.first().element(by.css('.edit-btn')).click();

    // Edit
    expect(
      browser.getLocationAbsUrl()
    ).toMatch(/\/providers\/edit\/Testprovider$/);
    expect(element(by.css('#inputProviderName')).getAttribute('value')).toBe('Testprovider');
    expect(
      element(by.css('#inputProviderDescription')).getAttribute('value')).toBe('Test description');
    expect(element(by.css('#inputProviderType')).getAttribute('value')).toBe('1');
    formfields = element.all(by.repeater('(name,fieldData) in config.fields'));
    var size = formfields.get(2).element(by.css('input')).getAttribute('value');
    expect(size).toEqual('10');
    var zone = formfields.get(6).element(by.css('select')).getAttribute('value');
    expect(zone).toEqual('5');

    // Delete
    browser.get('/providers');
    providersList = element.all(by.repeater('item in list'));
    providersList.first().element(by.css('.delete-btn')).click();
    ptor.switchTo().alert().accept();
    providersList = element.all(by.repeater('item in list'));
    expect(providersList.count()).toEqual(0);
  });

  it('should show a list of providers', function () {
    browser.get('/providers');

    expect(
      browser.getLocationAbsUrl()
    ).toMatch(/\/providers$/);

    providersList = element.all(by.repeater('item in list'));
    expect(providersList.count()).toEqual(0);
  });

  it('should logout', function () {
    helper.logout();
  });

});

<|endoftext|>


<commit_before>var Http = require('http'),
  _ = require('../underscore_ext');
  Request = require('./request');

/**
 * Class responsible for tunnelling requests
 */
class Server {
  constructor(config) {
    _.bindAll(this, '_handleRequest');

    this._configure.call(this, config);
  }

  /**
   * Listen to port
   */
  listen() {
    this._createServer();
    this.server.listen(this.config.port);
  }

  /**
   * Stops listening
   */
  stop() {
    this.server.close();
  }

  /**
   * Configure redirecter
   */
  _configure(config) {
    this.config = _.extend({
      port:3330,
      before:[]
    }, config);

    this.before = _.asArray(config.before);
  }

  /**
   * Initiate server
   */
  _createServer() {
    let redirecter = this;

    redirecter.server = Http.createServer(this._handleRequest);
  }

  /**
   * Handles each request piping it to the proxied server
   */
  _handleRequest(request, response){
    if (this._applyBefore(request, response)) {
      this._pipeRequest(request, response);
    }
  }

  _pipeRequest(request, response) {
    request.pipe(this._proxyRequest(request, response));
  }

  _proxyRequest(request, response) {
    return Request(this.config.proxy, request, response).startRequest();
  }

  /**
   * Run before scripts on request
   */
  _applyBefore(request, response){
    let redirecter = this;

    for (var i = 0; i < redirecter.before.length; i++){
      if (! redirecter.before[i].call(redirecter, request, response))
        return false;
    }
    return true;
  }
}

module.exports = function(config){
  return new Server(config);
};

module.exports.fn = Server.prototype;
<commit_msg>Require request properly<commit_after>var Http = require('http'),
  _ = require('../underscore_ext'),
  Request = require('./request');

/**
 * Class responsible for tunnelling requests
 */
class Server {
  constructor(config) {
    _.bindAll(this, '_handleRequest');

    this._configure.call(this, config);
  }

  /**
   * Listen to port
   */
  listen() {
    this._createServer();
    this.server.listen(this.config.port);
  }

  /**
   * Stops listening
   */
  stop() {
    this.server.close();
  }

  /**
   * Configure redirecter
   */
  _configure(config) {
    this.config = _.extend({
      port:3330,
      before:[]
    }, config);

    this.before = _.asArray(config.before);
  }

  /**
   * Initiate server
   */
  _createServer() {
    let redirecter = this;

    redirecter.server = Http.createServer(this._handleRequest);
  }

  /**
   * Handles each request piping it to the proxied server
   */
  _handleRequest(request, response){
    if (this._applyBefore(request, response)) {
      this._pipeRequest(request, response);
    }
  }

  _pipeRequest(request, response) {
    request.pipe(this._proxyRequest(request, response));
  }

  _proxyRequest(request, response) {
    return Request(this.config.proxy, request, response).startRequest();
  }

  /**
   * Run before scripts on request
   */
  _applyBefore(request, response){
    let redirecter = this;

    for (var i = 0; i < redirecter.before.length; i++){
      if (! redirecter.before[i].call(redirecter, request, response))
        return false;
    }
    return true;
  }
}

module.exports = function(config){
  return new Server(config);
};

module.exports.fn = Server.prototype;
<|endoftext|>


<commit_before>var jspm = require('jspm');
var builder = new jspm.Builder();

builder.config({
  separateCSS: false,
  buildCSS: true
});

// or builder.buildStatic
builder.bundle('./src/client/index.js', './dist/client/index.js', {
  minify: false,
  sourceMaps: true
}).then(function () {
  console.log('Build complete');
}).catch(function (err) {
  console.log('Build error: ', err);
});<commit_msg>Remove redundant config<commit_after>var jspm = require('jspm');
var builder = new jspm.Builder();

// or builder.buildStatic
builder.bundle('./src/client/index.js', './dist/client/index.js', {
  minify: false,
  sourceMaps: true
}).then(function () {
  console.log('Build complete');
}).catch(function (err) {
  console.log('Build error: ', err);
});<|endoftext|>


<commit_before>#!/usr/bin/env node

const path = require('path');
const fs = require('fs');

const credentialsPath = path.join(__dirname, '..', 'credentials.json');

if(!fs.existsSync(credentialsPath) || (process.argv[2] === '--config')) {
	require('../lib/config.js')()
	.then(() => sendMessage());
} else {
	sendMessage();
}

function sendMessage() {
	const api = require('../lib/freesmsapi.js');
	const credentials = require('../credentials.json');

	const argv = require('yargs')
		.option('f', {
			alias: 'file',
			describe: 'File(s) to be add to the SMS',
			default: [],
			type: 'array',
			nargs: 1
		})
		.option('encoding', {
			describe: 'File(s) encoding',
			default: 'utf8',
			type: 'string',
			nargs: 1
		})
		.option('s', {
			alias: 'split',
			describe: 'Split each string arguments in separate messages',
			default: false,
			type: 'boolean'
		})
		.epilogue('For more information, find more information at https://github.com/Scotow/freemobile-sms.')
		.argv
	;

	const messages = argv.split ? argv._ : [argv._.join(' ')];
	argv.file.forEach((file) => {
		try {
			messages.push(fs.readFileSync(file, argv.encoding));
		} catch(error) {
			console.error(`${file}: No such file.`);
			process.exit(1);
		}
	});

	// console.log(messages.length);
	// process.exit(0);

	api.send(messages, credentials)
	.then(() => {
		process.exit(0);
	})
	.catch((error) => {
		if(typeof error === 'number') {
			console.error(`The FreeMobile API return the following HTTP status code: ${error}.`);
			process.exit(error);
		} else {
			console.error(error.message);
			process.exit(1);
		}
	});
}
<commit_msg>Remove debug comments on main command.<commit_after>#!/usr/bin/env node

const path = require('path');
const fs = require('fs');

const credentialsPath = path.join(__dirname, '..', 'credentials.json');

if(!fs.existsSync(credentialsPath) || (process.argv[2] === '--config')) {
	require('../lib/config.js')()
	.then(() => sendMessage());
} else {
	sendMessage();
}

function sendMessage() {
	const api = require('../lib/freesmsapi.js');
	const credentials = require('../credentials.json');

	const argv = require('yargs')
		.option('f', {
			alias: 'file',
			describe: 'File(s) to be add to the SMS',
			default: [],
			type: 'array',
			nargs: 1
		})
		.option('encoding', {
			describe: 'File(s) encoding',
			default: 'utf8',
			type: 'string',
			nargs: 1
		})
		.option('s', {
			alias: 'split',
			describe: 'Split each string arguments in separate messages',
			default: false,
			type: 'boolean'
		})
		.epilogue('For more information, find more information at https://github.com/Scotow/freemobile-sms.')
		.argv
	;

	const messages = argv.split ? argv._ : [argv._.join(' ')];
	argv.file.forEach((file) => {
		try {
			messages.push(fs.readFileSync(file, argv.encoding));
		} catch(error) {
			console.error(`${file}: No such file.`);
			process.exit(1);
		}
	});

	api.send(messages, credentials)
	.then(() => {
		process.exit(0);
	})
	.catch((error) => {
		if(typeof error === 'number') {
			console.error(`The FreeMobile API return the following HTTP status code: ${error}.`);
			process.exit(error);
		} else {
			console.error(error.message);
			process.exit(1);
		}
	});
}
<|endoftext|>


<commit_before>export default {
  'essentials': [
    'passport',
    'ticket',
    'wallet',
    'cash',
    'creditcards',
    'phone',
    'charger',
    'adapter',
    'laptop',
    'umbrella'
  ],
  'toiletries': [
    'toothbrush',
    'toothpaste',
    'deodorant',
    'medications',
    'sunscreen',
    'beardstuff'
  ],
  'clothes': [
    'underwear',
    'socks',
    't-shirt',
    'sleepwear',
    'jeans',
    'sweater',
    'jacket'
  ],
  'extras': [
    'readings',
    'movies/series',
    'keyboard',
    'headphones',
    'speakers',
    'tablet',
    'earplugs',
    'watch',
    'paper-tissues'
  ]
}
<commit_msg>+ sunglasses<commit_after>export default {
  'essentials': [
    'passport',
    'ticket',
    'wallet',
    'cash',
    'creditcards',
    'phone',
    'charger',
    'adapter',
    'laptop',
    'umbrella'
  ],
  'toiletries': [
    'toothbrush',
    'toothpaste',
    'deodorant',
    'medications',
    'sunscreen',
    'beardstuff'
  ],
  'clothes': [
    'underwear',
    'socks',
    't-shirt',
    'sleepwear',
    'jeans',
    'sweater',
    'jacket'
  ],
  'extras': [
    'readings',
    'movies/series',
    'keyboard',
    'headphones',
    'speakers',
    'tablet',
    'earplugs',
    'watch',
    'paper-tissues',
    'sunglasses'
  ]
}
<|endoftext|>


<commit_before>'use strict';

// As of v14, Node.js does not exit when there is an unhandled Promise rejection. Convert an
// unhandled rejection into an uncaught exception, which does cause Node.js to exit.
process.on('unhandledRejection', (err) => { throw err; });

const fs = require('fs');
const childProcess = require('child_process');
const path = require('path');
const semver = require('semver');

/*

Usage

node src/bin/release.js patch

*/
const usage =
    'node src/bin/release.js [patch/minor/major] -- example: "node src/bin/release.js patch"';

const release = process.argv[2];

if (!release) {
  console.log(usage);
  throw new Error('No release type included');
}

const cwd = path.join(fs.realpathSync(__dirname), '../../');
process.chdir(cwd);

// Run command without capturing stdout.
const run = (cmd, opts = {}) => childProcess.execSync(cmd, {stdio: 'inherit', ...opts});

const readJson = (filename) => JSON.parse(fs.readFileSync(filename, {encoding: 'utf8', flag: 'r'}));
const writeJson = (filename, obj) => {
  let json = JSON.stringify(obj, null, 2);
  if (json !== '' && !json.endsWith('\n')) json += '\n';
  fs.writeFileSync(filename, json);
};

const changelog = fs.readFileSync('CHANGELOG.md', {encoding: 'utf8', flag: 'r'});
const pkg = readJson('./src/package.json');
const currentVersion = pkg.version;

const newVersion = semver.inc(currentVersion, release);
if (!newVersion) {
  console.log(usage);
  throw new Error('Unable to generate new version from input');
}

const changelogIncludesVersion = changelog.indexOf(newVersion) !== -1;

if (!changelogIncludesVersion) {
  throw new Error(`No changelog record for ${newVersion}, please create changelog record`);
}

console.log('Okay looks good, lets create the package.json and package-lock.json');

pkg.version = newVersion;

writeJson('./src/package.json', pkg);

// run npm version `release` where release is patch, minor or major
run('npm install --package-lock-only', {cwd: 'src/'});
// run npm install --package-lock-only <-- required???

// Many users will be using the latest LTS version of npm, and the latest LTS version of npm uses
// lockfileVersion 1. Enforce v1 so that users don't see a (benign) compatibility warning.
if (readJson('./src/package-lock.json').lockfileVersion !== 1) {
  throw new Error('Please regenerate package-lock.json with npm v6.x.');
}

run('git add src/package.json');
run('git add src/package-lock.json');
run('git commit -m "bump version"');

run('make docs');
run('cd .. && git clone git@github.com:ether/ether.github.com.git');
run(`cp -R out/doc/ ../ether.github.com/doc/v${newVersion}`);

console.log('Once merged into master please run the following commands');
console.log(`git checkout master && git tag -a ${newVersion} -m ${newVersion} && git push origin master`);
console.log(`cd ../ether.github.com && git add . && git commit -m '${newVersion} docs' && git push`);
console.log('bin/buildForWindows.sh');
console.log('Visit https://github.com/ether/etherpad-lite/releases/new and create a new release ' +
            `with 'master' as the target and the version is ${newVersion}.  Include the windows ` +
            'zip as an asset');
console.log(`Once the new docs are uploaded then modify the download
   links (replace ${currentVersion} with ${newVersion} on etherpad.org and then pull master onto develop`);
console.log('Finally go public with an announcement via our comms channels :)');
<commit_msg>release: Assume `../ether.github.com` exists<commit_after>'use strict';

// As of v14, Node.js does not exit when there is an unhandled Promise rejection. Convert an
// unhandled rejection into an uncaught exception, which does cause Node.js to exit.
process.on('unhandledRejection', (err) => { throw err; });

const fs = require('fs');
const childProcess = require('child_process');
const path = require('path');
const semver = require('semver');

/*

Usage

node src/bin/release.js patch

*/
const usage =
    'node src/bin/release.js [patch/minor/major] -- example: "node src/bin/release.js patch"';

const release = process.argv[2];

if (!release) {
  console.log(usage);
  throw new Error('No release type included');
}

const cwd = path.join(fs.realpathSync(__dirname), '../../');
process.chdir(cwd);

// Run command without capturing stdout.
const run = (cmd, opts = {}) => childProcess.execSync(cmd, {stdio: 'inherit', ...opts});

const readJson = (filename) => JSON.parse(fs.readFileSync(filename, {encoding: 'utf8', flag: 'r'}));
const writeJson = (filename, obj) => {
  let json = JSON.stringify(obj, null, 2);
  if (json !== '' && !json.endsWith('\n')) json += '\n';
  fs.writeFileSync(filename, json);
};

const changelog = fs.readFileSync('CHANGELOG.md', {encoding: 'utf8', flag: 'r'});
const pkg = readJson('./src/package.json');
const currentVersion = pkg.version;

const newVersion = semver.inc(currentVersion, release);
if (!newVersion) {
  console.log(usage);
  throw new Error('Unable to generate new version from input');
}

const changelogIncludesVersion = changelog.indexOf(newVersion) !== -1;

if (!changelogIncludesVersion) {
  throw new Error(`No changelog record for ${newVersion}, please create changelog record`);
}

console.log('Okay looks good, lets create the package.json and package-lock.json');

pkg.version = newVersion;

writeJson('./src/package.json', pkg);

// run npm version `release` where release is patch, minor or major
run('npm install --package-lock-only', {cwd: 'src/'});
// run npm install --package-lock-only <-- required???

// Many users will be using the latest LTS version of npm, and the latest LTS version of npm uses
// lockfileVersion 1. Enforce v1 so that users don't see a (benign) compatibility warning.
if (readJson('./src/package-lock.json').lockfileVersion !== 1) {
  throw new Error('Please regenerate package-lock.json with npm v6.x.');
}

run('git add src/package.json');
run('git add src/package-lock.json');
run('git commit -m "bump version"');

run('make docs');
run(`cp -R out/doc/ ../ether.github.com/doc/v${newVersion}`);

console.log('Once merged into master please run the following commands');
console.log(`git checkout master && git tag -a ${newVersion} -m ${newVersion} && git push origin master`);
console.log(`cd ../ether.github.com && git add . && git commit -m '${newVersion} docs' && git push`);
console.log('bin/buildForWindows.sh');
console.log('Visit https://github.com/ether/etherpad-lite/releases/new and create a new release ' +
            `with 'master' as the target and the version is ${newVersion}.  Include the windows ` +
            'zip as an asset');
console.log(`Once the new docs are uploaded then modify the download
   links (replace ${currentVersion} with ${newVersion} on etherpad.org and then pull master onto develop`);
console.log('Finally go public with an announcement via our comms channels :)');
<|endoftext|>


<commit_before>'use strict';

jasmine.getFixtures().fixturesPath = 'base/test/fixtures';

var moment = require('moment');
var createWidget = require('./utils/createWidget');
var mockAjax = require('./utils/mockAjax');

describe('Advanced configuration', function() {

  beforeEach(function(){
    loadFixtures('main.html');
    jasmine.Ajax.install();
    mockAjax.all();
  });

  afterEach(function() {
    jasmine.Ajax.uninstall();
  });

  it('should go to the first upcoming event when goToFirstEvent is set', function(done) {

    mockAjax.findTimeWithDateInFuture();

    var config = {
      goToFirstEvent: true
    }
    var widget = createWidget(config);

    setTimeout(function() {

      var future = moment().add(1, 'month').startOf('day');

      var calendarDate = widget.fullCalendar('getDate');
      expect(calendarDate.format('YYYY-MM-DD')).toBe(future.format('YYYY-MM-DD'));

      setTimeout(function() {

        var scrollable = $('.bookingjs-calendar').find('.fc-scroller');
        var scrollTop = scrollable.scrollTop();
        expect(scrollTop).not.toBe(321);

        done();

      }, 300);
    }, 100);

  });

  it('should go to current date when goToFirstEvent is disabled', function(done) {

    mockAjax.findTimeWithDateInFuture();

    var config = {
      goToFirstEvent: false
    }
    var widget = createWidget(config);

    setTimeout(function() {

      var today = moment();

      var calendarDate = widget.fullCalendar('getDate');
      expect(calendarDate.format('YYYY-MM-DD')).toBe(today.format('YYYY-MM-DD'));

      setTimeout(function() {

        var scrollable = $('.bookingjs-calendar').find('.fc-scroller');
        var scrollTop = scrollable.scrollTop();
        expect(scrollTop).toBe(321);

        done();

      }, 300);
    }, 100);

  });

  it('should be able to load even though no timeslots are available', function(done) {

    mockAjax.findTimeWithNoTimeslots();

    createWidget();

    setTimeout(function() {

      var availableTimeslots = $('.fc-time-grid-event')
      expect(availableTimeslots.length).toBe(0)

      done();

    }, 300);

  });

  it('should be able override config settings fetched remotely, but before render', function(done) {

    mockAjax.all();

    function updateConfig () {
      var widgetConfig = widget.getConfig()
      expect(widgetConfig.name).toBe('Marty McFly')
      widgetConfig.name = 'Marty McFly 2'
      widget.setConfig(widgetConfig)
    }

    var widget = new TimekitBooking();
    var config = {
      widgetId: '12345',
      callbacks: {
        renderStarted: updateConfig
      }
    };

    spyOn(config.callbacks, 'renderStarted').and.callThrough();

    widget.init(config);

    setTimeout(function() {

      expect(config.callbacks.renderStarted).toHaveBeenCalled();

      var request = jasmine.Ajax.requests.first();
      expect(request.url).toBe('https://api.timekit.io/v2/widgets/embed/12345');

      var widgetConfig = widget.getConfig()

      expect(widgetConfig.name).toBe('Marty McFly 2')

      done();

    }, 100)

  });

  it('should be able to set which dynamic includes that CreateBooking request returns in response', function(done) {

    mockAjax.createBookingWithCustomIncludes();

    var config = {
      createBookingResponseInclude: ['provider_event', 'attributes', 'event', 'user']
    }
    createWidget(config);

    setTimeout(function() {

      interact.clickEvent();

      setTimeout(function() {

        interact.fillSubmit();

        setTimeout(function() {

          var request = jasmine.Ajax.requests.mostRecent();
          var requestData = JSON.parse(request.params);

          expect(request.url).toBe('https://api.timekit.io/v2/bookings?include=provider_event,attributes,event,user');
          done();

        }, 200);
      }, 500);
    }, 500);

  });

});
<commit_msg>fix test<commit_after>'use strict';

jasmine.getFixtures().fixturesPath = 'base/test/fixtures';

var moment = require('moment');
var createWidget = require('./utils/createWidget');
var mockAjax = require('./utils/mockAjax');
var interact = require('./utils/commonInteractions');

describe('Advanced configuration', function() {

  beforeEach(function(){
    loadFixtures('main.html');
    jasmine.Ajax.install();
    mockAjax.all();
  });

  afterEach(function() {
    jasmine.Ajax.uninstall();
  });

  it('should go to the first upcoming event when goToFirstEvent is set', function(done) {

    mockAjax.findTimeWithDateInFuture();

    var config = {
      goToFirstEvent: true
    }
    var widget = createWidget(config);

    setTimeout(function() {

      var future = moment().add(1, 'month').startOf('day');

      var calendarDate = widget.fullCalendar('getDate');
      expect(calendarDate.format('YYYY-MM-DD')).toBe(future.format('YYYY-MM-DD'));

      setTimeout(function() {

        var scrollable = $('.bookingjs-calendar').find('.fc-scroller');
        var scrollTop = scrollable.scrollTop();
        expect(scrollTop).not.toBe(321);

        done();

      }, 300);
    }, 100);

  });

  it('should go to current date when goToFirstEvent is disabled', function(done) {

    mockAjax.findTimeWithDateInFuture();

    var config = {
      goToFirstEvent: false
    }
    var widget = createWidget(config);

    setTimeout(function() {

      var today = moment();

      var calendarDate = widget.fullCalendar('getDate');
      expect(calendarDate.format('YYYY-MM-DD')).toBe(today.format('YYYY-MM-DD'));

      setTimeout(function() {

        var scrollable = $('.bookingjs-calendar').find('.fc-scroller');
        var scrollTop = scrollable.scrollTop();
        expect(scrollTop).toBe(321);

        done();

      }, 300);
    }, 100);

  });

  it('should be able to load even though no timeslots are available', function(done) {

    mockAjax.findTimeWithNoTimeslots();

    createWidget();

    setTimeout(function() {

      var availableTimeslots = $('.fc-time-grid-event')
      expect(availableTimeslots.length).toBe(0)

      done();

    }, 300);

  });

  it('should be able override config settings fetched remotely, but before render', function(done) {

    mockAjax.all();

    function updateConfig () {
      var widgetConfig = widget.getConfig()
      expect(widgetConfig.name).toBe('Marty McFly')
      widgetConfig.name = 'Marty McFly 2'
      widget.setConfig(widgetConfig)
    }

    var widget = new TimekitBooking();
    var config = {
      widgetId: '12345',
      callbacks: {
        renderStarted: updateConfig
      }
    };

    spyOn(config.callbacks, 'renderStarted').and.callThrough();

    widget.init(config);

    setTimeout(function() {

      expect(config.callbacks.renderStarted).toHaveBeenCalled();

      var request = jasmine.Ajax.requests.first();
      expect(request.url).toBe('https://api.timekit.io/v2/widgets/embed/12345');

      var widgetConfig = widget.getConfig()

      expect(widgetConfig.name).toBe('Marty McFly 2')

      done();

    }, 100)

  });

  it('should be able to set which dynamic includes that CreateBooking request returns in response', function(done) {

    mockAjax.createBookingWithCustomIncludes();

    var config = {
      createBookingResponseInclude: ['provider_event', 'attributes', 'event', 'user']
    }
    createWidget(config);

    setTimeout(function() {

      interact.clickEvent();

      setTimeout(function() {

        interact.fillSubmit();

        setTimeout(function() {

          var request = jasmine.Ajax.requests.mostRecent();
          var requestData = JSON.parse(request.params);

          expect(request.url).toBe('https://api.timekit.io/v2/bookings?include=provider_event,attributes,event,user');
          done();

        }, 200);
      }, 500);
    }, 500);

  });

});
<|endoftext|>


<commit_before>'use strict';

/**
 * @license
 * Copyright 2015 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

goog.provide('tachyfont.GoogleBackendService');

goog.require('goog.Promise');
goog.require('tachyfont.BackendService');
goog.require('tachyfont.FontInfo');
goog.require('tachyfont.GlyphBundleResponse');

goog.scope(function() {

/**
 * Handles interacting with the backend server.
 *
 * @param {string} baseUrl of the backend server.
 * @constructor
 * @extends {tachyfont.BackendService}
 */
tachyfont.GoogleBackendService = function(baseUrl) {
  tachyfont.GoogleBackendService.base(this, 'constructor', baseUrl);
};
goog.inherits(tachyfont.GoogleBackendService, tachyfont.BackendService);
var GoogleBackendService = tachyfont.GoogleBackendService;

/** @type {string} */
GoogleBackendService.GLYPHS_REQUEST_PREFIX = 'g';

/** @type {string} */
GoogleBackendService.GLYPHS_REQUEST_SUFFIX = 'glyphs';

/** @type {string} */
GoogleBackendService.FRAMEWORK_REQUEST_PREFIX = 't';

/** @type {string} */
GoogleBackendService.FRAMEWORK_REQUEST_SUFFIX = 'framework';

/** @override */
GoogleBackendService.prototype.requestCodepoints = function(
    fontInfo, codes) {
  var self = this;
  return this.requestUrl(this.getUrl_(fontInfo,
      GoogleBackendService.GLYPHS_REQUEST_PREFIX,
      GoogleBackendService.GLYPHS_REQUEST_SUFFIX),
      'POST',
      'glyphs=' + encodeURIComponent(this.compressedGlyphsList_(codes)),
      {'Content-Type': 'application/x-www-form-urlencoded'})
      .then(function(glyphData) {
        return self.parseHeader_(glyphData);
      });
};

/**
 * Parses the header of a codepoint response and returns info on it:
 * @param {ArrayBuffer} glyphData from a code point request.
 * @return Header info, {count: ..., flags: ..., version: ...,
 *         fontSignature: ...}
 * @private
 */
GoogleBackendService.prototype.parseHeader_ = function(glyphData) {
  var dataView = new DataView(glyphData);
  var offset = 0;
  var magicNumber = '';
  for (var i = 0; i < 4; i++) {
    magicNumber += String.fromCharCode(dataView.getUint8(offset++));
  }

  if (magicNumber == 'BSAC') {
    var version = dataView.getUint8(offset++) + '.' +
        dataView.getUint8(offset++);
    offset += 2; // Skip reserved section.
    var signature = '';
    for (var i = 0; i < 20; i++) {
      signature += dataView.getUint8(offset++).toString(16);
    }
    var count = dataView.getUint16(offset);
    offset += 2;
    var flags = dataView.getUint16(offset);
    offset += 2;
    return new tachyfont.GlyphBundleResponse(
        version, signature, count, flags, offset, glyphData);
  } else {
    throw new Error('Invalid code point bundle header magic number: ' +
        magicNumber);
  }
};

/** @override */
GoogleBackendService.prototype.requestFontBase = function(fontInfo) {
  return this.requestUrl(this.getUrl_(fontInfo,
      GoogleBackendService.FRAMEWORK_REQUEST_PREFIX,
      GoogleBackendService.FRAMEWORK_REQUEST_SUFFIX),
      'GET', null, {});
};

/** @override */
GoogleBackendService.prototype.log = function(message) {
  // Not implemented yet.
  return new goog.Promise(function(resolve, reject) {
    resolve(new ArrayBuffer(0));
  });
};

/**
 * @private
 * @param {!tachyfont.FontInfo} fontInfo containing info on the font; ie:
 *     fontkit, familyPath = the font's directory; ie. "notosansjapanese", and
 *     name = Unique name for this particular instance of the font
 *     (style/weight) ie. "notosans100".
 * @param {string} prefix Action prefix in the URL.
 * @param {string} suffix Action suffset in the URL.
 * @return {string} URL for the specified font action.
 */
GoogleBackendService.prototype.getUrl_ = function(fontInfo, prefix, suffix) {
  var familyPath = fontInfo.getfamilyPath();
  if (!familyPath) {
    // Using familyPath is preferred over familyName.
    familyPath = fontInfo.getFamilyName().replace(/ /g, '').toLowerCase();
  }
  return this.baseUrl + '/' + prefix + '/' + familyPath + '/' +
      fontInfo.getVersion() + '/' + fontInfo.getFontKit() + '.' + suffix;
};

/**
 * @private
 * @param {Array.<number>} codes list of code points to compress.
 * @return {string} compressed code point list.
 */
GoogleBackendService.prototype.compressedGlyphsList_ = function(codes) {
  var result = '';
  for (var i = 0; i < codes.length; i++) {
    var cp = codes[i];
    if (cp != 45) { // Dash
      result = result + String.fromCharCode(cp);
    } else {
      // Dash is a special character in the compressed glyph list and must
      // be at the start of the string.
      result = '-' + result;
    }
  }
  return result;
};

});  // goog.scope
<commit_msg>fix surrogate support in compressedGlyphsList_<commit_after>'use strict';

/**
 * @license
 * Copyright 2015 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

goog.provide('tachyfont.GoogleBackendService');

goog.require('goog.Promise');
goog.require('tachyfont.BackendService');
goog.require('tachyfont.FontInfo');
goog.require('tachyfont.GlyphBundleResponse');

goog.scope(function() {

/**
 * Handles interacting with the backend server.
 *
 * @param {string} baseUrl of the backend server.
 * @constructor
 * @extends {tachyfont.BackendService}
 */
tachyfont.GoogleBackendService = function(baseUrl) {
  tachyfont.GoogleBackendService.base(this, 'constructor', baseUrl);
};
goog.inherits(tachyfont.GoogleBackendService, tachyfont.BackendService);
var GoogleBackendService = tachyfont.GoogleBackendService;

/** @type {string} */
GoogleBackendService.GLYPHS_REQUEST_PREFIX = 'g';

/** @type {string} */
GoogleBackendService.GLYPHS_REQUEST_SUFFIX = 'glyphs';

/** @type {string} */
GoogleBackendService.FRAMEWORK_REQUEST_PREFIX = 't';

/** @type {string} */
GoogleBackendService.FRAMEWORK_REQUEST_SUFFIX = 'framework';

/** @override */
GoogleBackendService.prototype.requestCodepoints = function(
    fontInfo, codes) {
  var self = this;
  return this.requestUrl(this.getUrl_(fontInfo,
      GoogleBackendService.GLYPHS_REQUEST_PREFIX,
      GoogleBackendService.GLYPHS_REQUEST_SUFFIX),
      'POST',
      'glyphs=' + encodeURIComponent(this.compressedGlyphsList_(codes)),
      {'Content-Type': 'application/x-www-form-urlencoded'})
      .then(function(glyphData) {
        return self.parseHeader_(glyphData);
      });
};

/**
 * Parses the header of a codepoint response and returns info on it:
 * @param {ArrayBuffer} glyphData from a code point request.
 * @return Header info, {count: ..., flags: ..., version: ...,
 *         fontSignature: ...}
 * @private
 */
GoogleBackendService.prototype.parseHeader_ = function(glyphData) {
  var dataView = new DataView(glyphData);
  var offset = 0;
  var magicNumber = '';
  for (var i = 0; i < 4; i++) {
    magicNumber += String.fromCharCode(dataView.getUint8(offset++));
  }

  if (magicNumber == 'BSAC') {
    var version = dataView.getUint8(offset++) + '.' +
        dataView.getUint8(offset++);
    offset += 2; // Skip reserved section.
    var signature = '';
    for (var i = 0; i < 20; i++) {
      signature += dataView.getUint8(offset++).toString(16);
    }
    var count = dataView.getUint16(offset);
    offset += 2;
    var flags = dataView.getUint16(offset);
    offset += 2;
    return new tachyfont.GlyphBundleResponse(
        version, signature, count, flags, offset, glyphData);
  } else {
    throw new Error('Invalid code point bundle header magic number: ' +
        magicNumber);
  }
};

/** @override */
GoogleBackendService.prototype.requestFontBase = function(fontInfo) {
  return this.requestUrl(this.getUrl_(fontInfo,
      GoogleBackendService.FRAMEWORK_REQUEST_PREFIX,
      GoogleBackendService.FRAMEWORK_REQUEST_SUFFIX),
      'GET', null, {});
};

/** @override */
GoogleBackendService.prototype.log = function(message) {
  // Not implemented yet.
  return new goog.Promise(function(resolve, reject) {
    resolve(new ArrayBuffer(0));
  });
};

/**
 * @private
 * @param {!tachyfont.FontInfo} fontInfo containing info on the font; ie:
 *     fontkit, familyPath = the font's directory; ie. "notosansjapanese", and
 *     name = Unique name for this particular instance of the font
 *     (style/weight) ie. "notosans100".
 * @param {string} prefix Action prefix in the URL.
 * @param {string} suffix Action suffset in the URL.
 * @return {string} URL for the specified font action.
 */
GoogleBackendService.prototype.getUrl_ = function(fontInfo, prefix, suffix) {
  var familyPath = fontInfo.getfamilyPath();
  if (!familyPath) {
    // Using familyPath is preferred over familyName.
    familyPath = fontInfo.getFamilyName().replace(/ /g, '').toLowerCase();
  }
  return this.baseUrl + '/' + prefix + '/' + familyPath + '/' +
      fontInfo.getVersion() + '/' + fontInfo.getFontKit() + '.' + suffix;
};

/**
 * @private
 * @param {Array.<number>} codes list of code points to compress.
 * @return {string} compressed code point list.
 */
GoogleBackendService.prototype.compressedGlyphsList_ = function(codes) {
  var result = '';
  for (var i = 0; i < codes.length; i++) {
    var cp = codes[i];
    if (cp != 45) { // Dash
      result = result + String.fromCodePoint(cp);
    } else {
      // Dash is a special character in the compressed glyph list and must
      // be at the start of the string.
      result = '-' + result;
    }
  }
  return result;
};

});  // goog.scope
<|endoftext|>