<commit_before>// require ../support/jquery
// require esphinx_ui
// require esphinx/support/ajax
// require esphinx/support/function
// require esphinx/support/array
// require esphinx/observer

"use strict";

var
    jQuery,
    esPhinx,
    Singleton,
    Ajax,
    Constructor;

(function ($module) {

    $module.extend({

        windows: {

            modal: {

                // functions are objects in js
                new: function (contentSource, options) {

                    var
                        ConstructorReference = $module.windows.modal.new,
                        self = this,

                        $ = esPhinx,
                        ajax = Ajax,
                        body = $("body"),

                        modal,
                        mask,
                        main,
                        container,
                        btnClose,
                        btnHide,
                        headers,
                        params,
                        asynchronousAnswer,
                        imgControl,

                        maskTransitionDuration = function (mask) {
                            return parseFloat(mask
                                .css("transition-duration")) * 1000;
                        },

                        restartTransition = function (mask) {
                            mask.css("transition", "opacity 0s");
                        },

                        resolveParams = function () {
                            options = options || {};

                            if (typeof options.windowController !== "boolean") {
                                options.windowController = true;
                            }

                            if (typeof options.remote !== "boolean") {
                                options.remote = true;
                            }
                        },

                        resolveHeaderActions = function (main, options) {
                            var
                                header,
                                actions;

                            if (options.windowController) {
                                header = $("");
                                actions = $("

").addClass("actions");
                                btnClose = $('')
                                    .addClass("btn-close");
                                btnHide = $('')
                                    .addClass("btn-hide");

                                header.append(actions);
                                actions.append(btnClose);
                                actions.append(btnHide);

                                main
                                    .prepend(header)
                                    .css({
                                        "max-height": $(document).height(),
                                        "max-width": $(document).width()
                                    });

                                bindHeaderEventListeners();
                            }
                        },

                        bindHeaderEventListeners = function () {
                            // $(document).off("keydown").on("keydown", function (e) {
                            //     if (e.keyCode === 27) {
                            //         self.hide();
                            //     }
                            // });

                            btnHide.on("click", function () {
                                self.hide();
                            });

                            btnClose.on("click", function () {
                                self.close();
                            });
                        },

                        observeContent = function () {
                            var
                                imgs,
                                length = 0;

                            main.observe(function (observer) {
                                imgs = main.find("img");
                                if (imgs.any()) {
                                    imgs.each(function (img) {
                                        $(img).on("load", function (e) {
                                            // debugger
                                            length += 1;
                                        });
                                    });

                                    FlowControl.new({
                                        condition: function () {
                                            if (length === imgs.length) {
                                                return true;
                                            }

                                            // when processing is synchronous
                                            if (!options.remote) {
                                                if (options.loading) {
                                                    options.loading(main);
                                                }
                                                self.show();
                                            }

                                            return false;
                                        },
                                        ready: function () {
                                            if (!asynchronousAnswer) {
                                                container.html(contentSource);
                                                main.html(container);
                                            }

                                            length = 0;
                                            resolveHeaderActions(main, options);

                                            if (options.complete) {
                                                self.hide(false);

                                                options.complete.call(self);
                                            }
                                        }
                                    });
                                } else {
                                    resolveHeaderActions(main, options);

                                    if (options.complete) {
                                        options.complete.call(self);
                                    }
                                }

                                // talvez tenha que remanejar o disconnect
                                observer.disconnect();
                            });
                        },

                        create = function (remote) {
                            modal = $("

")
                                .addClass("esphinx ui modal");
                            main = $("")
                                .addClass("basicss hidden");
                            mask = $("

")
                                .addClass("basicss fixed transparent mask");
                            container = $("

").addClass("container");

                            modal
                                .append(mask)
                                .append(main);

                            body.append(modal);

                            observeContent();

                            if (options.remote) {
                                headers = options.header || options.headers
                                || null;
                                params = options.param || options.params
                                || null;
                                ajax.new(contentSource, {
                                    params: params,
                                    headers: headers,
                                    progress: function () {
                                        if (options.loading) {
                                            // callback
                                            options.loading(main);
                                            self.show();
                                            // debugger
                                        }
                                    },
                                    success: function (a) {
                                        if (options.success) {
                                            // callback
                                            options.success(main);
                                        }
                                        asynchronousAnswer = a;

                                        container.html(asynchronousAnswer);

                                        // because here the processing is asynchronous, it's not linear
                                        self.hide(false);
                                        main.html(container);
                                    }
                                });
                            } else {
                                container.html(contentSource);
                                main.html(container);
                            }

                        };

                    // global scope (public)
                    this.close = function () {
                        main.hide();

                        restartTransition(mask);
                        if (options.fadeOut) {
                            mask.css("transition", "opacity " + options.fadeOut);
                        }
                        mask.addClass("transparent");

                        setTimeout(function () {
                            modal.remove();
                        }, maskTransitionDuration(mask));

                        self.deleteSingleton();
                    };

                    this.hide = function (animation = true) {
                        main.hide();

                        restartTransition(mask);

                        if (animation) {
                            if (options.fadeOut) {
                                mask.css("transition", "opacity " + options.fadeOut);
                                setTimeout(function () {
                                    modal.css("z-index", -1);
                                }, maskTransitionDuration(mask));
                            }
                        }

                        mask.addClass("transparent");
                    };

                    this.show = function () {
                        modal.css("z-index", 0);

                        restartTransition(mask);
                        if (options.fadeIn) {
                            mask.css("transition", "opacity " + options.fadeIn);
                        }
                        mask.removeClass("transparent");

                        main.centralizeAt(document);
                        main.show();
                    };

                    if (!(this instanceof ConstructorReference)) {
                        self = Singleton.exists(ConstructorReference, arguments);
                        if (!self) {
                            return ConstructorReference.instance(arguments);
                        } else {
                            self.show();
                        }
                    // that "else" will should to exit for the "show" method can be used by who instanciates it
                    } else {
                        resolveParams();
                        create();
                    }

                    return self;
                }

            }

        }

    });

}(esPhinx.ui));
<commit_msg>adequation<commit_after>// require ../support/jquery
// require esphinx_ui
// require esphinx/support/ajax
// require esphinx/support/function
// require esphinx/support/array
// require esphinx/observer

"use strict";

var
    jQuery,
    esPhinx,
    Singleton,
    Ajax,
    Constructor;

(function ($module) {

    $module.extend({

        windows: {

            modal: {

                // functions are objects in js
                new: function (contentSource, options) {

                    var
                        ConstructorReference = $module.windows.modal.new,
                        self = this,

                        $ = esPhinx,
                        ajax = Ajax,
                        body = $("body"),

                        modal,
                        mask,
                        main,
                        container,
                        btnClose,
                        btnHide,
                        headers,
                        params,
                        asynchronousAnswer,
                        imgControl,

                        maskTransitionDuration = function (mask) {
                            return parseFloat(mask
                                .css("transition-duration")) * 1000;
                        },

                        restartTransition = function (mask) {
                            mask.css("transition", "opacity 0s");
                        },

                        resolveParams = function () {
                            options = options || {};

                            if (typeof options.windowController !== "boolean") {
                                options.windowController = true;
                            }

                            if (typeof options.remote !== "boolean") {
                                options.remote = true;
                            }
                        },

                        resolveHeaderActions = function (main, options) {
                            var
                                header,
                                actions;

                            if (options.windowController) {
                                header = $("");
                                actions = $("

").addClass("actions");
                                btnClose = $('')
                                    .addClass("btn-close");
                                btnHide = $('')
                                    .addClass("btn-hide");

                                header.append(actions);
                                actions.append(btnClose);
                                actions.append(btnHide);

                                main
                                    .prepend(header)
                                    .css({
                                        "max-height": $(document).height(),
                                        "max-width": $(document).width()
                                    });

                                bindHeaderEventListeners();
                            }
                        },

                        bindHeaderEventListeners = function () {
                            // $(document).off("keydown").on("keydown", function (e) {
                            //     if (e.keyCode === 27) {
                            //         self.hide();
                            //     }
                            // });

                            btnHide.on("click", function () {
                                self.hide();
                            });

                            btnClose.on("click", function () {
                                self.close();
                            });
                        },

                        observeContent = function () {
                            var
                                imgs,
                                length = 0;

                            main.observe(function (observer) {
                                imgs = main.find("img");
                                if (imgs.any()) {
                                    imgs.each(function (img) {
                                        $(img).on("load", function (e) {
                                            // debugger
                                            length += 1;
                                        });
                                    });

                                    FlowControl.new({
                                        condition: function () {
                                            if (length === imgs.length) {
                                                return true;
                                            }

                                            // when processing is synchronous
                                            if (!options.remote) {
                                                if (options.loading) {
                                                    options.loading(main);
                                                }
                                                self.show();
                                            }

                                            return false;
                                        },
                                        ready: function () {
                                            if (!asynchronousAnswer) {
                                                container.html(contentSource);
                                                main.html(container);
                                            }

                                            length = 0;
                                            resolveHeaderActions(main, options);

                                            if (options.complete) {
                                                self.hide(false);

                                                options.complete.call(self);
                                            }
                                        }
                                    });
                                } else {
                                    resolveHeaderActions(main, options);

                                    if (options.complete) {
                                        options.complete.call(self);
                                    }
                                }

                                // talvez tenha que remanejar o disconnect
                                observer.disconnect();
                            });
                        },

                        create = function (remote) {
                            modal = $("

")
                                .addClass("esphinx ui modal");
                            main = $("")
                                .addClass("basicss hidden");
                            mask = $("

")
                                .addClass("basicss fixed transparent mask");
                            container = $("

").addClass("container");

                            modal
                                .append(mask)
                                .append(main);

                            body.append(modal);

                            observeContent();

                            if (options.remote) {
                                headers = options.header || options.headers
                                || null;
                                params = options.param || options.params
                                || null;
                                ajax.new(contentSource, {
                                    params: params,
                                    headers: headers,
                                    progress: function () {
                                        if (options.loading) {
                                            // callback
                                            options.loading(main);
                                            self.show();
                                            // debugger
                                        }
                                    },
                                    success: function (a) {
                                        asynchronousAnswer = a;
                                        container.html(asynchronousAnswer);
                                        // because here the processing is asynchronous, it's not linear
                                        self.hide(false);
                                        main.html(container);
                                    }
                                });
                            } else {
                                container.html(contentSource);
                                main.html(container);
                            }

                        };

                    // global scope (public)
                    this.close = function () {
                        main.hide();

                        restartTransition(mask);
                        if (options.fadeOut) {
                            mask.css("transition", "opacity " + options.fadeOut);
                        }
                        mask.addClass("transparent");

                        setTimeout(function () {
                            modal.remove();
                        }, maskTransitionDuration(mask));

                        self.deleteSingleton();
                    };

                    this.hide = function (animation = true) {
                        main.hide();

                        restartTransition(mask);

                        if (animation) {
                            if (options.fadeOut) {
                                mask.css("transition", "opacity " + options.fadeOut);
                                setTimeout(function () {
                                    modal.css("z-index", -1);
                                }, maskTransitionDuration(mask));
                            }
                        }

                        mask.addClass("transparent");
                    };

                    this.show = function () {
                        modal.css("z-index", 0);

                        restartTransition(mask);
                        if (options.fadeIn) {
                            mask.css("transition", "opacity " + options.fadeIn);
                        }
                        mask.removeClass("transparent");

                        main.centralizeAt(document);
                        main.show();
                    };

                    if (!(this instanceof ConstructorReference)) {
                        self = Singleton.exists(ConstructorReference, arguments);
                        if (!self) {
                            return ConstructorReference.instance(arguments);
                        } else {
                            self.show();
                        }
                    // that "else" will should to exit for the "show" method can be used by who instanciates it
                    } else {
                        resolveParams();
                        create();
                    }

                    return self;
                }

            }

        }

    });

}(esPhinx.ui));
<|endoftext|>


<commit_before>var awssum = require('awssum');
var amazon = awssum.load('amazon/amazon');
var CloudSearch = awssum.load('amazon/cloudsearch').CloudSearch;
var DocumentService = awssum.load('amazon/cloudsearch').DocumentService;
var SearchService = awssum.load('amazon/cloudsearch').SearchService;
var xml = require('./batch/xml');
var fs = require('fs');

var OPTIONAL_PARAM = { required : false, type : 'param' };

function sendRawDocumentRequest() {
}

function Client(options) {
  this.rawArgs = options.rawArgs;
  this.domainName = options.domainName;
  this.host = options.host;
  this.port = options.port;
  this.docEndpoint = options.docEndpoint;
  this.searchEndpoint = options.searchEndpoint;
  this.isACS = options.isACS;

  this.accessKeyId     = options.accessKeyId;
  this.secretAccessKey = options.secretAccessKey;
}
Client.prototype = {
  get configurationAPI() {
    if (!this._configurationAPI) {
      this._configurationAPI = new CloudSearch({
        accessKeyId:     this.accessKeyId,
        secretAccessKey: this.secretAccessKey
      });
      if (!this.isACS) {
        var self = this;
        this._configurationAPI.host = function() {
          return self.host;
        };
        this._configurationAPI.addExtras = function(options, args) {
          options.protocol = self.protocol || 'http';
          options.port = self.port;
        };
      }
    }
    return this._configurationAPI;
  },

  get APIDefinitions() {
    return {
      'doc': {
        endPoint:    this.docEndPoint,
        elementName: 'DocService',
        klass:       DocumentService
      },
      'search': {
        endPoint:    this.searchEndPoint,
        elementName: 'SearchService',
        klass:       SearchService
      }
    };
  },
  setupAPI: function(type, callback) {
    this.cachedAPI = this.cachedAPI || {};
    var name = this.domainName + '_' + type;
    if (name in this.cachedAPI)
      return this.cacnedAPI[type];

    var self = this;
    var definition = this.APIDefinitions[type];
    if (definition.endPoint) {
      var parsedEndpoint = definition.endPoint.match(/^([^-]+-([^-]+)-([^\.]+)[^:]+)(?::(\d+))?$/);
      var api = this.createService({
        domainName: parsedEndpoint[2],
        domainId: parsedEndpoint[3],
        host: parsedEndpoint[1],
        port: parsedEndpoint[4] || 80,
        klass: definition.klass
      });
      this.cachedAPI[name] = api;
      return callback(api);
    }

    this.getDomainStatus(function(error, domain) {
      if (error)
        self.raiseFatalError(error);

      try {
        var endpoint = domain[definition.elementName].Endpoint.split(':');
        var api = self.createService({
          domainName: domain.DomainName,
          domainId: domain.DomainId.replace(new RegExp('/' + domain.DomainName + '$'), ''),
          host: endpoint[0],
          port: endpoint[1] || 80,
          klass: definition.klass
        });
        self.cachedAPI[name] = api;
        callback(api);
      } catch(error) {
        self.raiseFatalError(error);
      }
    });
  },
  createService: function(options) {
    var service = new options.klass({
      accessKeyId: this.accessKeyId,
      secretAccessKey: this.secretAccessKey,
      domainName: options.domainName,
      domainId: options.domainId,
      region: amazon.US_EAST_1
    });
    var self = this;
    if (!this.isACS) {
      var host = options.host;
      service.host = function() {
        return host;
      };
      var port = options.port;
      service.addExtras = function(options, args) {
        options.protocol = self.protocol || 'http';
        options.port = port;
      };
    }
    service.extractBody = function(options, args) {
      return 'json';
    };
    service.addCommonOptions = function(options, args) {
      options.headers['content-type'] = 'application/json';
      options.headers['content-length'] = self.countBytes(JSON.stringify(args.Docs));
    };
    return service;
  },
  countBytes: function(string) {
    string = encodeURIComponent(string);
    var escapedPartsMatcher = /\%[0-9a-f][0-9a-f]/gi;
    var escapedParts = string.match(escapedPartsMatcher);
    var notEscapedParts = string.replace(escapedPartsMatcher, '');
    return notEscapedParts.length + (escapedParts ? escapedParts.length : 0);
  },

  raiseFatalError: function(error) {
    if (typeof error != 'string') {
      error = error.message ?
        error.message + '\n' + error.stack : JSON.stringify(error);
      error = 'Unexpected error: ' + error;
    }
    console.log(error);
    process.exit(1);
  },

  rawConfigurationRequest: function(action, params, callback) {
    var extractBody = this.configurationAPI.extractBody;
    this.configurationAPI.extractBody = function() {
      return 'blob';
    };

    var operation = {
          defaults: {
            Action: action
          },
          args: {}
        };
    Object.keys(params).forEach(function(name) {
      operation.args[name] = OPTIONAL_PARAM;
    });

    var self = this;
    this.configurationAPI.send(operation, params, null, function(error, result) {
      self.configurationAPI.extractBody = extractBody;
      callback(error, result);
    });
  },

  assertHaveDomainName: function() {
    if (!this.domainName)
      this.raiseFatalError('You must specify the domain name.');
    return this;
  },

  getDomainStatus: function(domainName, callback) {
    if (typeof domainName == 'function') {
      this.assertHaveDomainName();
      callback = domainName;
      domainName = this.domainName;
    }

    var self = this;
    this.getDomainStatuses(
      { DomainNames: [domainName] },
      function(error, domainStatuses) {
        if (error)
          self.raiseFatalError(error);
        if (domainStatuses.length && domainStatuses[0]) {
          callback(null, domainStatuses[0]);
        } else {
          callback(domainName + ' does not exist. You must specify an existing domain name.', null);
        }
      }
    );
  },

  getDomainStatuses: function(options, callback) {
    try {
      var self = this;
      if (!callback) callback = options;
      var domainStatusesCallback = function(error, response) {
          if (error)
            self.raiseFatalError(error);
          var domainStatuseList = response.Body
               .DescribeDomainsResponse
               .DescribeDomainsResult
               .DomainStatusList;
          var domainStatuses = domainStatuseList && domainStatuseList.member || [];
          if (!Array.isArray(domainStatuses))
            domainStatuses = [domainStatuses];
          callback(null, domainStatuses);
        };
      if (arguments.length > 1)
        this.configurationAPI.DescribeDomains(options, domainStatusesCallback);
      else
        this.configurationAPI.DescribeDomains(domainStatusesCallback);
    } catch(error) {
      this.raiseFatalError(error);
    }
  },

  getIndexFieldStatus: function(options, callback) {
    var domainName;
    var fieldName;
    if (typeof options == 'string') {
      domainName = this.domainName;
      fieldName = options;
    } else {
      domainName = options.domainName;
      fieldName = options.fieldName;
    }

    var self = this;
    this.configurationAPI.DescribeIndexFields(
      {
        DomainName: domainName,
        FieldNames: [fieldName]
      },
      function(error, response) {
        if (error)
          self.raiseFatalError(error);

        var indexFields = response.Body
             .DescribeIndexFieldsResponse
             .DescribeIndexFieldsResult
             .IndexFields
             .member;
        indexFields = !indexFields ? [] :
                      !Array.isArray(indexFields) ? [indexFields] :
                      indexFields;
        if (indexFields.length && indexFields[0])
          callback(null, indexFields[0]);
        else
          callback(fieldName + ' does not exist.', null);
      }
    );
  },

  getIndexFieldStatuses: function(domainName, callback) {
    if (typeof domainName == 'function') {
      this.assertHaveDomainName();
      callback = domainName;
      domainName = this.domainName;
    }

    var self = this;
    this.configurationAPI.DescribeIndexFields(
      { DomainName: domainName },
      function(error, response) {
        if (error)
          self.raiseFatalError(error);

        var indexFields = response.Body
             .DescribeIndexFieldsResponse
             .DescribeIndexFieldsResult
             .IndexFields
             .member;
        indexFields = !indexFields ? [] :
                      !Array.isArray(indexFields) ? [indexFields] :
                      indexFields;
        callback(null, indexFields);
      }
    );
  },

  getDefaultSearchField: function(domainName, callback) {
    if (typeof domainName == 'function') {
      this.assertHaveDomainName();
      callback = domainName;
      domainName = this.domainName;
    }

    var self = this;
    this.configurationAPI.DescribeDefaultSearchField(
      { DomainName: domainName },
      function(error, response) {
        if (error)
          self.raiseFatalError(error);
        try {
          var defaultSearchField = response.Body
                .DescribeDefaultSearchFieldResponse
                .DescribeDefaultSearchFieldResult
                .DefaultSearchField
                .Options;
          if (typeof defaultSearchField != 'string') defaultSearchField = '';
          callback(null, defaultSearchField);
        } catch(error) {
          commandLine.raiseFatalError(error);
        }
      }
    );
  },

  summarizeIndexFieldStatus: function(status, noStatus) {
    var type = status.Options.IndexFieldType;
    var options = status.Options.TextOptions ||
                  status.Options.UIntOptions ||
                  status.Options.LiteralOptions ||
                  {};
    var summarizedOptions = [];
    if (type == 'text' || type == 'uint' || options.SearchEnabled == 'true')
      summarizedOptions.push('Search');
    if (type != 'uint' && options.FacetEnabled == 'true')
      summarizedOptions.push('Facet');
    if (type == 'uint' || options.ResultEnabled == 'true')
      summarizedOptions.push('Result');

    return status.Options.IndexFieldName + ' ' +
             (noStatus ? '' : (status.Status.State + ' ')) +
             type + ' (' + summarizedOptions.join(' ') + ')';
  },

  assertDomainExists: function(callback) {
    var domainName = this.domainName;
    var self = this;
    this.getDomainStatus(domainName, function(error, domain) {
      if (error || !domain)
        self.raiseFatalError(domainName + ' does not exist. You must specify an existing domain name.');
      callback();
    });
  },

  assertNoDomain: function(callback) {
    this.getDomainStatuses(function(error, domains) {
      if (!error && domains.length)
        error = new Error(domains.length + ' domains exist unexpectedly.');
      callback(error);
    });
  },

  detectFileFormat: function(path) {
    var format = path.match(/\.([^\.]+)$/i);
    var supportedFormats = ['xml', 'json'];
    if (!format)
      this.raiseFatalError("Couldn't detect format");

    format = format[1].toLowerCase();

    if (supportedFormats.indexOf(format) < 0)
      this.raiseFatalError('Unknown format <' + format + '>. Supported: ' + supportedFormats.join(', '));

    return format;
  },
  readSDFBatch: function(path, format) {
    format = format || this.detectFileFormat(path);
    var batches = fs.readFileSync(path, 'UTF-8');
    if (format == 'xml')
      batches = xml.toJSON(batches);
    else
      batches = JSON.parse(batches);
    return batches;
  }
};

function toValidHostAndPort(hostAndPort) {
  hostAndPort = hostAndPort.split(':');
  if (hostAndPort[0] == 'localhost')
    hostAndPort[0] = '127.0.0.1';
  if (hostAndPort[0].match(/^\d+\.\d+\.\d+\.\d+$/))
    hostAndPort[0] += '.xip.io';
  return hostAndPort.join(':');
}
Client.toValidHostAndPort = toValidHostAndPort;

exports.Client = Client;
<commit_msg>Remove a trailing space<commit_after>var awssum = require('awssum');
var amazon = awssum.load('amazon/amazon');
var CloudSearch = awssum.load('amazon/cloudsearch').CloudSearch;
var DocumentService = awssum.load('amazon/cloudsearch').DocumentService;
var SearchService = awssum.load('amazon/cloudsearch').SearchService;
var xml = require('./batch/xml');
var fs = require('fs');

var OPTIONAL_PARAM = { required : false, type : 'param' };

function sendRawDocumentRequest() {
}

function Client(options) {
  this.rawArgs = options.rawArgs;
  this.domainName = options.domainName;
  this.host = options.host;
  this.port = options.port;
  this.docEndpoint = options.docEndpoint;
  this.searchEndpoint = options.searchEndpoint;
  this.isACS = options.isACS;

  this.accessKeyId     = options.accessKeyId;
  this.secretAccessKey = options.secretAccessKey;
}
Client.prototype = {
  get configurationAPI() {
    if (!this._configurationAPI) {
      this._configurationAPI = new CloudSearch({
        accessKeyId:     this.accessKeyId,
        secretAccessKey: this.secretAccessKey
      });
      if (!this.isACS) {
        var self = this;
        this._configurationAPI.host = function() {
          return self.host;
        };
        this._configurationAPI.addExtras = function(options, args) {
          options.protocol = self.protocol || 'http';
          options.port = self.port;
        };
      }
    }
    return this._configurationAPI;
  },

  get APIDefinitions() {
    return {
      'doc': {
        endPoint:    this.docEndPoint,
        elementName: 'DocService',
        klass:       DocumentService
      },
      'search': {
        endPoint:    this.searchEndPoint,
        elementName: 'SearchService',
        klass:       SearchService
      }
    };
  },
  setupAPI: function(type, callback) {
    this.cachedAPI = this.cachedAPI || {};
    var name = this.domainName + '_' + type;
    if (name in this.cachedAPI)
      return this.cacnedAPI[type];

    var self = this;
    var definition = this.APIDefinitions[type];
    if (definition.endPoint) {
      var parsedEndpoint = definition.endPoint.match(/^([^-]+-([^-]+)-([^\.]+)[^:]+)(?::(\d+))?$/);
      var api = this.createService({
        domainName: parsedEndpoint[2],
        domainId: parsedEndpoint[3],
        host: parsedEndpoint[1],
        port: parsedEndpoint[4] || 80,
        klass: definition.klass
      });
      this.cachedAPI[name] = api;
      return callback(api);
    }

    this.getDomainStatus(function(error, domain) {
      if (error)
        self.raiseFatalError(error);

      try {
        var endpoint = domain[definition.elementName].Endpoint.split(':');
        var api = self.createService({
          domainName: domain.DomainName,
          domainId: domain.DomainId.replace(new RegExp('/' + domain.DomainName + '$'), ''),
          host: endpoint[0],
          port: endpoint[1] || 80,
          klass: definition.klass
        });
        self.cachedAPI[name] = api;
        callback(api);
      } catch(error) {
        self.raiseFatalError(error);
      }
    });
  },
  createService: function(options) {
    var service = new options.klass({
      accessKeyId: this.accessKeyId,
      secretAccessKey: this.secretAccessKey,
      domainName: options.domainName,
      domainId: options.domainId,
      region: amazon.US_EAST_1
    });
    var self = this;
    if (!this.isACS) {
      var host = options.host;
      service.host = function() {
        return host;
      };
      var port = options.port;
      service.addExtras = function(options, args) {
        options.protocol = self.protocol || 'http';
        options.port = port;
      };
    }
    service.extractBody = function(options, args) {
      return 'json';
    };
    service.addCommonOptions = function(options, args) {
      options.headers['content-type'] = 'application/json';
      options.headers['content-length'] = self.countBytes(JSON.stringify(args.Docs));
    };
    return service;
  },
  countBytes: function(string) {
    string = encodeURIComponent(string);
    var escapedPartsMatcher = /\%[0-9a-f][0-9a-f]/gi;
    var escapedParts = string.match(escapedPartsMatcher);
    var notEscapedParts = string.replace(escapedPartsMatcher, '');
    return notEscapedParts.length + (escapedParts ? escapedParts.length : 0);
  },

  raiseFatalError: function(error) {
    if (typeof error != 'string') {
      error = error.message ?
        error.message + '\n' + error.stack : JSON.stringify(error);
      error = 'Unexpected error: ' + error;
    }
    console.log(error);
    process.exit(1);
  },

  rawConfigurationRequest: function(action, params, callback) {
    var extractBody = this.configurationAPI.extractBody;
    this.configurationAPI.extractBody = function() {
      return 'blob';
    };

    var operation = {
          defaults: {
            Action: action
          },
          args: {}
        };
    Object.keys(params).forEach(function(name) {
      operation.args[name] = OPTIONAL_PARAM;
    });

    var self = this;
    this.configurationAPI.send(operation, params, null, function(error, result) {
      self.configurationAPI.extractBody = extractBody;
      callback(error, result);
    });
  },

  assertHaveDomainName: function() {
    if (!this.domainName)
      this.raiseFatalError('You must specify the domain name.');
    return this;
  },

  getDomainStatus: function(domainName, callback) {
    if (typeof domainName == 'function') {
      this.assertHaveDomainName();
      callback = domainName;
      domainName = this.domainName;
    }

    var self = this;
    this.getDomainStatuses(
      { DomainNames: [domainName] },
      function(error, domainStatuses) {
        if (error)
          self.raiseFatalError(error);
        if (domainStatuses.length && domainStatuses[0]) {
          callback(null, domainStatuses[0]);
        } else {
          callback(domainName + ' does not exist. You must specify an existing domain name.', null);
        }
      }
    );
  },

  getDomainStatuses: function(options, callback) {
    try {
      var self = this;
      if (!callback) callback = options;
      var domainStatusesCallback = function(error, response) {
          if (error)
            self.raiseFatalError(error);
          var domainStatuseList = response.Body
               .DescribeDomainsResponse
               .DescribeDomainsResult
               .DomainStatusList;
          var domainStatuses = domainStatuseList && domainStatuseList.member || [];
          if (!Array.isArray(domainStatuses))
            domainStatuses = [domainStatuses];
          callback(null, domainStatuses);
        };
      if (arguments.length > 1)
        this.configurationAPI.DescribeDomains(options, domainStatusesCallback);
      else
        this.configurationAPI.DescribeDomains(domainStatusesCallback);
    } catch(error) {
      this.raiseFatalError(error);
    }
  },

  getIndexFieldStatus: function(options, callback) {
    var domainName;
    var fieldName;
    if (typeof options == 'string') {
      domainName = this.domainName;
      fieldName = options;
    } else {
      domainName = options.domainName;
      fieldName = options.fieldName;
    }

    var self = this;
    this.configurationAPI.DescribeIndexFields(
      {
        DomainName: domainName,
        FieldNames: [fieldName]
      },
      function(error, response) {
        if (error)
          self.raiseFatalError(error);

        var indexFields = response.Body
             .DescribeIndexFieldsResponse
             .DescribeIndexFieldsResult
             .IndexFields
             .member;
        indexFields = !indexFields ? [] :
                      !Array.isArray(indexFields) ? [indexFields] :
                      indexFields;
        if (indexFields.length && indexFields[0])
          callback(null, indexFields[0]);
        else
          callback(fieldName + ' does not exist.', null);
      }
    );
  },

  getIndexFieldStatuses: function(domainName, callback) {
    if (typeof domainName == 'function') {
      this.assertHaveDomainName();
      callback = domainName;
      domainName = this.domainName;
    }

    var self = this;
    this.configurationAPI.DescribeIndexFields(
      { DomainName: domainName },
      function(error, response) {
        if (error)
          self.raiseFatalError(error);

        var indexFields = response.Body
             .DescribeIndexFieldsResponse
             .DescribeIndexFieldsResult
             .IndexFields
             .member;
        indexFields = !indexFields ? [] :
                      !Array.isArray(indexFields) ? [indexFields] :
                      indexFields;
        callback(null, indexFields);
      }
    );
  },

  getDefaultSearchField: function(domainName, callback) {
    if (typeof domainName == 'function') {
      this.assertHaveDomainName();
      callback = domainName;
      domainName = this.domainName;
    }

    var self = this;
    this.configurationAPI.DescribeDefaultSearchField(
      { DomainName: domainName },
      function(error, response) {
        if (error)
          self.raiseFatalError(error);
        try {
          var defaultSearchField = response.Body
                .DescribeDefaultSearchFieldResponse
                .DescribeDefaultSearchFieldResult
                .DefaultSearchField
                .Options;
          if (typeof defaultSearchField != 'string') defaultSearchField = '';
          callback(null, defaultSearchField);
        } catch(error) {
          commandLine.raiseFatalError(error);
        }
      }
    );
  },

  summarizeIndexFieldStatus: function(status, noStatus) {
    var type = status.Options.IndexFieldType;
    var options = status.Options.TextOptions ||
                  status.Options.UIntOptions ||
                  status.Options.LiteralOptions ||
                  {};
    var summarizedOptions = [];
    if (type == 'text' || type == 'uint' || options.SearchEnabled == 'true')
      summarizedOptions.push('Search');
    if (type != 'uint' && options.FacetEnabled == 'true')
      summarizedOptions.push('Facet');
    if (type == 'uint' || options.ResultEnabled == 'true')
      summarizedOptions.push('Result');

    return status.Options.IndexFieldName + ' ' +
             (noStatus ? '' : (status.Status.State + ' ')) +
             type + ' (' + summarizedOptions.join(' ') + ')';
  },

  assertDomainExists: function(callback) {
    var domainName = this.domainName;
    var self = this;
    this.getDomainStatus(domainName, function(error, domain) {
      if (error || !domain)
        self.raiseFatalError(domainName + ' does not exist. You must specify an existing domain name.');
      callback();
    });
  },

  assertNoDomain: function(callback) {
    this.getDomainStatuses(function(error, domains) {
      if (!error && domains.length)
        error = new Error(domains.length + ' domains exist unexpectedly.');
      callback(error);
    });
  },

  detectFileFormat: function(path) {
    var format = path.match(/\.([^\.]+)$/i);
    var supportedFormats = ['xml', 'json'];
    if (!format)
      this.raiseFatalError("Couldn't detect format");

    format = format[1].toLowerCase();

    if (supportedFormats.indexOf(format) < 0)
      this.raiseFatalError('Unknown format <' + format + '>. Supported: ' + supportedFormats.join(', '));

    return format;
  },
  readSDFBatch: function(path, format) {
    format = format || this.detectFileFormat(path);
    var batches = fs.readFileSync(path, 'UTF-8');
    if (format == 'xml')
      batches = xml.toJSON(batches);
    else
      batches = JSON.parse(batches);
    return batches;
  }
};

function toValidHostAndPort(hostAndPort) {
  hostAndPort = hostAndPort.split(':');
  if (hostAndPort[0] == 'localhost')
    hostAndPort[0] = '127.0.0.1';
  if (hostAndPort[0].match(/^\d+\.\d+\.\d+\.\d+$/))
    hostAndPort[0] += '.xip.io';
  return hostAndPort.join(':');
}
Client.toValidHostAndPort = toValidHostAndPort;

exports.Client = Client;
<|endoftext|>


<commit_before>var levels = [
  {
    name: 'justify-content 1',
    instructions: 'Welcome to Flexbox Froggy, a game where you help Froggy and friends by writing CSS code! Guide this frog get to the lilypad on the right by using the justify-content property, which aligns items horizontally and accepts the following values:

flex-start: Items align to the left side of the container.

flex-end: Items align to the right side of the container.

center: Items align at the center of the container.

space-between: Items display with equal spacing between them.

space-around: Items display with equal spacing around them.

For example, justify-content: center; will center the frog.
',
    board: 'g',
    style: {'justify-content': 'flex-end'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'justify-content 2',
    instructions: 'Use justify-content again to help these frogs get to their lilypads. Remember that this CSS property aligns items horizontally and accepts the following values:

flex-start: Items align to the left side of the container.

flex-end: Items align to the right side of the container.

center: Items align at the center of the container.

space-between: Items display with equal spacing between them.

space-around: Items display with equal spacing around them.

',
    board: 'gy',
    style: {'justify-content': 'center'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'justify-content 3',
    instructions: 'Help all three frogs find their lilypads just by using justify-content. This time, the lilypads have lots of space all around them.',
    board: 'gyr',
    style: {'justify-content': 'space-around'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'justify-content 4',
    instructions: 'Now the lilypads on the edges have drifted to the shore, increasing the space between them. Use justify-content. This time, the lilypads have equal spacing between them.',
    board: 'gyr',
    style: {'justify-content': 'space-between'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'align-items 1',
    instructions: 'Now use align-items to help the frogs get to the bottom of the pond. This CSS property aligns items vertically and accepts the following values:

flex-start: Items align to the top of the container.

flex-end: Items align to the bottom of the container.

center: Items align at the vertical center of the container.

baseline: Items display at the baseline of the container.

stretch: Items are stretched to fit the container.

',
    board: 'gyr',
    style: {'align-items': 'flex-end'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'align-items 2',
    instructions: 'Lead the frog to the center of the pond using a combination of justify-content and align-items.',
    board: 'g',
    style: {'justify-content': 'center', 'align-items': 'center'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'align-items 3',
    instructions: 'The frogs need to cross the pond again, this time for some lilypads with plenty of space around them. Using a combination of justify-content and align-items.',
    board: 'gyr',
    style: {'justify-content': 'space-around', 'align-items': 'flex-end'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'flex-direction 1',
    instructions: 'The frogs need to get in the same order as their lilypads using flex-direction. This CSS property defines the direction items are placed in the container, and accepts the following values:

row: Items are placed the same as the text direction.

row-reverse: Items are placed opposite to the text direction.

column: Items are placed top to bottom.

column-reverse: Items are placed bottom to top.

',
    board: 'gyr',
    style: {'flex-direction': 'row-reverse'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'flex-direction 2',
    instructions: 'Help the frogs find their column of lilypads using flex-direction. This CSS property defines the direction items are placed in the container, and accepts the following values:

row: Items are placed the same as the text direction.

row-reverse: Items are placed opposite to the text direction.

column: Items are placed top to bottom.

column-reverse: Items are placed bottom to top.

',
    board: 'gyr',
    style: {'flex-direction': 'column'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'flex-direction 3',
    instructions: 'Help the frogs get to their own lilypads. Although they seem close, it will take both flex-direction and justify-content to get them there.
Notice that when you set the direction to a reversed row or column, start and end are also reversed.',
    board: 'gyr',
    style: {'flex-direction': 'row-reverse', 'justify-content': 'flex-end'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'flex-direction 4',
    instructions: '
Help the frogs find their lilypads using flex-direction and justify-content.

Notice that when the flex direction is a column, justify-content changes to the vertical and align-items to the horizontal.
',
    board: 'gyr',
    style: {'flex-direction': 'column', 'justify-content': 'flex-end'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'flex-direction 5',
    instructions: 'Help the frogs find their lilypads using flex-direction and justify-content.',
    board: 'gyr',
    style: {'flex-direction': 'column-reverse', 'justify-content': 'space-between'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'flex-direction 6',
    instructions: 'Help the frogs find their lilypads using flex-direction, justify-content, and align-items.',
    board: 'gyr',
    style: {'flex-direction': 'row-reverse', 'justify-content': 'center', 'align-items': 'flex-end'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'order 1',
    instructions: 'Sometimes reversing the row or column order of a container is not enough. In these cases, we can apply the order property to individual items. By default, items have a value of 0, but we can use this property to set it to a positive or negative integer value.
Use the order property to reorder the frogs according to their lilypads.',
    board: 'gyr',
    selector: '> :nth-child(2)',
    classes: {'#pond, #background': 'wrap'},
    style: {'order': '2'},
    before: "#pond {\n  display: flex;\n}\n\n.yellow {\n",
    after: "}",
  },
  {
    name: 'order 2',
    instructions: 'Use the order property to send the red frog to his lilypad.',
    board: 'gggrg',
    selector: '> :nth-child(4)',
    classes: {'#pond, #background': 'wrap'},
    style: {'order': '-1'},
    before: "#pond {\n  display: flex;\n}\n\n.red {\n",
    after: "}",
  },
  {
    name: 'align-self 1',
    instructions: 'Another property you can apply to individual items is align-self. This property accepts the same values as align-items and its value for the specific item.',
    board: 'ggygg',
    selector: '> :nth-child(3)',
    style: {'align-self': 'flex-end'},
    before: "#pond {\n  display: flex;\n  align-items: flex-start\n}\n\n.yellow {\n",
    after: "}",
  },
  {
    name: 'align-self 2',
    instructions: 'Combine order with align-self to help the frogs to their destinations.',
    board: 'ygygg',
    selector: '> .yellow',
    style: {'align-self': 'flex-end', 'order': '2'},
    before: "#pond {\n  display: flex;\n  align-items: flex-start\n}\n\n.yellow {\n",
    after: "}",
  },
  {
    name: 'flex-wrap 1',
    instructions: 'Oh no! The frogs are all squeezed onto a single row of lilypads. Spread them out using the flex-wrap property, which accepts the following values:

nowrap: Every item is fit to a single line.

wrap: Items wrap around to additional lines.

wrap-reverse: Items wrap around to additional lines in reverse.

',
    board: 'ygggggr',
    style: {'flex-wrap': 'wrap'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'flex-wrap 2',
    instructions: 'Help this army of frogs form three orderly columns using a combination of flex-direction and flex-wrap.',
    board: 'gggggrrrrryyyyy',
    style: {'flex-direction': 'column', 'flex-wrap': 'wrap'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'flex-flow 1',
    instructions: 'The two properties flex-direction and flex-wrap are used so often together that the shorthand property flex-flow was created to combine them. This shorthand property accepts the value of of the two properties separated by a space.
For example, you can use flex-flow: row wrap to set rows and wrap them.

Try using flex-flow to repeat the previous level.
',
    board: 'gggggrrrrryyyyy',
    style: {'flex-flow': 'column wrap'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'align-content 1',
    instructions: 'The frogs are spread all over the pond, but the lilypads are bunched at the top. You can use align-content to set how multiple lines are spaced apart. This property takes the following values:

flex-start: Lines are packed at the top of the container.

flex-end: Lines are packed at the bottom of the container.

center: Lines are packed at the vertical center of the container.

space-between: Lines display with equal spacing between them.

space-around: Lines display with equal spacing around them.

stretch: Lines are stretched to fit the container.

When there is only one line, this property has no effect.
',
    board: 'ggggggggggggggg',
    classes: {'#pond, #background': 'wrap'},
    style: {'align-content': 'flex-start'},
    before: "#pond {\n  display: flex;\n  flex-wrap: wrap\n",
    after: "}",
  },
  {
    name: 'align-content 2',
    instructions: 'Now the current has bunched the lilypads at the bottom. Use align-content to guide the frogs there.',
    board: 'ggggggggggggggg',
    classes: {'#pond, #background': 'wrap'},
    style: {'align-content': 'flex-end'},
    before: "#pond {\n  display: flex;\n  flex-wrap: wrap\n",
    after: "}",
  },
  {
    name: 'align-content 3',
    instructions: 'The frogs have had a party, but it is time to go home. Use a combination of flex-direction and align-content to get them to their lilypads.',
    board: 'rgggyrgggyrgggy',
    classes: {'#pond, #background': 'wrap'},
    style: {'flex-direction': 'column-reverse', 'align-content': 'center'},
    before: "#pond {\n  display: flex;\n  flex-wrap: wrap\n",
    after: "}",
  },
  {
    name: 'align-content 4',
    instructions: 'Bring the frogs home one last time by using all of the CSS properties you learned about.',
    board: 'rggggyy',
    style: {'flex-direction': 'column-reverse', 'flex-wrap': 'wrap-reverse', 'align-content': 'space-between', 'justify-content': 'center'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  }
];
<commit_msg>fix typo on level 1<commit_after>var levels = [
  {
    name: 'justify-content 1',
    instructions: 'Welcome to Flexbox Froggy, a game where you help Froggy and friends by writing CSS code! Guide this frog to the lilypad on the right by using the justify-content property, which aligns items horizontally and accepts the following values:

flex-start: Items align to the left side of the container.

flex-end: Items align to the right side of the container.

center: Items align at the center of the container.

space-between: Items display with equal spacing between them.

space-around: Items display with equal spacing around them.

For example, justify-content: center; will center the frog.
',
    board: 'g',
    style: {'justify-content': 'flex-end'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'justify-content 2',
    instructions: 'Use justify-content again to help these frogs get to their lilypads. Remember that this CSS property aligns items horizontally and accepts the following values:

flex-start: Items align to the left side of the container.

flex-end: Items align to the right side of the container.

center: Items align at the center of the container.

space-between: Items display with equal spacing between them.

space-around: Items display with equal spacing around them.

',
    board: 'gy',
    style: {'justify-content': 'center'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'justify-content 3',
    instructions: 'Help all three frogs find their lilypads just by using justify-content. This time, the lilypads have lots of space all around them.',
    board: 'gyr',
    style: {'justify-content': 'space-around'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'justify-content 4',
    instructions: 'Now the lilypads on the edges have drifted to the shore, increasing the space between them. Use justify-content. This time, the lilypads have equal spacing between them.',
    board: 'gyr',
    style: {'justify-content': 'space-between'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'align-items 1',
    instructions: 'Now use align-items to help the frogs get to the bottom of the pond. This CSS property aligns items vertically and accepts the following values:

flex-start: Items align to the top of the container.

flex-end: Items align to the bottom of the container.

center: Items align at the vertical center of the container.

baseline: Items display at the baseline of the container.

stretch: Items are stretched to fit the container.

',
    board: 'gyr',
    style: {'align-items': 'flex-end'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'align-items 2',
    instructions: 'Lead the frog to the center of the pond using a combination of justify-content and align-items.',
    board: 'g',
    style: {'justify-content': 'center', 'align-items': 'center'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'align-items 3',
    instructions: 'The frogs need to cross the pond again, this time for some lilypads with plenty of space around them. Using a combination of justify-content and align-items.',
    board: 'gyr',
    style: {'justify-content': 'space-around', 'align-items': 'flex-end'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'flex-direction 1',
    instructions: 'The frogs need to get in the same order as their lilypads using flex-direction. This CSS property defines the direction items are placed in the container, and accepts the following values:

row: Items are placed the same as the text direction.

row-reverse: Items are placed opposite to the text direction.

column: Items are placed top to bottom.

column-reverse: Items are placed bottom to top.

',
    board: 'gyr',
    style: {'flex-direction': 'row-reverse'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'flex-direction 2',
    instructions: 'Help the frogs find their column of lilypads using flex-direction. This CSS property defines the direction items are placed in the container, and accepts the following values:

row: Items are placed the same as the text direction.

row-reverse: Items are placed opposite to the text direction.

column: Items are placed top to bottom.

column-reverse: Items are placed bottom to top.

',
    board: 'gyr',
    style: {'flex-direction': 'column'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'flex-direction 3',
    instructions: 'Help the frogs get to their own lilypads. Although they seem close, it will take both flex-direction and justify-content to get them there.
Notice that when you set the direction to a reversed row or column, start and end are also reversed.',
    board: 'gyr',
    style: {'flex-direction': 'row-reverse', 'justify-content': 'flex-end'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'flex-direction 4',
    instructions: '
Help the frogs find their lilypads using flex-direction and justify-content.

Notice that when the flex direction is a column, justify-content changes to the vertical and align-items to the horizontal.
',
    board: 'gyr',
    style: {'flex-direction': 'column', 'justify-content': 'flex-end'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'flex-direction 5',
    instructions: 'Help the frogs find their lilypads using flex-direction and justify-content.',
    board: 'gyr',
    style: {'flex-direction': 'column-reverse', 'justify-content': 'space-between'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'flex-direction 6',
    instructions: 'Help the frogs find their lilypads using flex-direction, justify-content, and align-items.',
    board: 'gyr',
    style: {'flex-direction': 'row-reverse', 'justify-content': 'center', 'align-items': 'flex-end'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'order 1',
    instructions: 'Sometimes reversing the row or column order of a container is not enough. In these cases, we can apply the order property to individual items. By default, items have a value of 0, but we can use this property to set it to a positive or negative integer value.
Use the order property to reorder the frogs according to their lilypads.',
    board: 'gyr',
    selector: '> :nth-child(2)',
    classes: {'#pond, #background': 'wrap'},
    style: {'order': '2'},
    before: "#pond {\n  display: flex;\n}\n\n.yellow {\n",
    after: "}",
  },
  {
    name: 'order 2',
    instructions: 'Use the order property to send the red frog to his lilypad.',
    board: 'gggrg',
    selector: '> :nth-child(4)',
    classes: {'#pond, #background': 'wrap'},
    style: {'order': '-1'},
    before: "#pond {\n  display: flex;\n}\n\n.red {\n",
    after: "}",
  },
  {
    name: 'align-self 1',
    instructions: 'Another property you can apply to individual items is align-self. This property accepts the same values as align-items and its value for the specific item.',
    board: 'ggygg',
    selector: '> :nth-child(3)',
    style: {'align-self': 'flex-end'},
    before: "#pond {\n  display: flex;\n  align-items: flex-start\n}\n\n.yellow {\n",
    after: "}",
  },
  {
    name: 'align-self 2',
    instructions: 'Combine order with align-self to help the frogs to their destinations.',
    board: 'ygygg',
    selector: '> .yellow',
    style: {'align-self': 'flex-end', 'order': '2'},
    before: "#pond {\n  display: flex;\n  align-items: flex-start\n}\n\n.yellow {\n",
    after: "}",
  },
  {
    name: 'flex-wrap 1',
    instructions: 'Oh no! The frogs are all squeezed onto a single row of lilypads. Spread them out using the flex-wrap property, which accepts the following values:

nowrap: Every item is fit to a single line.

wrap: Items wrap around to additional lines.

wrap-reverse: Items wrap around to additional lines in reverse.

',
    board: 'ygggggr',
    style: {'flex-wrap': 'wrap'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'flex-wrap 2',
    instructions: 'Help this army of frogs form three orderly columns using a combination of flex-direction and flex-wrap.',
    board: 'gggggrrrrryyyyy',
    style: {'flex-direction': 'column', 'flex-wrap': 'wrap'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'flex-flow 1',
    instructions: 'The two properties flex-direction and flex-wrap are used so often together that the shorthand property flex-flow was created to combine them. This shorthand property accepts the value of of the two properties separated by a space.
For example, you can use flex-flow: row wrap to set rows and wrap them.

Try using flex-flow to repeat the previous level.
',
    board: 'gggggrrrrryyyyy',
    style: {'flex-flow': 'column wrap'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  },
  {
    name: 'align-content 1',
    instructions: 'The frogs are spread all over the pond, but the lilypads are bunched at the top. You can use align-content to set how multiple lines are spaced apart. This property takes the following values:

flex-start: Lines are packed at the top of the container.

flex-end: Lines are packed at the bottom of the container.

center: Lines are packed at the vertical center of the container.

space-between: Lines display with equal spacing between them.

space-around: Lines display with equal spacing around them.

stretch: Lines are stretched to fit the container.

When there is only one line, this property has no effect.
',
    board: 'ggggggggggggggg',
    classes: {'#pond, #background': 'wrap'},
    style: {'align-content': 'flex-start'},
    before: "#pond {\n  display: flex;\n  flex-wrap: wrap\n",
    after: "}",
  },
  {
    name: 'align-content 2',
    instructions: 'Now the current has bunched the lilypads at the bottom. Use align-content to guide the frogs there.',
    board: 'ggggggggggggggg',
    classes: {'#pond, #background': 'wrap'},
    style: {'align-content': 'flex-end'},
    before: "#pond {\n  display: flex;\n  flex-wrap: wrap\n",
    after: "}",
  },
  {
    name: 'align-content 3',
    instructions: 'The frogs have had a party, but it is time to go home. Use a combination of flex-direction and align-content to get them to their lilypads.',
    board: 'rgggyrgggyrgggy',
    classes: {'#pond, #background': 'wrap'},
    style: {'flex-direction': 'column-reverse', 'align-content': 'center'},
    before: "#pond {\n  display: flex;\n  flex-wrap: wrap\n",
    after: "}",
  },
  {
    name: 'align-content 4',
    instructions: 'Bring the frogs home one last time by using all of the CSS properties you learned about.',
    board: 'rggggyy',
    style: {'flex-direction': 'column-reverse', 'flex-wrap': 'wrap-reverse', 'align-content': 'space-between', 'justify-content': 'center'},
    before: "#pond {\n  display: flex;\n",
    after: "}",
  }
];
<|endoftext|>


<commit_before>var exec = require('child_process').exec;
var chalk = require('chalk');

// Output styling.
var success = chalk.green;
var notice = chalk.yellow;
var whoops = chalk.bold.red; // Can't name error as exec uses error in callback.
var underline = chalk.underline;

exports.init = function() {
	exec('git init', function(error, stdout, stderr) {
		if (stdout.substring(0, 13) === 'Reinitialized') {
			console.log(notice('[~] Reinitialized existing Git repository.'));
		} else {
			console.log(success('[✔] Initialized new Git repository.'));
		}
	});
};

exports.clone = function(repository) {
	// Nothing to clone.
	if (!repository) {
		console.log(notice('[~] You must enter a repository URL.'));
	} else {
		exec('git clone ' + repository, function(error, stdout, stderr) {
			if (stderr.substring(0, 7) === 'Cloning') {
				if (stderr.split('\n')[1].split(' ')[0] === 'fatal:') {
					console.log(whoops('[✖] Could not clone repository.'));
				} else {
					console.log(success('[✔] Cloned into ' + stderr.split('\n')[0].split(' ')[2]));
				}
			} else {
				if (stderr.substring(0, 23) === 'fatal: destination path') {
					console.log(notice('[~] Directory ' + stderr.split(' ')[3] + ' is not empty.'));
				} else {
					console.log(whoops('[✖] Could not clone repository.'));
				}
			}
		});
	}
};

exports.addAll = function() {
	exec('git add -A');

	console.log(success('[✔] Added everything!'));
};

exports.addSingle = function(target) {
	//TODO: Fix the Error handling! Currently just ignores warnings
	exec('git add ' + target, function(error, stdout, stderr) {
		if (stderr.substring(0, 7) !== 'warning') {
			console.log(whoops('[✖] Could not add target specified. Are you sure the target exists?'));
		} else {
			if (typeof target === 'undefined') { // Then just add all.
				exports.addAll();
			} else {
				console.log(success('[✔] Added ' + target + '!'));
			}
		}
	});
};

exports.addOptions = function(options, target) {
	// TODO: Fix the Error Handling! Currently just ignores warnings
	exec('git add -' + options + ' ' + target, function(error, stdout, stderr) {
		if (stderr.substring(0, 7) !== 'warning') {
			console.log(whoops('[✖] Could not add target specified. Are you sure the target exists?'));
		} else {
			if (typeof target === 'undefined') { // Then just add all.
				exports.addAll();
			} else {
				console.log(success('[✔] Added ' + target + '!'));
			}
		}
	});
};

exports.commit = function(message) {
	// No commit message.
	if (message === '') {
		console.log(notice('[~] You must enter a commit message.'));
	} else {
		exports.addAll();

		exec('git commit -m "' + message + '"', function(error, stdout, stderr) {
			if (stdout.substring(0, 1) === '[') {
				console.log(success('[✔] Commited!'));

				console.log();
				console.log('"' + underline(message) + '"');
			} else if (stdout.substring(0, 2) === 'On') {
				console.log(notice('[~] Everything already committed.'));
			} else {
				console.log(whoops('[✖] Could not commit changes.') + chalk.red(' Try again if there was a large amount of changes to add.'));
			}
		});
	}
};

exports.push = function() {
	exec('git push', function(error, stdout, stderr) {
		if (stderr.substring(0, 10) === 'Everything') {
			console.log(notice('[~] All commits already pushed.'));
		} else if (stderr.substring(0, 2) === 'To') {
			console.log(success('[✔] Pushed!'));
		} else {
			// TODO: add handling for non-fast-forwards (when you need to pull first, merge, and then push).
			console.log(whoops('[✖] Could not push commits.') + chalk.red(' (may have to pull first, merge any conflicts, and then attempt to push again using the ') + chalk.red.underline('standard git command') + chalk.red('.)'));
		}
	});
};

exports.pull = function() {
	exec('git pull', function(error, stdout, stderr) {
		if (stdout.substring(0, 7) === 'Already') {
			console.log(notice('[~] Everything is already up-to-date.'));
		} else if (stdout.substring(0, 8) === 'Updating') {
			console.log(success('[✔] Pulled!'));
		} else {
			// TODO: add handling for merge conflicts.
			console.log(whoops('[✖] Could not pull commits.') + chalk.red(' (may have to pull using the ') + chalk.red.underline('standard git command') + chalk.red(' to handle merge conflicts.)'));
		}
	});
};

exports.fetch = function() {
	exec('git fetch', function(error, stdout, stderr) {
		if (stdout === '' && stderr === '') {
			console.log(success('[✔] Fetched!'));
		} else {
			console.log(whoops('[✖] Could not fetch commits.'));
		}
	});
};

exports.status = function() {
	exec('git status', function(error, stdout, stderr) {
		var status = stdout.split('\n');

		// Branch.
		console.log(chalk.dim('branch  ') + chalk.gray.dim(' | ') + success(status[0].split(' ')[2]));

		// Position in branch.
		var position;
		switch (status[1].split(' ')[3]) {
			case 'behind':
				position = 'position' + chalk.gray.dim(' | ') + notice(status[1].split(' ')[7] + ' commits behind (fetch or pull)');
				break;

			case 'working': // Quick hack to get it working with freshly initialized git repositories.
			case 'up-to-date':
				position = chalk.dim('position') + chalk.gray.dim(' | ') + success('up-to-date');
				break;

			case 'ahead':
				position = 'position' + chalk.gray.dim(' | ') + notice(status[1].split(' ')[7] + ' commits ahead (push commits)');
				break;

			default:
				// TODO: add proper handling for freshly initialized git repositories.
				if (typeof status[1].split(' ')[3] === 'undefined') { // Quick hack to get it working with freshly initialized git repositories.
					position = chalk.dim('position') + chalk.gray.dim(' | ') + success('up-to-date');
				} else {
					position = 'position' + chalk.gray.dim(' | ') + whoops('diverged');
				}
		}
		console.log(position);

		console.log();

		// Staging and commits.
		var staging;
		if (status[3] === 'Changes not staged for commit:') {
			staging = 'staging ' + chalk.gray.dim(' | ') + notice('not all changes staged (add all changes)');
		} else {
			if (status[3].split(' ')[0] !== 'nothing to commit, working directory clean') {
				if (status[4].split(' ')[0] === 'Untracked') {
					staging = 'staging ' + chalk.gray.dim(' | ') + notice('not all changes staged (add all changes)');
				} else {
					staging = chalk.dim('staging ') + chalk.gray.dim(' | ') + success('all changes staged');
				}
			}
		}

		console.log(staging);

		var commits;
		if (status[3] === 'Changes to be committed:') {
			commits = 'commits ' + chalk.gray.dim(' | ') + notice('not all changes committed (commit all changes)');
		} else {
			commits = chalk.dim('commits ') + chalk.gray.dim(' | ') + success('all changes committed');
		}

		console.log(commits);
	});
};

// https://gist.github.com/textarcana/1306223
exports.log = function() {
	exec('git log --pretty=format:\'{%n  "commit": "%H",%n  "author": "%an <%ae>",%n  "date": "%ad",%n  "message": "%f"%n},\' $@ | perl -pe \'BEGIN{print "["}; END{print "]\n"}\' | perl -pe \'s/},]/}]/\'', function(error, stdout, stderr) {
		var log = JSON.parse(stdout);
		log.reverse(); // Show newest at the bottom.

		for (var i = 0; i < log.length; i++) {
			console.log(); // New line between each commit.

			console.log(chalk.yellow('[' + log[i].commit + ']'));

			var author = {
				name: log[i].author.split('<')[0].trim(),
				email: '<' + log[i].author.split('<')[1]
			};

			console.log('|- ' + chalk.gray(author.name) + " " + chalk.gray.dim(author.email));
			console.log('|- ' + chalk.gray.dim(log[i].date));
			console.log('|- ' + chalk.green(log[i].message.split('-').join(' ')));
		}
	});
};
<commit_msg>Fix #3.<commit_after>var exec = require('child_process').exec;
var chalk = require('chalk');

// Output styling.
var success = chalk.green;
var notice = chalk.yellow;
var whoops = chalk.bold.red; // Can't name error as exec uses error in callback.
var underline = chalk.underline;

exports.init = function() {
	exec('git init', function(error, stdout, stderr) {
		if (stdout.substring(0, 13) === 'Reinitialized') {
			console.log(notice('[~] Reinitialized existing Git repository.'));
		} else {
			console.log(success('[✔] Initialized new Git repository.'));
		}
	});
};

exports.clone = function(repository) {
	// Nothing to clone.
	if (!repository) {
		console.log(notice('[~] You must enter a repository URL.'));
	} else {
		exec('git clone ' + repository, function(error, stdout, stderr) {
			if (stderr.substring(0, 7) === 'Cloning') {
				if (stderr.split('\n')[1].split(' ')[0] === 'fatal:') {
					console.log(whoops('[✖] Could not clone repository.'));
				} else {
					console.log(success('[✔] Cloned into ' + stderr.split('\n')[0].split(' ')[2]));
				}
			} else {
				if (stderr.substring(0, 23) === 'fatal: destination path') {
					console.log(notice('[~] Directory ' + stderr.split(' ')[3] + ' is not empty.'));
				} else {
					console.log(whoops('[✖] Could not clone repository.'));
				}
			}
		});
	}
};

exports.addAll = function() {
	exec('git add -A');

	console.log(success('[✔] Added everything!'));
};

exports.addSingle = function(target) {
	//TODO: Fix the Error handling! Currently just ignores warnings
	exec('git add ' + target, function(error, stdout, stderr) {
		if (stderr.substring(0, 7) !== 'warning') {
			console.log(whoops('[✖] Could not add target specified. Are you sure the target exists?'));
		} else {
			if (typeof target === 'undefined') { // Then just add all.
				exports.addAll();
			} else {
				console.log(success('[✔] Added ' + target + '!'));
			}
		}
	});
};

exports.addOptions = function(options, target) {
	// TODO: Fix the Error Handling! Currently just ignores warnings
	exec('git add -' + options + ' ' + target, function(error, stdout, stderr) {
		if (stderr.substring(0, 7) !== 'warning') {
			console.log(whoops('[✖] Could not add target specified. Are you sure the target exists?'));
		} else {
			if (typeof target === 'undefined') { // Then just add all.
				exports.addAll();
			} else {
				console.log(success('[✔] Added ' + target + '!'));
			}
		}
	});
};

exports.commit = function(message) {
	// No commit message.
	if (message === '') {
		console.log(notice('[~] You must enter a commit message.'));
	} else {
		exports.addAll();

		exec('git commit -m "' + message + '"', function(error, stdout, stderr) {
			if (stdout.substring(0, 1) === '[') {
				console.log(success('[✔] Commited!'));

				console.log();
				console.log('"' + underline(message) + '"');
			} else if (stdout.substring(0, 2) === 'On') {
				console.log(notice('[~] Everything already committed.'));
			} else {
				console.log(whoops('[✖] Could not commit changes.') + chalk.red(' Try again if there was a large amount of changes to add.'));
			}
		});
	}
};

exports.push = function() {
	exec('git push', function(error, stdout, stderr) {
		if (stderr.substring(0, 10) === 'Everything') {
			console.log(notice('[~] All commits already pushed.'));
		} else if (stderr.substring(0, 2) === 'To') {
			console.log(success('[✔] Pushed!'));
		} else {
			// TODO: add handling for non-fast-forwards (when you need to pull first, merge, and then push).
			console.log(whoops('[✖] Could not push commits.') + chalk.red(' (may have to pull first, merge any conflicts, and then attempt to push again using the ') + chalk.red.underline('standard git command') + chalk.red('.)'));
		}
	});
};

exports.pull = function() {
	exec('git pull', function(error, stdout, stderr) {
		if (stdout.substring(0, 7) === 'Already') {
			console.log(notice('[~] Everything is already up-to-date.'));
		} else if (stdout.substring(0, 8) === 'Updating') {
			console.log(success('[✔] Pulled!'));
		} else {
			// TODO: add handling for merge conflicts.
			console.log(whoops('[✖] Could not pull commits.') + chalk.red(' (may have to pull using the ') + chalk.red.underline('standard git command') + chalk.red(' to handle merge conflicts.)'));
		}
	});
};

exports.fetch = function() {
	exec('git fetch', function(error, stdout, stderr) {
		if (stdout === '' && stderr === '') {
			console.log(success('[✔] Fetched!'));
		} else {
			console.log(whoops('[✖] Could not fetch commits.'));
		}
	});
};

exports.status = function() {
	exec('git status', function(error, stdout, stderr) {
		var status = stdout.split('\n');

		// Branch.
		console.log(chalk.dim('branch  ') + chalk.gray.dim(' | ') + success(status[0].split(' ')[2]));

		// Position in branch.
		var position;
		switch (status[1].split(' ')[3]) {
			case 'behind':
				position = 'position' + chalk.gray.dim(' | ') + notice(status[1].split(' ')[7] + ' commits behind (fetch or pull)');
				break;

			case 'working': // Quick hack to get it working with freshly initialized git repositories.
			case 'up-to-date':
				position = chalk.dim('position') + chalk.gray.dim(' | ') + success('up-to-date');
				break;

			case 'ahead':
				position = 'position' + chalk.gray.dim(' | ') + notice(status[1].split(' ')[7] + ' commits ahead (push commits)');
				break;

			default:
				// TODO: add proper handling for freshly initialized git repositories.
				if (typeof status[1].split(' ')[3] === 'undefined') { // Quick hack to get it working with freshly initialized git repositories.
					position = chalk.dim('position') + chalk.gray.dim(' | ') + success('up-to-date');
				} else {
					position = 'position' + chalk.gray.dim(' | ') + whoops('diverged');
				}
		}
		console.log(position);

		console.log();

		// Staging and commits.
		var staging;
		if (status[3] === 'Changes not staged for commit:') {
			staging = 'staging ' + chalk.gray.dim(' | ') + notice('not all changes staged (add all changes)');
		} else {
			if (status[3].split(' ')[0] !== 'nothing to commit, working directory clean') {
				if (status[1] === 'nothing to commit, working directory clean') {
					if (status[4].split(' ')[0] === 'Untracked') {
						staging = 'staging ' + chalk.gray.dim(' | ') + notice('not all changes staged (add all changes)');
					} else {
						staging = chalk.dim('staging ') + chalk.gray.dim(' | ') + success('all changes staged');
					}
				}
			}
		}

		console.log(staging);

		var commits;
		if (status[3] === 'Changes to be committed:') {
			commits = 'commits ' + chalk.gray.dim(' | ') + notice('not all changes committed (commit all changes)');
		} else {
			commits = chalk.dim('commits ') + chalk.gray.dim(' | ') + success('all changes committed');
		}

		console.log(commits);
	});
};

// https://gist.github.com/textarcana/1306223
exports.log = function() {
	exec('git log --pretty=format:\'{%n  "commit": "%H",%n  "author": "%an <%ae>",%n  "date": "%ad",%n  "message": "%f"%n},\' $@ | perl -pe \'BEGIN{print "["}; END{print "]\n"}\' | perl -pe \'s/},]/}]/\'', function(error, stdout, stderr) {
		var log = JSON.parse(stdout);
		log.reverse(); // Show newest at the bottom.

		for (var i = 0; i < log.length; i++) {
			console.log(); // New line between each commit.

			console.log(chalk.yellow('[' + log[i].commit + ']'));

			var author = {
				name: log[i].author.split('<')[0].trim(),
				email: '<' + log[i].author.split('<')[1]
			};

			console.log('|- ' + chalk.gray(author.name) + " " + chalk.gray.dim(author.email));
			console.log('|- ' + chalk.gray.dim(log[i].date));
			console.log('|- ' + chalk.green(log[i].message.split('-').join(' ')));
		}
	});
};
<|endoftext|>


<commit_before>
/**
 * Module dependencies.
 */

var debug = require('debug')('wpcom:media');

/**
 * Media methods
 *
 * @param {String} id
 * @param {String} sid site id
 * @param {WPCOM} wpcom
 * @api public
 */

function Media(id, sid, wpcom){
  if (!(this instanceof Media)) return new Media(id, sid, wpcom);

  this.wpcom = wpcom;
  this._sid = sid;
  this._id = id;

  if (!this._id) {
    debug('WARN: media id is not defined');
  }
}

/**
 * Get media
 *
 * @param {Object} [query]
 * @param {Function} fn
 * @api public
 */

Media.prototype.get = function(query, fn){
  var path = '/sites/' + this._sid + '/media/' + this._id;
  this.wpcom.sendRequest(path, query, null, fn);
};

/**
 * Add media file
 *
 * @param {String|Array} files
 * @param {Function} fn
 */

Media.prototype.addFiles = function(files, fn){
  var path = '/sites/' + this._sid + '/media/new';
  var params = { path: path, method: 'post', formData: [] };

  // process formData
  files = Array.isArray(files) ? files : [ files ];
  for (var i = 0; i < files.length; i++) {
    params.formData.push([ 'media[]', files[i]]);
  }

  this.wpcom.sendRequest(params, null, null, fn);
};

/**
 * Add media files from URL
 *
 * @param {String|Array} files
 * @param {Function} fn
 */

Media.prototype.addUrls = function(files, fn){
  var path = '/sites/' + this._sid + '/media/new';
  var params = { path: path, method: 'post' };
  var body = { media_urls: [] };

  // process formData
  files = Array.isArray(files) ? files : [ files ];
  for (var i = 0; i < files.length; i++) {
    body.media_urls.push(files[i]);
  }

  this.wpcom.sendRequest(params, null, body, fn);
};

/**
 * Delete media
 *
 * @param {Function} fn
 * @api public
 */

Media.prototype['delete'] =
Media.prototype.del = function(fn){
  var path = '/sites/' + this._sid + '/media/' + this._id + '/delete';
  this.wpcom.sendRequest({ path: path, method: 'post' }, null, body, fn);
};

/**
 * Expose `Media` module
 */

module.exports = Media;
<commit_msg>media: remove space close to array brackets<commit_after>
/**
 * Module dependencies.
 */

var debug = require('debug')('wpcom:media');

/**
 * Media methods
 *
 * @param {String} id
 * @param {String} sid site id
 * @param {WPCOM} wpcom
 * @api public
 */

function Media(id, sid, wpcom){
  if (!(this instanceof Media)) return new Media(id, sid, wpcom);

  this.wpcom = wpcom;
  this._sid = sid;
  this._id = id;

  if (!this._id) {
    debug('WARN: media id is not defined');
  }
}

/**
 * Get media
 *
 * @param {Object} [query]
 * @param {Function} fn
 * @api public
 */

Media.prototype.get = function(query, fn){
  var path = '/sites/' + this._sid + '/media/' + this._id;
  this.wpcom.sendRequest(path, query, null, fn);
};

/**
 * Add media file
 *
 * @param {String|Array} files
 * @param {Function} fn
 */

Media.prototype.addFiles = function(files, fn){
  var path = '/sites/' + this._sid + '/media/new';
  var params = { path: path, method: 'post', formData: [] };

  // process formData
  files = Array.isArray(files) ? files : [ files ];
  for (var i = 0; i < files.length; i++) {
    params.formData.push(['media[]', files[i]]);
  }

  this.wpcom.sendRequest(params, null, null, fn);
};

/**
 * Add media files from URL
 *
 * @param {String|Array} files
 * @param {Function} fn
 */

Media.prototype.addUrls = function(files, fn){
  var path = '/sites/' + this._sid + '/media/new';
  var params = { path: path, method: 'post' };
  var body = { media_urls: [] };

  // process formData
  files = Array.isArray(files) ? files : [ files ];
  for (var i = 0; i < files.length; i++) {
    body.media_urls.push(files[i]);
  }

  this.wpcom.sendRequest(params, null, body, fn);
};

/**
 * Delete media
 *
 * @param {Function} fn
 * @api public
 */

Media.prototype['delete'] =
Media.prototype.del = function(fn){
  var path = '/sites/' + this._sid + '/media/' + this._id + '/delete';
  this.wpcom.sendRequest({ path: path, method: 'post' }, null, body, fn);
};

/**
 * Expose `Media` module
 */

module.exports = Media;
<|endoftext|>