<commit_before>/*
This file is part of the Juju GUI, which lets users view and manage Juju
environments within a graphical interface (https://launchpad.net/juju-gui).
Copyright (C) 2014 Canonical Ltd.

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License version 3, as published by
the Free Software Foundation.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero
General Public License for more details.

You should have received a copy of the GNU Affero General Public License along
with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

'use strict';

(function() {

  describe('Web handler', function() {
    var mockXhr, utils, webHandler, webModule, Y;
    var requirements = ['juju-env-web-handler', 'juju-tests-utils'];

    before(function(done) {
      // Set up the YUI instance, the test utils and the web namespace.
      Y = YUI(GlobalConfig).use(requirements, function(Y) {
        utils = Y.namespace('juju-tests.utils');
        webModule = Y.namespace('juju.environments.web');
        done();
      });
    });

    beforeEach(function() {
      // Instantiate a web handler and set up an XMLHttpRequest mock.
      webHandler = new webModule.WebHandler();
      var context = XMLHttpRequest.prototype;
      mockXhr = {
        addEventListener: utils.makeStubMethod(context, 'addEventListener'),
        open: utils.makeStubMethod(context, 'open'),
        setRequestHeader: utils.makeStubMethod(context, 'setRequestHeader'),
        send: utils.makeStubMethod(context, 'send'),
        removeEventListener: utils.makeStubMethod(
            context, 'removeEventListener')
      };
    });

    afterEach(function() {
      webHandler.destroy();
      // Reset all the method mocks.
      Y.each(mockXhr, function(value) {
        value.reset();
      });
    });

    // Ensure the progress event is correctly handled.
    var assertProgressHandled = function(progressCallback) {
      // Retrieve the registered progress handler.
      var args = mockXhr.addEventListener.allArguments();
      var progressHandler = args[0][1];
      // Set up a progress event and call the progress handler.
      var evt = {type: 'progress'};
      progressHandler(evt);
      // The progress callback has been correctly called.
      assert.strictEqual(progressCallback.callCount(), 1);
      assert.deepEqual(progressCallback.lastArguments(), [evt]);
      // The event listeners are only removed when the completed callback is
      // called.
      assert.strictEqual(mockXhr.removeEventListener.called(), false);
    };

    // Ensure the completed event is correctly handled.
    var assertCompletedHandled = function(completedCallback) {
      // Retrieve the registered handlers.
      var args = mockXhr.addEventListener.allArguments();
      var progressHandler = args[0][1];
      var completedHandler = args[1][1];
      // Set up a load event and call the completed handler.
      var evt = {type: 'load'};
      completedHandler(evt);
      // The completion callback has been correctly called.
      assert.strictEqual(completedCallback.callCount(), 1);
      assert.deepEqual(completedCallback.lastArguments(), [evt]);
      // The event listeners have been removed.
      assert.strictEqual(mockXhr.removeEventListener.callCount(), 3);
      args = mockXhr.removeEventListener.allArguments();
      assert.deepEqual(args[0], ['progress', progressHandler]);
      assert.deepEqual(args[1], ['error', completedHandler]);
      assert.deepEqual(args[2], ['load', completedHandler]);
    };

    describe('sendPostRequest', function() {

      it('opens and sends an XHR request with the proper data', function() {
        var path = '/juju-core/charms?series=trusty';
        var headers = {'Content-Type': 'application/zip'};
        var data = 'a zip file object';
        // Make a POST request.
        webHandler.sendPostRequest(
            path, headers, data, 'user', 'passwd', false,
            function() {return 'progress';}, function() {return 'completed';});
        // Ensure the xhr instance has been used properly.
        assert.strictEqual(mockXhr.addEventListener.callCount(), 3);
        // Two events listeners are added, one for request's progress and one
        // for request's completion.
        var args = mockXhr.addEventListener.allArguments();
        assert.strictEqual(args[0][0], 'progress');
        assert.strictEqual(args[1][0], 'error');
        assert.strictEqual(args[2][0], 'load');
        // The xhr is then asynchronously opened.
        assert.strictEqual(mockXhr.open.callCount(), 1);
        assert.deepEqual(mockXhr.open.lastArguments(), ['POST', path, true]);
        // Headers are properly set up.
        assert.strictEqual(mockXhr.setRequestHeader.callCount(), 2);
        args = mockXhr.setRequestHeader.allArguments();
        assert.deepEqual(args[0], ['Content-Type', 'application/zip']);
        assert.deepEqual(args[1], ['Authorization', 'Basic dXNlcjpwYXNzd2Q=']);
        // The zip file is then correctly sent.
        assert.strictEqual(mockXhr.send.callCount(), 1);
        assert.deepEqual(mockXhr.send.lastArguments(), ['a zip file object']);
        // The event listeners are only removed when the completed callback is
        // called.
        assert.strictEqual(mockXhr.removeEventListener.called(), false);
      });

      it('handles request progress', function() {
        var progressCallback = utils.makeStubFunction();
        // Make a POST request.
        webHandler.sendPostRequest(
            '/path/', {}, 'data', 'user', 'passwd', false, progressCallback);
        assertProgressHandled(progressCallback);
      });

      it('handles request completion', function() {
        var completedCallback = utils.makeStubFunction();
        // Make a POST request.
        webHandler.sendPostRequest(
            '/path/', {}, 'data', 'user', 'passwd', false,
            function() {}, completedCallback);
        assertCompletedHandled(completedCallback);
      });

    });

    describe('sendPutRequest', function() {

      it('opens and sends an XHR request with the proper data', function() {
        var path = '/juju-core/charms?series=trusty';
        var headers = {'Content-Type': 'application/zip'};
        var data = 'a zip file object';
        // Make a POST request.
        webHandler.sendPutRequest(
            path, headers, data, 'user', 'passwd', false,
            function() {return 'progress';}, function() {return 'completed';});
        // Ensure the xhr instance has been used properly.
        assert.strictEqual(mockXhr.addEventListener.callCount(), 3);
        // Two events listeners are added, one for request's progress and one
        // for request's completion.
        var args = mockXhr.addEventListener.allArguments();
        assert.strictEqual(args[0][0], 'progress');
        assert.strictEqual(args[1][0], 'error');
        assert.strictEqual(args[2][0], 'load');
        // The xhr is then asynchronously opened.
        assert.strictEqual(mockXhr.open.callCount(), 1);
        assert.deepEqual(mockXhr.open.lastArguments(), ['PUT', path, true]);
        // Headers are properly set up.
        assert.strictEqual(mockXhr.setRequestHeader.callCount(), 2);
        args = mockXhr.setRequestHeader.allArguments();
        assert.deepEqual(args[0], ['Content-Type', 'application/zip']);
        assert.deepEqual(args[1], ['Authorization', 'Basic dXNlcjpwYXNzd2Q=']);
        // The zip file is then correctly sent.
        assert.strictEqual(mockXhr.send.callCount(), 1);
        assert.deepEqual(mockXhr.send.lastArguments(), ['a zip file object']);
        // The event listeners are only removed when the completed callback is
        // called.
        assert.strictEqual(mockXhr.removeEventListener.called(), false);
      });

      it('handles request progress', function() {
        var progressCallback = utils.makeStubFunction();
        // Make a POST request.
        webHandler.sendPostRequest(
            '/path/', {}, 'data', 'user', 'passwd', false, progressCallback);
        assertProgressHandled(progressCallback);
      });

      it('handles request completion', function() {
        var completedCallback = utils.makeStubFunction();
        // Make a POST request.
        webHandler.sendPostRequest(
            '/path/', {}, 'data', 'user', 'passwd', false,
            function() {}, completedCallback);
        assertCompletedHandled(completedCallback);
      });

    });

    describe('sendGetRequest', function() {

      it('opens and sends an XHR request with the proper data', function() {
        var path = '/juju-core/charms?url=local:trusty/django-42';
        // Make a POST request.
        webHandler.sendGetRequest(
            path, null, 'user', 'passwd', false,
            function() {return 'progress';}, function() {return 'completed';});
        // Ensure the xhr instance has been used properly.
        assert.strictEqual(mockXhr.addEventListener.callCount(), 3);
        // Two events listeners are added, one for request's progress and one
        // for request's completion.
        var args = mockXhr.addEventListener.allArguments();
        assert.strictEqual(args[0][0], 'progress');
        assert.strictEqual(args[1][0], 'error');
        assert.strictEqual(args[2][0], 'load');
        // The xhr is then asynchronously opened.
        assert.strictEqual(mockXhr.open.callCount(), 1);
        assert.deepEqual(mockXhr.open.lastArguments(), ['GET', path, true]);
        // Headers are properly set up.
        assert.strictEqual(mockXhr.setRequestHeader.callCount(), 1);
        args = mockXhr.setRequestHeader.allArguments();
        assert.deepEqual(args[0], ['Authorization', 'Basic dXNlcjpwYXNzd2Q=']);
        // The zip file is then correctly sent.
        assert.strictEqual(mockXhr.send.callCount(), 1);
        assert.lengthOf(mockXhr.send.lastArguments(), 0);
        // The event listeners are only removed when the completed callback is
        // called.
        assert.strictEqual(mockXhr.removeEventListener.called(), false);
      });

      it('handles request progress', function() {
        var progressCallback = utils.makeStubFunction();
        // Make a GET request.
        webHandler.sendGetRequest(
            '/path/', {}, 'user', 'passwd', false, progressCallback);
        assertProgressHandled(progressCallback);
      });

      it('handles request completion', function() {
        var completedCallback = utils.makeStubFunction();
        // Make a GET request.
        webHandler.sendGetRequest(
            '/path/', {}, 'user', 'passwd', false,
            function() {}, completedCallback);
        assertCompletedHandled(completedCallback);
      });

    });

    it('defines a function which helps creating auth headers', function() {
      var header = webHandler._createAuthorizationHeader('myuser', 'mypasswd');
      assert.strictEqual(header, 'Basic bXl1c2VyOm15cGFzc3dk');
    });

    describe('getUrl', function() {
      it('returns a complete URL based on the given credentials', function() {
        var url = webHandler.getUrl('/my/path', 'myuser', 'mypassword');
        var expectedUrl = 'http://myuser:mypassword@' +
            window.location.host + '/my/path';
        assert.strictEqual(url, expectedUrl);
      });
    });

  });

})();
<commit_msg>Added tests for the web handler sendPatchRequest method<commit_after>/*
This file is part of the Juju GUI, which lets users view and manage Juju
environments within a graphical interface (https://launchpad.net/juju-gui).
Copyright (C) 2014 Canonical Ltd.

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License version 3, as published by
the Free Software Foundation.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero
General Public License for more details.

You should have received a copy of the GNU Affero General Public License along
with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

'use strict';

(function() {

  describe('Web handler', function() {
    var mockXhr, utils, webHandler, webModule, Y;
    var requirements = ['juju-env-web-handler', 'juju-tests-utils'];

    before(function(done) {
      // Set up the YUI instance, the test utils and the web namespace.
      Y = YUI(GlobalConfig).use(requirements, function(Y) {
        utils = Y.namespace('juju-tests.utils');
        webModule = Y.namespace('juju.environments.web');
        done();
      });
    });

    beforeEach(function() {
      // Instantiate a web handler and set up an XMLHttpRequest mock.
      webHandler = new webModule.WebHandler();
      var context = XMLHttpRequest.prototype;
      mockXhr = {
        addEventListener: utils.makeStubMethod(context, 'addEventListener'),
        open: utils.makeStubMethod(context, 'open'),
        setRequestHeader: utils.makeStubMethod(context, 'setRequestHeader'),
        send: utils.makeStubMethod(context, 'send'),
        removeEventListener: utils.makeStubMethod(
            context, 'removeEventListener')
      };
    });

    afterEach(function() {
      webHandler.destroy();
      // Reset all the method mocks.
      Y.each(mockXhr, function(value) {
        value.reset();
      });
    });

    // Ensure the progress event is correctly handled.
    var assertProgressHandled = function(progressCallback) {
      // Retrieve the registered progress handler.
      var args = mockXhr.addEventListener.allArguments();
      var progressHandler = args[0][1];
      // Set up a progress event and call the progress handler.
      var evt = {type: 'progress'};
      progressHandler(evt);
      // The progress callback has been correctly called.
      assert.strictEqual(progressCallback.callCount(), 1);
      assert.deepEqual(progressCallback.lastArguments(), [evt]);
      // The event listeners are only removed when the completed callback is
      // called.
      assert.strictEqual(mockXhr.removeEventListener.called(), false);
    };

    // Ensure the completed event is correctly handled.
    var assertCompletedHandled = function(completedCallback) {
      // Retrieve the registered handlers.
      var args = mockXhr.addEventListener.allArguments();
      var progressHandler = args[0][1];
      var completedHandler = args[1][1];
      // Set up a load event and call the completed handler.
      var evt = {type: 'load'};
      completedHandler(evt);
      // The completion callback has been correctly called.
      assert.strictEqual(completedCallback.callCount(), 1);
      assert.deepEqual(completedCallback.lastArguments(), [evt]);
      // The event listeners have been removed.
      assert.strictEqual(mockXhr.removeEventListener.callCount(), 3);
      args = mockXhr.removeEventListener.allArguments();
      assert.deepEqual(args[0], ['progress', progressHandler]);
      assert.deepEqual(args[1], ['error', completedHandler]);
      assert.deepEqual(args[2], ['load', completedHandler]);
    };

    describe('sendPostRequest', function() {

      it('opens and sends an XHR request with the proper data', function() {
        var path = '/juju-core/charms?series=trusty';
        var headers = {'Content-Type': 'application/zip'};
        var data = 'a zip file object';
        // Make a POST request.
        webHandler.sendPostRequest(
            path, headers, data, 'user', 'passwd', false,
            function() {return 'progress';}, function() {return 'completed';});
        // Ensure the xhr instance has been used properly.
        assert.strictEqual(mockXhr.addEventListener.callCount(), 3);
        // Two events listeners are added, one for request's progress and one
        // for request's completion.
        var args = mockXhr.addEventListener.allArguments();
        assert.strictEqual(args[0][0], 'progress');
        assert.strictEqual(args[1][0], 'error');
        assert.strictEqual(args[2][0], 'load');
        // The xhr is then asynchronously opened.
        assert.strictEqual(mockXhr.open.callCount(), 1);
        assert.deepEqual(mockXhr.open.lastArguments(), ['POST', path, true]);
        // Headers are properly set up.
        assert.strictEqual(mockXhr.setRequestHeader.callCount(), 2);
        args = mockXhr.setRequestHeader.allArguments();
        assert.deepEqual(args[0], ['Content-Type', 'application/zip']);
        assert.deepEqual(args[1], ['Authorization', 'Basic dXNlcjpwYXNzd2Q=']);
        // The zip file is then correctly sent.
        assert.strictEqual(mockXhr.send.callCount(), 1);
        assert.deepEqual(mockXhr.send.lastArguments(), ['a zip file object']);
        // The event listeners are only removed when the completed callback is
        // called.
        assert.strictEqual(mockXhr.removeEventListener.called(), false);
      });

      it('handles request progress', function() {
        var progressCallback = utils.makeStubFunction();
        // Make a POST request.
        webHandler.sendPostRequest(
            '/path/', {}, 'data', 'user', 'passwd', false, progressCallback);
        assertProgressHandled(progressCallback);
      });

      it('handles request completion', function() {
        var completedCallback = utils.makeStubFunction();
        // Make a POST request.
        webHandler.sendPostRequest(
            '/path/', {}, 'data', 'user', 'passwd', false,
            function() {}, completedCallback);
        assertCompletedHandled(completedCallback);
      });

    });

    describe('sendPutRequest', function() {

      it('opens and sends an XHR request with the proper data', function() {
        var path = '/juju-core/charms?series=trusty';
        var headers = {'Content-Type': 'application/zip'};
        var data = 'a zip file object';
        // Make a POST request.
        webHandler.sendPutRequest(
            path, headers, data, 'user', 'passwd', false,
            function() {return 'progress';}, function() {return 'completed';});
        // Ensure the xhr instance has been used properly.
        assert.strictEqual(mockXhr.addEventListener.callCount(), 3);
        // Two events listeners are added, one for request's progress and one
        // for request's completion.
        var args = mockXhr.addEventListener.allArguments();
        assert.strictEqual(args[0][0], 'progress');
        assert.strictEqual(args[1][0], 'error');
        assert.strictEqual(args[2][0], 'load');
        // The xhr is then asynchronously opened.
        assert.strictEqual(mockXhr.open.callCount(), 1);
        assert.deepEqual(mockXhr.open.lastArguments(), ['PUT', path, true]);
        // Headers are properly set up.
        assert.strictEqual(mockXhr.setRequestHeader.callCount(), 2);
        args = mockXhr.setRequestHeader.allArguments();
        assert.deepEqual(args[0], ['Content-Type', 'application/zip']);
        assert.deepEqual(args[1], ['Authorization', 'Basic dXNlcjpwYXNzd2Q=']);
        // The zip file is then correctly sent.
        assert.strictEqual(mockXhr.send.callCount(), 1);
        assert.deepEqual(mockXhr.send.lastArguments(), ['a zip file object']);
        // The event listeners are only removed when the completed callback is
        // called.
        assert.strictEqual(mockXhr.removeEventListener.called(), false);
      });

      it('handles request progress', function() {
        var progressCallback = utils.makeStubFunction();
        // Make a POST request.
        webHandler.sendPutRequest(
            '/path/', {}, 'data', 'user', 'passwd', false, progressCallback);
        assertProgressHandled(progressCallback);
      });

      it('handles request completion', function() {
        var completedCallback = utils.makeStubFunction();
        // Make a POST request.
        webHandler.sendPutRequest(
            '/path/', {}, 'data', 'user', 'passwd', false,
            function() {}, completedCallback);
        assertCompletedHandled(completedCallback);
      });

    });

    describe('sendGetRequest', function() {

      it('opens and sends an XHR request with the proper data', function() {
        var path = '/juju-core/charms?url=local:trusty/django-42';
        // Make a GET request.
        webHandler.sendGetRequest(
            path, null, 'user', 'passwd', false,
            function() {return 'progress';}, function() {return 'completed';});
        // Ensure the xhr instance has been used properly.
        assert.strictEqual(mockXhr.addEventListener.callCount(), 3);
        // Two events listeners are added, one for request's progress and one
        // for request's completion.
        var args = mockXhr.addEventListener.allArguments();
        assert.strictEqual(args[0][0], 'progress');
        assert.strictEqual(args[1][0], 'error');
        assert.strictEqual(args[2][0], 'load');
        // The xhr is then asynchronously opened.
        assert.strictEqual(mockXhr.open.callCount(), 1);
        assert.deepEqual(mockXhr.open.lastArguments(), ['GET', path, true]);
        // Headers are properly set up.
        assert.strictEqual(mockXhr.setRequestHeader.callCount(), 1);
        args = mockXhr.setRequestHeader.allArguments();
        assert.deepEqual(args[0], ['Authorization', 'Basic dXNlcjpwYXNzd2Q=']);
        // The zip file is then correctly sent.
        assert.strictEqual(mockXhr.send.callCount(), 1);
        assert.lengthOf(mockXhr.send.lastArguments(), 0);
        // The event listeners are only removed when the completed callback is
        // called.
        assert.strictEqual(mockXhr.removeEventListener.called(), false);
      });

      it('handles request progress', function() {
        var progressCallback = utils.makeStubFunction();
        // Make a GET request.
        webHandler.sendGetRequest(
            '/path/', {}, 'user', 'passwd', false, progressCallback);
        assertProgressHandled(progressCallback);
      });

      it('handles request completion', function() {
        var completedCallback = utils.makeStubFunction();
        // Make a GET request.
        webHandler.sendGetRequest(
            '/path/', {}, 'user', 'passwd', false,
            function() {}, completedCallback);
        assertCompletedHandled(completedCallback);
      });

    });

    describe('sendPatchRequest', function() {

      it('opens and sends an XHR request with the proper data', function() {
        var path = '/juju-core/charms?series=trusty';
        var headers = {'Content-Type': 'application/zip'};
        var data = 'a zip file object';
        // Make a POST request.
        webHandler.sendPatchRequest(
            path, headers, data, 'user', 'passwd', false,
            function() {return 'progress';}, function() {return 'completed';});
        // Ensure the xhr instance has been used properly.
        assert.strictEqual(mockXhr.addEventListener.callCount(), 3);
        // Two events listeners are added, one for request's progress and one
        // for request's completion.
        var args = mockXhr.addEventListener.allArguments();
        assert.strictEqual(args[0][0], 'progress');
        assert.strictEqual(args[1][0], 'error');
        assert.strictEqual(args[2][0], 'load');
        // The xhr is then asynchronously opened.
        assert.strictEqual(mockXhr.open.callCount(), 1);
        assert.deepEqual(mockXhr.open.lastArguments(), ['PATCH', path, true]);
        // Headers are properly set up.
        assert.strictEqual(mockXhr.setRequestHeader.callCount(), 2);
        args = mockXhr.setRequestHeader.allArguments();
        assert.deepEqual(args[0], ['Content-Type', 'application/zip']);
        assert.deepEqual(args[1], ['Authorization', 'Basic dXNlcjpwYXNzd2Q=']);
        // The zip file is then correctly sent.
        assert.strictEqual(mockXhr.send.callCount(), 1);
        assert.deepEqual(mockXhr.send.lastArguments(), ['a zip file object']);
        // The event listeners are only removed when the completed callback is
        // called.
        assert.strictEqual(mockXhr.removeEventListener.called(), false);
      });

      it('handles request progress', function() {
        var progressCallback = utils.makeStubFunction();
        // Make a POST request.
        webHandler.sendPatchRequest(
            '/path/', {}, 'data', 'user', 'passwd', false, progressCallback);
        assertProgressHandled(progressCallback);
      });

      it('handles request completion', function() {
        var completedCallback = utils.makeStubFunction();
        // Make a POST request.
        webHandler.sendPatchRequest(
            '/path/', {}, 'data', 'user', 'passwd', false,
            function() {}, completedCallback);
        assertCompletedHandled(completedCallback);
      });
    });

    it('defines a function which helps creating auth headers', function() {
      var header = webHandler._createAuthorizationHeader('myuser', 'mypasswd');
      assert.strictEqual(header, 'Basic bXl1c2VyOm15cGFzc3dk');
    });

    describe('getUrl', function() {
      it('returns a complete URL based on the given credentials', function() {
        var url = webHandler.getUrl('/my/path', 'myuser', 'mypassword');
        var expectedUrl = 'http://myuser:mypassword@' +
            window.location.host + '/my/path';
        assert.strictEqual(url, expectedUrl);
      });
    });

  });

})();
<|endoftext|>


<commit_before>/*!
 * @license choco.js Copyright(c) 2015 sasa+1
 * https://github.com/sasaplus1/choco.js
 * Released under the MIT license.
 */

/**
 * export to AMD/CommonJS/global.
 *
 * @param {Object} global global object.
 * @param {Function} factory factory method.
 */
(function(global, factory){
  'use strict';

  if (typeof define === 'function' && define.amd) {
    define(factory);
  } else if (typeof exports === 'object') {
    module.exports = factory();
  } else {
    global.choco = factory();
  }
}((this || 0).self || global, function(){
  'use strict';

  var ID = '__choco_id',
      MAX_SAFE_INTEGER = (!Number.MAX_SAFE_INTEGER) ?
         Math.pow(2, 53) - 1 : Number.MAX_SAFE_INTEGER;

  var successSuffix = '-success',
      failureSuffix = '-failure';

  var warn = (function(){
    if (typeof console !== 'undefined') {
      if (typeof console.warn === 'object') {
        // IE8, IE9
        return function() {
          Function.prototype.apply.call(console.warn, console, arguments);
        };
      } else {
        // modern browsers
        return console.warn.bind(console);
      }
    } else {
      // old browsers and others
      return function() {};
    }
  }());

  /**
   * convert to Promise from EventEmitter.
   *
   * @param {EventEmitter} emitter emitter instance.
   * @param {String} event event name.
   * @param {Object} params argument object for emitter.
   */
  function choco(emitter, event, params) {
    var paramsType = typeof params;

    if (paramsType !== 'undefined' && paramsType !== 'object') {
      throw new TypeError('params must be an Object');
    }

    if (paramsType === 'object' && typeof params[ID] !== 'undefined') {
      throw new Error(ID + ' is reserved');
    }

    return new Promise(function(resolve, reject) {
      var id = Math.floor(Math.random() * MAX_SAFE_INTEGER),
          successEvent = event + successSuffix,
          failureEvent = event + failureSuffix,
          onSuccess, onFailure;

      if (paramsType === 'undefined') {
        params = {};
      }
      params[ID] = id;

      emitter.on(successEvent, onSuccess = function(result) {
        if (typeof result !== 'object') {
          return warn('result is not an Object');
        }
        if (typeof result[ID] !== 'number') {
          return warn(ID + ' is not a Number');
        }

        if (result[ID] !== id) {
          return;
        }

        emitter.removeListener(successEvent, onSuccess);
        emitter.removeListener(failureEvent, onFailure);

        // FIXME
        delete result[ID];

        resolve(result);
      });
      emitter.on(failureEvent, onFailure = function(result) {
        if (typeof result !== 'object') {
          return warn('result is not an Object');
        }
        if (typeof result[ID] !== 'number') {
          return warn(ID + ' is not a Number');
        }

        if (result[ID] !== id) {
          return;
        }

        emitter.removeListener(successEvent, onSuccess);
        emitter.removeListener(failureEvent, onFailure);

        // FIXME
        delete result[ID];

        reject(result);
      });

      emitter.emit(event, params);
    });
  }

  return choco;
}));
<commit_msg>can change trigger method name<commit_after>/*!
 * @license choco.js Copyright(c) 2015 sasa+1
 * https://github.com/sasaplus1/choco.js
 * Released under the MIT license.
 */

/**
 * export to AMD/CommonJS/global.
 *
 * @param {Object} global global object.
 * @param {Function} factory factory method.
 */
(function(global, factory){
  'use strict';

  if (typeof define === 'function' && define.amd) {
    define(factory);
  } else if (typeof exports === 'object') {
    module.exports = factory();
  } else {
    global.choco = factory();
  }
}((this || 0).self || global, function(){
  'use strict';

  var ID = '__choco_id',
      MAX_SAFE_INTEGER = (!Number.MAX_SAFE_INTEGER) ?
         Math.pow(2, 53) - 1 : Number.MAX_SAFE_INTEGER;

  var successSuffix = '-success',
      failureSuffix = '-failure';

  var warn = (function(){
    if (typeof console !== 'undefined') {
      if (typeof console.warn === 'object') {
        // IE8, IE9
        return function() {
          Function.prototype.apply.call(console.warn, console, arguments);
        };
      } else {
        // modern browsers
        return console.warn.bind(console);
      }
    } else {
      // old browsers and others
      return function() {};
    }
  }());

  /**
   * convert to Promise from EventEmitter.
   *
   * @param {EventEmitter} emitter emitter instance.
   * @param {String} event event name.
   * @param {Object} params argument object for emitter.
   */
  function choco(emitter, event, params) {
    var paramsType = typeof params;

    if (paramsType !== 'undefined' && paramsType !== 'object') {
      throw new TypeError('params must be an Object');
    }

    if (paramsType === 'object' && typeof params[ID] !== 'undefined') {
      throw new Error(ID + ' is reserved');
    }

    return new Promise(function(resolve, reject) {
      var id = Math.floor(Math.random() * MAX_SAFE_INTEGER),
          successEvent = event + successSuffix,
          failureEvent = event + failureSuffix,
          onSuccess, onFailure;

      if (paramsType === 'undefined') {
        params = {};
      }
      params[ID] = id;

      emitter.on(successEvent, onSuccess = function(result) {
        if (typeof result !== 'object') {
          return warn('result is not an Object');
        }
        if (typeof result[ID] !== 'number') {
          return warn(ID + ' is not a Number');
        }

        if (result[ID] !== id) {
          return;
        }

        emitter.removeListener(successEvent, onSuccess);
        emitter.removeListener(failureEvent, onFailure);

        // FIXME
        delete result[ID];

        resolve(result);
      });
      emitter.on(failureEvent, onFailure = function(result) {
        if (typeof result !== 'object') {
          return warn('result is not an Object');
        }
        if (typeof result[ID] !== 'number') {
          return warn(ID + ' is not a Number');
        }

        if (result[ID] !== id) {
          return;
        }

        emitter.removeListener(successEvent, onSuccess);
        emitter.removeListener(failureEvent, onFailure);

        // FIXME
        delete result[ID];

        reject(result);
      });

      emitter[choco.trigger](event, params);
    });
  }

  // trigger method name
  choco.trigger = 'emit';

  return choco;
}));
<|endoftext|>


<commit_before>/*jslint node: true */
"use strict";
var async = require('async');
var objectHash = require("./object_hash.js");
var constants = require("./constants.js");
var paid_witnessing = require("./paid_witnessing.js");
var headers_commission = require("./headers_commission.js");
var mc_outputs = require("./mc_outputs.js");

var TRANSFER_INPUT_SIZE = 0 // type: "transfer" omitted
	+ 44 // unit
	+ 8 // message_index
	+ 8; // output_index
var TRANSFER_INPUT_KEYS_SIZE = "unit".length + "message_index".length + "output_index".length;

var HEADERS_COMMISSION_INPUT_SIZE = 18 // type: "headers_commission"
	+ 8 // from_main_chain_index
	+ 8; // to_main_chain_index
var HEADERS_COMMISSION_INPUT_KEYS_SIZE = "type".length + "from_main_chain_index".length + "to_main_chain_index".length;

var WITNESSING_INPUT_SIZE = 10 // type: "witnessing"
	+ 8 // from_main_chain_index
	+ 8; // to_main_chain_index
var WITNESSING_INPUT_KEYS_SIZE = "type".length + "from_main_chain_index".length + "to_main_chain_index".length;

var ADDRESS_SIZE = 32;
var ADDRESS_KEY_SIZE = "address".length;

// bMultiAuthored includes all addresses, not just those that pay
// arrAddresses is paying addresses
// spend_unconfirmed is one of: none, all, own
function pickDivisibleCoinsForAmount(conn, objAsset, arrAddresses, last_ball_mci, amount, bMultiAuthored, spend_unconfirmed, onDone){
	var asset = objAsset ? objAsset.asset : null;
	console.log("pick coins in "+asset+" for amount "+amount+" with spend_unconfirmed "+spend_unconfirmed);
	var is_base = objAsset ? 0 : 1;
	var bWithKeys = (last_ball_mci >= constants.includeKeySizesUpgradeMci);
	var transfer_input_size = is_base * (TRANSFER_INPUT_SIZE + (bWithKeys ? TRANSFER_INPUT_KEYS_SIZE : 0));
	var arrInputsWithProofs = [];
	var total_amount = 0;
	var required_amount = amount;

	if (!(typeof last_ball_mci === 'number' && last_ball_mci >= 0))
		throw Error("invalid last_ball_mci: "+last_ball_mci);
	var confirmation_condition;
	if (spend_unconfirmed === 'none')
		confirmation_condition = 'AND main_chain_index<='+last_ball_mci;
	else if (spend_unconfirmed === 'all')
		confirmation_condition = '';
	else if (spend_unconfirmed === 'own')
		confirmation_condition = 'AND ( main_chain_index<='+last_ball_mci+' OR EXISTS ( \n\
			SELECT 1 FROM unit_authors CROSS JOIN my_addresses USING(address) WHERE unit_authors.unit=outputs.unit \n\
			UNION \n\
			SELECT 1 FROM unit_authors CROSS JOIN shared_addresses ON address=shared_address WHERE unit_authors.unit=outputs.unit \n\
			UNION \n\
			SELECT 1 FROM unit_authors WHERE unit_authors.unit=outputs.unit AND unit_authors.address IN(' + arrAddresses.map(conn.escape).join(', ') + ')\n\
		) )';
	else
		throw Error("invalid spend_unconfirmed="+spend_unconfirmed);

	// adds element to arrInputsWithProofs
	function addInput(input){
		total_amount += input.amount;
		var objInputWithProof = {input: input};
		if (objAsset && objAsset.is_private){ // for type=payment only
			var spend_proof = objectHash.getBase64Hash({
				asset: asset,
				amount: input.amount,
				address: input.address,
				unit: input.unit,
				message_index: input.message_index,
				output_index: input.output_index,
				blinding: input.blinding
			});
			var objSpendProof = {spend_proof: spend_proof};
			if (bMultiAuthored)
				objSpendProof.address = input.address;
			objInputWithProof.spend_proof = objSpendProof;
		}
		if (!bMultiAuthored || !input.type)
			delete input.address;
		delete input.amount;
		delete input.blinding;
		arrInputsWithProofs.push(objInputWithProof);
	}

	// first, try to find a coin just bigger than the required amount
	function pickOneCoinJustBiggerAndContinue(){
		if (amount === Infinity)
			return pickMultipleCoinsAndContinue();
		var more = is_base ? '>' : '>=';
		conn.query(
			"SELECT unit, message_index, output_index, amount, blinding, address \n\
			FROM outputs \n\
			CROSS JOIN units USING(unit) \n\
			WHERE address IN(?) AND asset"+(asset ? "="+conn.escape(asset) : " IS NULL")+" AND is_spent=0 AND amount "+more+" ? \n\
				AND sequence='good' "+confirmation_condition+" \n\
			ORDER BY is_stable DESC, amount LIMIT 1",
			[arrSpendableAddresses, amount+transfer_input_size],
			function(rows){
				if (rows.length === 1){
					var input = rows[0];
					// default type is "transfer"
					addInput(input);
					onDone(arrInputsWithProofs, total_amount);
				}
				else
					pickMultipleCoinsAndContinue();
			}
		);
	}

	// then, try to add smaller coins until we accumulate the target amount
	function pickMultipleCoinsAndContinue(){
		conn.query(
			"SELECT unit, message_index, output_index, amount, address, blinding \n\
			FROM outputs \n\
			CROSS JOIN units USING(unit) \n\
			WHERE address IN(?) AND asset"+(asset ? "="+conn.escape(asset) : " IS NULL")+" AND is_spent=0 \n\
				AND sequence='good' "+confirmation_condition+"  \n\
			ORDER BY amount DESC LIMIT ?",
			[arrSpendableAddresses, constants.MAX_INPUTS_PER_PAYMENT_MESSAGE-2],
			function(rows){
				async.eachSeries(
					rows,
					function(row, cb){
						var input = row;
						objectHash.cleanNulls(input);
						required_amount += transfer_input_size;
						addInput(input);
						// if we allow equality, we might get 0 amount for change which is invalid
						var bFound = is_base ? (total_amount > required_amount) : (total_amount >= required_amount);
						bFound ? cb('found') : cb();
					},
					function(err){
						if (err === 'found')
							onDone(arrInputsWithProofs, total_amount);
						else if (asset)
							issueAsset();
						else
							addHeadersCommissionInputs();
					}
				);
			}
		);
	}

	function addHeadersCommissionInputs(){
		addMcInputs("headers_commission", HEADERS_COMMISSION_INPUT_SIZE + (bWithKeys ? HEADERS_COMMISSION_INPUT_KEYS_SIZE : 0),
			headers_commission.getMaxSpendableMciForLastBallMci(last_ball_mci), addWitnessingInputs);
	}

	function addWitnessingInputs(){
		addMcInputs("witnessing", WITNESSING_INPUT_SIZE + (bWithKeys ? WITNESSING_INPUT_KEYS_SIZE : 0), paid_witnessing.getMaxSpendableMciForLastBallMci(last_ball_mci), issueAsset);
	}

	function addMcInputs(type, input_size, max_mci, onStillNotEnough){
		var address_size = ADDRESS_SIZE + (bWithKeys ? ADDRESS_KEY_SIZE : 0);
		async.eachSeries(
			arrAddresses,
			function(address, cb){
				var target_amount = required_amount + input_size + (bMultiAuthored ? address_size : 0) - total_amount;
				mc_outputs.findMcIndexIntervalToTargetAmount(conn, type, address, max_mci, target_amount, {
					ifNothing: cb,
					ifFound: function(from_mc_index, to_mc_index, earnings, bSufficient){
						if (earnings === 0)
							throw Error("earnings === 0");
						total_amount += earnings;
						var input = {
							type: type,
							from_main_chain_index: from_mc_index,
							to_main_chain_index: to_mc_index
						};
						var full_input_size = input_size;
						if (bMultiAuthored){
							full_input_size += address_size; // address length
							input.address = address;
						}
						required_amount += full_input_size;
						arrInputsWithProofs.push({input: input});
						(total_amount > required_amount)
							? cb("found") // break eachSeries
							: cb(); // try next address
					}
				});
			},
			function(err){
				if (!err)
					console.log(arrAddresses+" "+type+": got only "+total_amount+" out of required "+required_amount);
				(err === "found") ? onDone(arrInputsWithProofs, total_amount) : onStillNotEnough();
			}
		);
	}

	function issueAsset(){
		if (!asset)
			return finish();
		else{
			if (amount === Infinity && !objAsset.cap) // don't try to create infinite issue
				return onDone(null);
		}
		console.log("will try to issue asset "+asset);
		// for issue, we use full list of addresses rather than spendable addresses
		if (objAsset.issued_by_definer_only && arrAddresses.indexOf(objAsset.definer_address) === -1)
			return finish();
		var issuer_address = objAsset.issued_by_definer_only ? objAsset.definer_address : arrAddresses[0];
		var issue_amount = objAsset.cap || (required_amount - total_amount) || 1; // 1 currency unit in case required_amount = total_amount

		function addIssueInput(serial_number){
			total_amount += issue_amount;
			var input = {
				type: "issue",
				amount: issue_amount,
				serial_number: serial_number
			};
			if (bMultiAuthored)
				input.address = issuer_address;
			var objInputWithProof = {input: input};
			if (objAsset && objAsset.is_private){
				var spend_proof = objectHash.getBase64Hash({
					asset: asset,
					amount: issue_amount,
					denomination: 1,
					address: issuer_address,
					serial_number: serial_number
				});
				var objSpendProof = {spend_proof: spend_proof};
				if (bMultiAuthored)
					objSpendProof.address = input.address;
				objInputWithProof.spend_proof = objSpendProof;
			}
			arrInputsWithProofs.unshift(objInputWithProof);
			var bFound = is_base ? (total_amount > required_amount) : (total_amount >= required_amount);
			bFound ? onDone(arrInputsWithProofs, total_amount) : finish();
		}

		if (objAsset.cap){
			conn.query("SELECT 1 FROM inputs WHERE type='issue' AND asset=?", [asset], function(rows){
				if (rows.length > 0) // already issued
					return finish();
				addIssueInput(1);
			});
		}
		else{
			conn.query(
				"SELECT MAX(serial_number) AS max_serial_number FROM inputs WHERE type='issue' AND asset=? AND address=?",
				[asset, issuer_address],
				function(rows){
					var max_serial_number = (rows.length === 0) ? 0 : rows[0].max_serial_number;
					addIssueInput(max_serial_number+1);
				}
			);
		}
	}

	function finish(){
		if (amount === Infinity && arrInputsWithProofs.length > 0)
			onDone(arrInputsWithProofs, total_amount);
		else
			onDone(null);
	}

	var arrSpendableAddresses = arrAddresses.concat(); // cloning
	if (objAsset && objAsset.auto_destroy){
		var i = arrAddresses.indexOf(objAsset.definer_address);
		if (i>=0)
			arrSpendableAddresses.splice(i, 1);
	}
	if (arrSpendableAddresses.length > 0)
		pickOneCoinJustBiggerAndContinue();
	else
		issueAsset();
}

function getConfirmationConditionSql(spend_unconfirmed){
	if (spend_unconfirmed === 'none')
		return 'AND is_stable=1';
	else if (spend_unconfirmed === 'all')
		return '';
	else if (spend_unconfirmed === 'own')
		return 'AND ( is_stable=1 OR EXISTS ( \n\
			SELECT 1 FROM unit_authors CROSS JOIN my_addresses USING(address) WHERE unit_authors.unit=outputs.unit \n\
			UNION \n\
			SELECT 1 FROM unit_authors CROSS JOIN shared_addresses ON address=shared_address WHERE unit_authors.unit=outputs.unit \n\
		) )';
	else
		throw Error("invalid spend_unconfirmed="+spend_unconfirmed);

}

exports.pickDivisibleCoinsForAmount = pickDivisibleCoinsForAmount;
exports.getConfirmationConditionSql = getConfirmationConditionSql;
<commit_msg>simplified<commit_after>/*jslint node: true */
"use strict";
var async = require('async');
var objectHash = require("./object_hash.js");
var constants = require("./constants.js");
var paid_witnessing = require("./paid_witnessing.js");
var headers_commission = require("./headers_commission.js");
var mc_outputs = require("./mc_outputs.js");

var TRANSFER_INPUT_SIZE = 0 // type: "transfer" omitted
	+ 44 // unit
	+ 8 // message_index
	+ 8; // output_index
var TRANSFER_INPUT_KEYS_SIZE = "unit".length + "message_index".length + "output_index".length;

var HEADERS_COMMISSION_INPUT_SIZE = 18 // type: "headers_commission"
	+ 8 // from_main_chain_index
	+ 8; // to_main_chain_index
var HEADERS_COMMISSION_INPUT_KEYS_SIZE = "type".length + "from_main_chain_index".length + "to_main_chain_index".length;

var WITNESSING_INPUT_SIZE = 10 // type: "witnessing"
	+ 8 // from_main_chain_index
	+ 8; // to_main_chain_index
var WITNESSING_INPUT_KEYS_SIZE = "type".length + "from_main_chain_index".length + "to_main_chain_index".length;

var ADDRESS_SIZE = 32;
var ADDRESS_KEY_SIZE = "address".length;

// bMultiAuthored includes all addresses, not just those that pay
// arrAddresses is paying addresses
// spend_unconfirmed is one of: none, all, own
function pickDivisibleCoinsForAmount(conn, objAsset, arrAddresses, last_ball_mci, amount, bMultiAuthored, spend_unconfirmed, onDone){
	var asset = objAsset ? objAsset.asset : null;
	console.log("pick coins in "+asset+" for amount "+amount+" with spend_unconfirmed "+spend_unconfirmed);
	var is_base = objAsset ? 0 : 1;
	var bWithKeys = (last_ball_mci >= constants.includeKeySizesUpgradeMci);
	var transfer_input_size = is_base ? (TRANSFER_INPUT_SIZE + (bWithKeys ? TRANSFER_INPUT_KEYS_SIZE : 0)) : 0;
	var arrInputsWithProofs = [];
	var total_amount = 0;
	var required_amount = amount;

	if (!(typeof last_ball_mci === 'number' && last_ball_mci >= 0))
		throw Error("invalid last_ball_mci: "+last_ball_mci);
	var confirmation_condition;
	if (spend_unconfirmed === 'none')
		confirmation_condition = 'AND main_chain_index<='+last_ball_mci;
	else if (spend_unconfirmed === 'all')
		confirmation_condition = '';
	else if (spend_unconfirmed === 'own')
		confirmation_condition = 'AND ( main_chain_index<='+last_ball_mci+' OR EXISTS ( \n\
			SELECT 1 FROM unit_authors CROSS JOIN my_addresses USING(address) WHERE unit_authors.unit=outputs.unit \n\
			UNION \n\
			SELECT 1 FROM unit_authors CROSS JOIN shared_addresses ON address=shared_address WHERE unit_authors.unit=outputs.unit \n\
			UNION \n\
			SELECT 1 FROM unit_authors WHERE unit_authors.unit=outputs.unit AND unit_authors.address IN(' + arrAddresses.map(conn.escape).join(', ') + ')\n\
		) )';
	else
		throw Error("invalid spend_unconfirmed="+spend_unconfirmed);

	// adds element to arrInputsWithProofs
	function addInput(input){
		total_amount += input.amount;
		var objInputWithProof = {input: input};
		if (objAsset && objAsset.is_private){ // for type=payment only
			var spend_proof = objectHash.getBase64Hash({
				asset: asset,
				amount: input.amount,
				address: input.address,
				unit: input.unit,
				message_index: input.message_index,
				output_index: input.output_index,
				blinding: input.blinding
			});
			var objSpendProof = {spend_proof: spend_proof};
			if (bMultiAuthored)
				objSpendProof.address = input.address;
			objInputWithProof.spend_proof = objSpendProof;
		}
		if (!bMultiAuthored || !input.type)
			delete input.address;
		delete input.amount;
		delete input.blinding;
		arrInputsWithProofs.push(objInputWithProof);
	}

	// first, try to find a coin just bigger than the required amount
	function pickOneCoinJustBiggerAndContinue(){
		if (amount === Infinity)
			return pickMultipleCoinsAndContinue();
		var more = is_base ? '>' : '>=';
		conn.query(
			"SELECT unit, message_index, output_index, amount, blinding, address \n\
			FROM outputs \n\
			CROSS JOIN units USING(unit) \n\
			WHERE address IN(?) AND asset"+(asset ? "="+conn.escape(asset) : " IS NULL")+" AND is_spent=0 AND amount "+more+" ? \n\
				AND sequence='good' "+confirmation_condition+" \n\
			ORDER BY is_stable DESC, amount LIMIT 1",
			[arrSpendableAddresses, amount+transfer_input_size],
			function(rows){
				if (rows.length === 1){
					var input = rows[0];
					// default type is "transfer"
					addInput(input);
					onDone(arrInputsWithProofs, total_amount);
				}
				else
					pickMultipleCoinsAndContinue();
			}
		);
	}

	// then, try to add smaller coins until we accumulate the target amount
	function pickMultipleCoinsAndContinue(){
		conn.query(
			"SELECT unit, message_index, output_index, amount, address, blinding \n\
			FROM outputs \n\
			CROSS JOIN units USING(unit) \n\
			WHERE address IN(?) AND asset"+(asset ? "="+conn.escape(asset) : " IS NULL")+" AND is_spent=0 \n\
				AND sequence='good' "+confirmation_condition+"  \n\
			ORDER BY amount DESC LIMIT ?",
			[arrSpendableAddresses, constants.MAX_INPUTS_PER_PAYMENT_MESSAGE-2],
			function(rows){
				async.eachSeries(
					rows,
					function(row, cb){
						var input = row;
						objectHash.cleanNulls(input);
						required_amount += transfer_input_size;
						addInput(input);
						// if we allow equality, we might get 0 amount for change which is invalid
						var bFound = is_base ? (total_amount > required_amount) : (total_amount >= required_amount);
						bFound ? cb('found') : cb();
					},
					function(err){
						if (err === 'found')
							onDone(arrInputsWithProofs, total_amount);
						else if (asset)
							issueAsset();
						else
							addHeadersCommissionInputs();
					}
				);
			}
		);
	}

	function addHeadersCommissionInputs(){
		addMcInputs("headers_commission", HEADERS_COMMISSION_INPUT_SIZE + (bWithKeys ? HEADERS_COMMISSION_INPUT_KEYS_SIZE : 0),
			headers_commission.getMaxSpendableMciForLastBallMci(last_ball_mci), addWitnessingInputs);
	}

	function addWitnessingInputs(){
		addMcInputs("witnessing", WITNESSING_INPUT_SIZE + (bWithKeys ? WITNESSING_INPUT_KEYS_SIZE : 0), paid_witnessing.getMaxSpendableMciForLastBallMci(last_ball_mci), issueAsset);
	}

	function addMcInputs(type, input_size, max_mci, onStillNotEnough){
		var address_size = ADDRESS_SIZE + (bWithKeys ? ADDRESS_KEY_SIZE : 0);
		var full_input_size = input_size + (bMultiAuthored ? address_size : 0);
		async.eachSeries(
			arrAddresses,
			function(address, cb){
				var target_amount = required_amount + full_input_size - total_amount;
				mc_outputs.findMcIndexIntervalToTargetAmount(conn, type, address, max_mci, target_amount, {
					ifNothing: cb,
					ifFound: function(from_mc_index, to_mc_index, earnings, bSufficient){
						if (earnings === 0)
							throw Error("earnings === 0");
						var input = {
							type: type,
							from_main_chain_index: from_mc_index,
							to_main_chain_index: to_mc_index
						};
						if (bMultiAuthored)
							input.address = address;
						total_amount += earnings;
						required_amount += full_input_size;
						arrInputsWithProofs.push({input: input});
						(total_amount > required_amount)
							? cb("found") // break eachSeries
							: cb(); // try next address
					}
				});
			},
			function(err){
				if (!err)
					console.log(arrAddresses+" "+type+": got only "+total_amount+" out of required "+required_amount);
				(err === "found") ? onDone(arrInputsWithProofs, total_amount) : onStillNotEnough();
			}
		);
	}

	function issueAsset(){
		if (!asset)
			return finish();
		else{
			if (amount === Infinity && !objAsset.cap) // don't try to create infinite issue
				return onDone(null);
		}
		console.log("will try to issue asset "+asset);
		// for issue, we use full list of addresses rather than spendable addresses
		if (objAsset.issued_by_definer_only && arrAddresses.indexOf(objAsset.definer_address) === -1)
			return finish();
		var issuer_address = objAsset.issued_by_definer_only ? objAsset.definer_address : arrAddresses[0];
		var issue_amount = objAsset.cap || (required_amount - total_amount) || 1; // 1 currency unit in case required_amount = total_amount

		function addIssueInput(serial_number){
			total_amount += issue_amount;
			var input = {
				type: "issue",
				amount: issue_amount,
				serial_number: serial_number
			};
			if (bMultiAuthored)
				input.address = issuer_address;
			var objInputWithProof = {input: input};
			if (objAsset && objAsset.is_private){
				var spend_proof = objectHash.getBase64Hash({
					asset: asset,
					amount: issue_amount,
					denomination: 1,
					address: issuer_address,
					serial_number: serial_number
				});
				var objSpendProof = {spend_proof: spend_proof};
				if (bMultiAuthored)
					objSpendProof.address = input.address;
				objInputWithProof.spend_proof = objSpendProof;
			}
			arrInputsWithProofs.unshift(objInputWithProof);
			var bFound = is_base ? (total_amount > required_amount) : (total_amount >= required_amount);
			bFound ? onDone(arrInputsWithProofs, total_amount) : finish();
		}

		if (objAsset.cap){
			conn.query("SELECT 1 FROM inputs WHERE type='issue' AND asset=?", [asset], function(rows){
				if (rows.length > 0) // already issued
					return finish();
				addIssueInput(1);
			});
		}
		else{
			conn.query(
				"SELECT MAX(serial_number) AS max_serial_number FROM inputs WHERE type='issue' AND asset=? AND address=?",
				[asset, issuer_address],
				function(rows){
					var max_serial_number = (rows.length === 0) ? 0 : rows[0].max_serial_number;
					addIssueInput(max_serial_number+1);
				}
			);
		}
	}

	function finish(){
		if (amount === Infinity && arrInputsWithProofs.length > 0)
			onDone(arrInputsWithProofs, total_amount);
		else
			onDone(null);
	}

	var arrSpendableAddresses = arrAddresses.concat(); // cloning
	if (objAsset && objAsset.auto_destroy){
		var i = arrAddresses.indexOf(objAsset.definer_address);
		if (i>=0)
			arrSpendableAddresses.splice(i, 1);
	}
	if (arrSpendableAddresses.length > 0)
		pickOneCoinJustBiggerAndContinue();
	else
		issueAsset();
}

function getConfirmationConditionSql(spend_unconfirmed){
	if (spend_unconfirmed === 'none')
		return 'AND is_stable=1';
	else if (spend_unconfirmed === 'all')
		return '';
	else if (spend_unconfirmed === 'own')
		return 'AND ( is_stable=1 OR EXISTS ( \n\
			SELECT 1 FROM unit_authors CROSS JOIN my_addresses USING(address) WHERE unit_authors.unit=outputs.unit \n\
			UNION \n\
			SELECT 1 FROM unit_authors CROSS JOIN shared_addresses ON address=shared_address WHERE unit_authors.unit=outputs.unit \n\
		) )';
	else
		throw Error("invalid spend_unconfirmed="+spend_unconfirmed);

}

exports.pickDivisibleCoinsForAmount = pickDivisibleCoinsForAmount;
exports.getConfirmationConditionSql = getConfirmationConditionSql;
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Owner: felix@famo.us
 * @license MPL 2.0
 * @copyright Famous Industries, Inc. 2014
 */

define(function(require, exports, module) {
    var Entity = require('../core/Entity');
    var RenderNode = require('../core/RenderNode');
    var Transform = require('../core/Transform');
    var ViewSequence = require('../core/ViewSequence');
    var EventHandler = require('../core/EventHandler');
    var Modifier = require('../core/Modifier');
    var OptionsManager = require('../core/OptionsManager');
    var Transitionable = require('../transitions/Transitionable');
    var TransitionableTransform = require('../transitions/TransitionableTransform');

    /**
     * A layout which divides a context into several evenly-sized grid cells.
     *   If dimensions are provided, the grid is evenly subdivided with children
     *   cells representing their own context, otherwise the cellSize property is used to compute
     *   dimensions so that items of cellSize will fit.
     * @class GridLayout
     * @constructor
     * @param {Options} [options] An object of configurable options.
     * @param {Array.Number} [options.dimensions=[1, 1]] A two value array which specifies the amount of columns
     * and rows in your Gridlayout instance.
     * @param {Array.Number} [options.gutterSize=[0, 0]] A two-value array which specifies size of the
     * horizontal and vertical gutters between items in the grid layout.
     * @param {Transition} [options.transition=false] The transiton that controls the Gridlayout instance's reflow.
     */
    function GridLayout(options) {
        this.options = Object.create(GridLayout.DEFAULT_OPTIONS);
        this.optionsManager = new OptionsManager(this.options);
        if (options) this.setOptions(options);

        this.id = Entity.register(this);

        this._modifiers = [];
        this._states = [];
        this._contextSizeCache = [0, 0];
        this._dimensionsCache = [0, 0];
        this._activeCount = 0;

        this._eventOutput = new EventHandler();
        EventHandler.setOutputHandler(this, this._eventOutput);
    }

    function _reflow(size, cols, rows) {
        var usableSize = [size[0], size[1]];
        usableSize[0] -= this.options.gutterSize[0] * (cols - 1);
        usableSize[1] -= this.options.gutterSize[1] * (rows - 1);

        var rowSize = Math.round(usableSize[1] / rows);
        var colSize = Math.round(usableSize[0] / cols);

        var currY = 0;
        var currX;
        var currIndex = 0;
        for (var i = 0; i < rows; i++) {
            currX = 0;
            for (var j = 0; j < cols; j++) {
                if (this._modifiers[currIndex] === undefined) {
                    _createModifier.call(this, currIndex, [colSize, rowSize], [currX, currY, 0], 1);
                }
                else {
                    _animateModifier.call(this, currIndex, [colSize, rowSize], [currX, currY, 0], 1);
                }

                currIndex++;
                currX += colSize + this.options.gutterSize[0];
            }

            currY += rowSize + this.options.gutterSize[1];
        }

        this._dimensionsCache = [this.options.dimensions[0], this.options.dimensions[1]];
        this._contextSizeCache = [size[0], size[1]];

        this._activeCount = rows * cols;

        for (i = this._activeCount ; i < this._modifiers.length; i++) _animateModifier.call(this, i, [Math.round(colSize), Math.round(rowSize)], [0, 0], 0);

        this._eventOutput.emit('reflow');
    }

    function _createModifier(index, size, position, opacity) {
        var transitionItem = {
            transform: new TransitionableTransform(Transform.translate.apply(null, position)),
            opacity: new Transitionable(opacity),
            size: new Transitionable(size)
        };

        var modifier = new Modifier({
            transform: transitionItem.transform,
            opacity: transitionItem.opacity,
            size: transitionItem.size
        });

        this._states[index] = transitionItem;
        this._modifiers[index] = modifier;

    }

    function _animateModifier(index, size, position, opacity) {
        var currState = this._states[index];

        var currSize = currState.size;
        var currOpacity = currState.opacity;
        var currTransform = currState.transform;

        var transition = this.options.transition;

        currTransform.halt();
        currOpacity.halt();
        currSize.halt();

        currTransform.setTranslate(position, transition);
        currSize.set(size, transition);
        currOpacity.set(opacity, transition);
    }

    GridLayout.DEFAULT_OPTIONS = {
        dimensions: [1, 1],
        transition: false,
        gutterSize: [0, 0]
    };

    /**
     * Generate a render spec from the contents of this component.
     *
     * @private
     * @method render
     * @return {Object} Render spec for this component
     */
    GridLayout.prototype.render = function render() {
        return this.id;
    };

    /**
     * Patches the GridLayout instance's options with the passed-in ones.
     *
     * @method setOptions
     * @param {Options} options An object of configurable options for the GridLayout instance.
     */
    GridLayout.prototype.setOptions = function setOptions(options) {
        return this.optionsManager.setOptions(options);
    };

    /**
     * Sets the collection of renderables under the Gridlayout instance's control.
     *
     * @method sequenceFrom
     * @param {Array|ViewSequence} sequence Either an array of renderables or a Famous viewSequence.
     */
    GridLayout.prototype.sequenceFrom = function sequenceFrom(sequence) {
        if (sequence instanceof Array) sequence = new ViewSequence(sequence);
        this.sequence = sequence;
    };

    /**
     * Apply changes from this component to the corresponding document element.
     * This includes changes to classes, styles, size, content, opacity, origin,
     * and matrix transforms.
     *
     * @private
     * @method commit
     * @param {Context} context commit context
     */
    GridLayout.prototype.commit = function commit(context) {
        var transform = context.transform;
        var opacity = context.opacity;
        var origin = context.origin;
        var size = context.size;

        var cols = this.options.dimensions[0];
        var rows = this.options.dimensions[1];

        if (size[0] !== this._contextSizeCache[0] || size[1] !== this._contextSizeCache[1] || cols !== this._dimensionsCache[0] || rows !== this._dimensionsCache[1]) {
            _reflow.call(this, size, cols, rows);
        }

        var sequence = this.sequence;
        var result = [];
        var currIndex = 0;
        while (sequence && (currIndex < this._modifiers.length)) {
            var item = sequence.get();
            var modifier = this._modifiers[currIndex];
            if (currIndex >= this._activeCount && this._states[currIndex].opacity.isActive()) {
                this._modifiers.splice(currIndex, 1);
                this._states.splice(currIndex, 1);
            }
            if (item) {
                result.push(
                    modifier.modify({
                        origin: origin,
                        target: item.render()
                    })
                );
            }
            sequence = sequence.getNext();
            currIndex++;
        }

        if (size) transform = Transform.moveThen([-size[0]*origin[0], -size[1]*origin[1], 0], transform);
        return {
            transform: transform,
            opacity: opacity,
            size: size,
            target: result
        };
    };

    module.exports = GridLayout;
});
<commit_msg>Adds getSize to gridLayout<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Owner: felix@famo.us
 * @license MPL 2.0
 * @copyright Famous Industries, Inc. 2014
 */

define(function(require, exports, module) {
    var Entity = require('../core/Entity');
    var RenderNode = require('../core/RenderNode');
    var Transform = require('../core/Transform');
    var ViewSequence = require('../core/ViewSequence');
    var EventHandler = require('../core/EventHandler');
    var Modifier = require('../core/Modifier');
    var OptionsManager = require('../core/OptionsManager');
    var Transitionable = require('../transitions/Transitionable');
    var TransitionableTransform = require('../transitions/TransitionableTransform');

    /**
     * A layout which divides a context into several evenly-sized grid cells.
     *   If dimensions are provided, the grid is evenly subdivided with children
     *   cells representing their own context, otherwise the cellSize property is used to compute
     *   dimensions so that items of cellSize will fit.
     * @class GridLayout
     * @constructor
     * @param {Options} [options] An object of configurable options.
     * @param {Array.Number} [options.dimensions=[1, 1]] A two value array which specifies the amount of columns
     * and rows in your Gridlayout instance.
     * @param {Array.Number} [options.gutterSize=[0, 0]] A two-value array which specifies size of the
     * horizontal and vertical gutters between items in the grid layout.
     * @param {Transition} [options.transition=false] The transiton that controls the Gridlayout instance's reflow.
     */
    function GridLayout(options) {
        this.options = Object.create(GridLayout.DEFAULT_OPTIONS);
        this.optionsManager = new OptionsManager(this.options);
        if (options) this.setOptions(options);

        this.id = Entity.register(this);

        this._modifiers = [];
        this._states = [];
        this._contextSizeCache = [0, 0];
        this._dimensionsCache = [0, 0];
        this._activeCount = 0;

        this._eventOutput = new EventHandler();
        EventHandler.setOutputHandler(this, this._eventOutput);
    }

    function _reflow(size, cols, rows) {
        var usableSize = [size[0], size[1]];
        usableSize[0] -= this.options.gutterSize[0] * (cols - 1);
        usableSize[1] -= this.options.gutterSize[1] * (rows - 1);

        var rowSize = Math.round(usableSize[1] / rows);
        var colSize = Math.round(usableSize[0] / cols);

        var currY = 0;
        var currX;
        var currIndex = 0;
        for (var i = 0; i < rows; i++) {
            currX = 0;
            for (var j = 0; j < cols; j++) {
                if (this._modifiers[currIndex] === undefined) {
                    _createModifier.call(this, currIndex, [colSize, rowSize], [currX, currY, 0], 1);
                }
                else {
                    _animateModifier.call(this, currIndex, [colSize, rowSize], [currX, currY, 0], 1);
                }

                currIndex++;
                currX += colSize + this.options.gutterSize[0];
            }

            currY += rowSize + this.options.gutterSize[1];
        }

        this._dimensionsCache = [this.options.dimensions[0], this.options.dimensions[1]];
        this._contextSizeCache = [size[0], size[1]];

        this._activeCount = rows * cols;

        for (i = this._activeCount ; i < this._modifiers.length; i++) _animateModifier.call(this, i, [Math.round(colSize), Math.round(rowSize)], [0, 0], 0);

        this._eventOutput.emit('reflow');
    }

    function _createModifier(index, size, position, opacity) {
        var transitionItem = {
            transform: new TransitionableTransform(Transform.translate.apply(null, position)),
            opacity: new Transitionable(opacity),
            size: new Transitionable(size)
        };

        var modifier = new Modifier({
            transform: transitionItem.transform,
            opacity: transitionItem.opacity,
            size: transitionItem.size
        });

        this._states[index] = transitionItem;
        this._modifiers[index] = modifier;

    }

    function _animateModifier(index, size, position, opacity) {
        var currState = this._states[index];

        var currSize = currState.size;
        var currOpacity = currState.opacity;
        var currTransform = currState.transform;

        var transition = this.options.transition;

        currTransform.halt();
        currOpacity.halt();
        currSize.halt();

        currTransform.setTranslate(position, transition);
        currSize.set(size, transition);
        currOpacity.set(opacity, transition);
    }

    GridLayout.DEFAULT_OPTIONS = {
        dimensions: [1, 1],
        transition: false,
        gutterSize: [0, 0]
    };

    /**
     * Generate a render spec from the contents of this component.
     *
     * @private
     * @method render
     * @return {Object} Render spec for this component
     */
    GridLayout.prototype.render = function render() {
        return this.id;
    };

    /**
     * Patches the GridLayout instance's options with the passed-in ones.
     *
     * @method setOptions
     * @param {Options} options An object of configurable options for the GridLayout instance.
     */
    GridLayout.prototype.setOptions = function setOptions(options) {
        return this.optionsManager.setOptions(options);
    };

    /**
     * Sets the collection of renderables under the Gridlayout instance's control.
     *
     * @method sequenceFrom
     * @param {Array|ViewSequence} sequence Either an array of renderables or a Famous viewSequence.
     */
    GridLayout.prototype.sequenceFrom = function sequenceFrom(sequence) {
        if (sequence instanceof Array) sequence = new ViewSequence(sequence);
        this.sequence = sequence;
    };

    /**
     * Returns the size of the grid layout.
     *
     * @method getSize
     * @return {Array} Total size of the grid layout.
     */
    GridLayout.prototype.getSize = function getSize() {
      return this._contextSizeCache;
    };

    /**
     * Apply changes from this component to the corresponding document element.
     * This includes changes to classes, styles, size, content, opacity, origin,
     * and matrix transforms.
     *
     * @private
     * @method commit
     * @param {Context} context commit context
     */
    GridLayout.prototype.commit = function commit(context) {
        var transform = context.transform;
        var opacity = context.opacity;
        var origin = context.origin;
        var size = context.size;

        var cols = this.options.dimensions[0];
        var rows = this.options.dimensions[1];

        if (size[0] !== this._contextSizeCache[0] || size[1] !== this._contextSizeCache[1] || cols !== this._dimensionsCache[0] || rows !== this._dimensionsCache[1]) {
            _reflow.call(this, size, cols, rows);
        }

        var sequence = this.sequence;
        var result = [];
        var currIndex = 0;
        while (sequence && (currIndex < this._modifiers.length)) {
            var item = sequence.get();
            var modifier = this._modifiers[currIndex];
            if (currIndex >= this._activeCount && this._states[currIndex].opacity.isActive()) {
                this._modifiers.splice(currIndex, 1);
                this._states.splice(currIndex, 1);
            }
            if (item) {
                result.push(
                    modifier.modify({
                        origin: origin,
                        target: item.render()
                    })
                );
            }
            sequence = sequence.getNext();
            currIndex++;
        }

        if (size) transform = Transform.moveThen([-size[0]*origin[0], -size[1]*origin[1], 0], transform);
        return {
            transform: transform,
            opacity: opacity,
            size: size,
            target: result
        };
    };

    module.exports = GridLayout;
});
<|endoftext|>


<commit_before>var DashboardController = Ember.Controller.extend({

});

export = DashboardController;
<commit_msg>remove dashboard controller<commit_after><|endoftext|>


<commit_before>var fs = require('fs');
var path = require('path');
var mkdirp = require('mkdirp');

exports = module.exports = Invent;

function Invent(options) {
    options || (options = {});
    this.name = options.name || 'invent';
    this.destination = options.name || '.';
    this.color = options.color || true;
    this.force = options.force || false;
    this.templatePath = path.join(__dirname, 'templates');
};

Invent.prototype.create = function () {
    var self = this;
    process.on('exit', function (code) {
        if (code === 0) {
            console.log();
            console.log(' getting started :');
            console.log(' $ cd ' + this.destination + ' && vagrant up');
            console.log(' $ vagrant ssh');
            console.log();
            if (self.color) {
                console.log(' \x1b[36mstart inventing ;)\x1b[0m');
            } else {
                console.log(' start inventing ;)');
            }
            console.log();
        }
    });
    this.mkdir(this.destination, function () {
        self.writeTemplate('Vagrantfile');
        self.writeTemplate('package.json');
        self.writeTemplate('Berksfile');
    });
};

Invent.prototype.mkdir = function (destination, cb) {
    mkdirp(destination, 0755, function (err) {
    if (err) {
        throw err;
    }
    if (this.color) {
        console.log(' \033[36mcreated\033[0m : ' + destination);
    } else {
        console.log(' created : ' + destination);
    }
    cb && cb();
    });
};

Invent.prototype.writeTemplate = function (template) {
    var contents = fs.readFileSync(
            path.join(this.templatePath, template), 'utf-8'
        ).replace('{appName}', this.name);
    this.write(path.join(this.destination, template), contents);
};

Invent.prototype.write = function (destination, content, mode) {
    fs.writeFile(destination, content, { mode: mode || 0666 });
    if (this.color) {
        console.log(' \x1b[36mcreated\x1b[0m : ' + destination);
    } else {
        console.log(' created : ' + destination);
    }
};
<commit_msg>fixed variable reference<commit_after>var fs = require('fs');
var path = require('path');
var mkdirp = require('mkdirp');

exports = module.exports = Invent;

function Invent(options) {
    options || (options = {});
    this.name = options.name || 'invent';
    this.destination = options.name || '.';
    this.color = options.color || true;
    this.force = options.force || false;
    this.templatePath = path.join(__dirname, 'templates');
};

Invent.prototype.create = function () {
    var self = this;
    process.on('exit', function (code) {
        if (code === 0) {
            console.log();
            console.log(' getting started :');
            console.log(' $ cd ' + self.destination + ' && vagrant up');
            console.log(' $ vagrant ssh');
            console.log();
            if (self.color) {
                console.log(' \x1b[36mstart inventing ;)\x1b[0m');
            } else {
                console.log(' start inventing ;)');
            }
            console.log();
        }
    });
    this.mkdir(this.destination, function () {
        self.writeTemplate('Vagrantfile');
        self.writeTemplate('package.json');
        self.writeTemplate('Berksfile');
    });
};

Invent.prototype.mkdir = function (destination, cb) {
    mkdirp(destination, 0755, function (err) {
    if (err) {
        throw err;
    }
    if (this.color) {
        console.log(' \033[36mcreated\033[0m : ' + destination);
    } else {
        console.log(' created : ' + destination);
    }
    cb && cb();
    });
};

Invent.prototype.writeTemplate = function (template) {
    var contents = fs.readFileSync(
            path.join(this.templatePath, template), 'utf-8'
        ).replace('{appName}', this.name);
    this.write(path.join(this.destination, template), contents);
};

Invent.prototype.write = function (destination, content, mode) {
    fs.writeFile(destination, content, { mode: mode || 0666 });
    if (this.color) {
        console.log(' \x1b[36mcreated\x1b[0m : ' + destination);
    } else {
        console.log(' created : ' + destination);
    }
};
<|endoftext|>


<commit_before>/* HTML Editor*/
var editor = ace.edit("editor");
editor.setTheme("ace/theme/monokai");
editor.getSession().setMode("ace/mode/html");
editor.setOption("showPrintMargin", false);
editor.setFontSize("16px");
editor.getSession().setUseWrapMode(true);

$(document).ready(function() {
    if (annyang) {
        function addText(text){
            editor.insert(text);
        }
        annyang.setLanguage('ru');
        var commands = {
            'переключить язык на английский': function() {
                annyang.setLanguage('en-US');
            },
            'switch language to russian': function() {
                annyang.setLanguage('ru');
            },
            'слово *wordRu': calcWordRu,
            'say *wordEn': calcWordEn,
            'слово дерево': function() {
                addText('дерево');
            },
            'открыть инструкцию': function() {
                localStorage.clear();
                tour.init();
                tour.start();
            },
            'закрыть инструкцию': function() {
                tour.end()
            },
            'энтер': function() {
                addText('\n');
            },
            'таб': function() {
                addText('    ');
            },
            'пробел': function() {
                addText(' ');
            },
            'отменить': function() {
                editor.undo();
            },
            'вернуть': function() {
                editor.redo();
            },
            'сохранить': function() {
                localStorage.setItem('text',editor.getValue());
            },
            'загрузить': function() {
                var str = localStorage.getItem('text');
                editor.getSession().setValue(str);
                editor.renderer.updateFull();
            },
            'верх *stepsUp': calcStepsUp,
            'вниз *stepsDown': calcStepsDown,
            'лево *stepsLeft': calcStepsLeft,
            'право *stepsRight': calcStepsRight,
            'перейти на *row строку *col столбец':calcRowCol,
            'текст': function() {
                addText('

');
            },
            'ссылка':function(){
                addText('');
            },
            'секция': function() {
                addText('
');
                addText('\n');
            },
            'класс': function() {
                addText('class=""');
            },
            'айди': function() {
                addText('id=""');
            },
            'блок класс':function(){
                addText('
');
                addText('\n');
            },
            'блок айди':function(){
                addText('
');
                addText('\n');
            },
            'старт':function(){
                addText('<!DOCTYPE html>\n\n    \n        <meta charset="utf-8">\n        <title></title>\n        \n    \n    \n
Hello
\n');
                addText('    \n');
                editor.gotoLine(7);
                editor.navigateLineEnd();
                addText('\n');
            }
        };
        annyang.addCommands(commands);
        annyang.start({ autoRestart: true, continuous: false });
    }
});

/* Preview code*/
function showHTML() {
    $('#return').html(editor.getValue());
}
editor.on("input", showHTML);

/* Step-by-step the tour */
var tour = new Tour({
    steps: [
    {
        element: "#editor",
        title: "Привет дорогой друг :)",
        backdrop: true,
        smartPlacement: true,
        backdropContainer: 'body',
        backdropPadding: 5,
        content: "Эта часть, в которой ты будешь видеть свой код и иметь возможность его редактировать!",
        duration: 10000
    },
    {
        element: "#return",
        title: "Превью",
        backdrop: true,
        smartPlacement: true,
        backdropContainer: 'body',
        backdropPadding: 5,
        content: "В этой же части будет отображаться весь твой сайт, каким его видит браузер - то есть в готовом виде!",
        duration: 10000
    }
    ],
    template: "
\

\

\

\

",
});

/* wrap word media query*/
if (window.matchMedia("(max-width: 1280px)").matches) {
    editor.getSession().setWrapLimitRange(0, 40);
}
else if (window.matchMedia("(max-width: 1366px)").matches)  {
  editor.getSession().setWrapLimitRange(0, 50);
}
else if (window.matchMedia("(max-width: 1600px)").matches) {
    editor.getSession().setWrapLimitRange(0, 100);
}
else if (window.matchMedia("(max-width: 1920px)").matches) {
    editor.getSession().setWrapLimitRange(0, 140);
}
else {}

    /* calc steps Up, Down, Left, Right by user say!*/
var calcStepsUp = function(stepsUp) {
    editor.navigateUp(stepsUp);
}
var calcStepsDown = function(stepsDown) {
    editor.navigateDown(stepsDown);
    console.log(stepsDown); /* sometimes have strange bag - cursor ignore number & go full down.*/
}
var calcStepsLeft = function(stepsLeft) {
    editor.navigateLeft(stepsLeft);
}
var calcStepsRight = function(stepsRight) {
    editor.navigateRight(stepsRight);
}

var calcRowCol = function(row,col) {
    editor.gotoLine(row,col,true);
}

var calcWordRu = function(wordRu) {
    editor.insert(wordRu);
    console.log(wordRu);
}

var calcWordEn = function(wordEn) {
    editor.insert(wordEn);
    console.log(wordEn);
}<commit_msg>add point, !, ?, space and style {}<commit_after>/* HTML Editor*/
var editor = ace.edit("editor");
editor.setTheme("ace/theme/monokai");
editor.getSession().setMode("ace/mode/html");
editor.setOption("showPrintMargin", false);
editor.setFontSize("16px");
editor.getSession().setUseWrapMode(true);

$(document).ready(function() {
    if (annyang) {
        function addText(text){
            editor.insert(text);
        }
        annyang.setLanguage('ru');
        var commands = {
            'переключить язык на английский': function() {
                annyang.setLanguage('en-US');
            },
            'switch language to russian': function() {
                annyang.setLanguage('ru');
            },
            'слово *wordRu': calcWordRu,
            'say *wordEn': calcWordEn,
            'слово дерево': function() {
                addText('дерево');
            },
            'открыть инструкцию': function() {
                localStorage.clear();
                tour.init();
                tour.start();
            },
            'закрыть инструкцию': function() {
                tour.end()
            },
            'энтер': function() {
                addText('\n');
            },
            'enter': function() {
                addText('\n');
            },
            'таб': function() {
                addText('    ');
            },
            'tab': function() {
                addText('    ');
            },
            'пробел': function() {
                addText(' ');
            },
            'space': function() {
                addText(' ');
            },
            'удалить': function() {
                /* I don't know how this made...*/
            },
            'отменить': function() {
                editor.undo();
            },
            'cancel': function() {
                editor.undo();
            },
            'вернуть': function() {
                editor.redo();
            },
            'сохранить': function() {
                localStorage.setItem('text',editor.getValue());
            },
            'загрузить': function() {
                var str = localStorage.getItem('text');
                editor.getSession().setValue(str);
                editor.renderer.updateFull();
            },
            'верх *stepsUp': calcStepsUp,
            'вниз *stepsDown': calcStepsDown,
            'лево *stepsLeft': calcStepsLeft,
            'право *stepsRight': calcStepsRight,
            'перейти на *row строку *col столбец':calcRowCol,
            'текст': function() {
                addText('

');
            },
            'ссылка':function(){
                addText('');
            },
            'секция': function() {
                addText('
');
                addText('\n');
            },
            'класс': function() {
                addText('class=""');
            },
            'айди': function() {
                addText('id=""');
            },
            'решетка': function() {
                addText('#');
            },
            'точка': function() {
                addText('.');
            },
            'запятая': function() {
                addText(',');
            },
            'восклицательный знак': function() {
                addText('!');
            },
            'вопросительный знак': function() {
                addText('?');
            },
            'стиль скобки': function() {
                addText('{');
                addText('\n');
            },
            'блок класс':function(){
                addText('
');
                addText('\n');
            },
            'блок айди':function(){
                addText('
');
                addText('\n');
            },
            'старт':function(){
                addText('<!DOCTYPE html>\n\n    \n        <meta charset="utf-8">\n        <title></title>\n        \n    \n    \n
Hello
\n');
                addText('    \n');
                editor.gotoLine(7);
                editor.navigateLineEnd();
                addText('\n');
            }
        };
        annyang.addCommands(commands);
        annyang.start({ autoRestart: true, continuous: false });
    }
});

/* Preview code*/
function showHTML() {
    $('#return').html(editor.getValue());
}
editor.on("input", showHTML);

/* Step-by-step the tour */
var tour = new Tour({
    steps: [
    {
        element: "#editor",
        title: "Привет дорогой друг :)",
        backdrop: true,
        smartPlacement: true,
        backdropContainer: 'body',
        backdropPadding: 5,
        content: "Эта часть, в которой ты будешь видеть свой код и иметь возможность его редактировать!",
        duration: 10000
    },
    {
        element: "#return",
        title: "Превью",
        backdrop: true,
        smartPlacement: true,
        backdropContainer: 'body',
        backdropPadding: 5,
        content: "В этой же части будет отображаться весь твой сайт, каким его видит браузер - то есть в готовом виде!",
        duration: 10000
    }
    ],
    template: "
\

\

\

\

",
});

/* wrap word media query*/
if (window.matchMedia("(max-width: 1280px)").matches) {
    editor.getSession().setWrapLimitRange(0, 40);
}
else if (window.matchMedia("(max-width: 1366px)").matches)  {
  editor.getSession().setWrapLimitRange(0, 50);
}
else if (window.matchMedia("(max-width: 1600px)").matches) {
    editor.getSession().setWrapLimitRange(0, 100);
}
else if (window.matchMedia("(max-width: 1920px)").matches) {
    editor.getSession().setWrapLimitRange(0, 140);
}
else {}

    /* calc steps Up, Down, Left, Right by user say!*/
var calcStepsUp = function(stepsUp) {
    editor.navigateUp(stepsUp);
}
var calcStepsDown = function(stepsDown) {
    editor.navigateDown(stepsDown);
    console.log(stepsDown); /* sometimes have strange bag - cursor ignore number & go full down.*/
}
var calcStepsLeft = function(stepsLeft) {
    editor.navigateLeft(stepsLeft);
}
var calcStepsRight = function(stepsRight) {
    editor.navigateRight(stepsRight);
}

var calcRowCol = function(row,col) {
    editor.gotoLine(row,col,true);
}

var calcWordRu = function(wordRu) {
    editor.insert(wordRu);
    console.log(wordRu);
}

var calcWordEn = function(wordEn) {
    editor.insert(wordEn);
    console.log(wordEn);
}<|endoftext|>