<commit_before>(function(undefined) {

    //Create gaffa
    var gaffa = window.gaffa = window.gaffa || newGaffa();

    //"constants"
    // functions to make it 'getter only'
    gaffa.pathSeparator = function() {
        return "/";
    };
    gaffa.upALevel = function() {
        return "..";
    };
    gaffa.relativePath = function() {
        return "~";
    };

    //internal varaibles
    var internalmodel = {},
        //these must always be instantiated.
        internalViews = [];

    //internal functions

    /*
        Now I can detect arrays.
    */
    Array.prototype.isArray = true;

    //Lots of similarities between get and set, refactor later to reuse code.
    function get(path, model) {
        if (path) {
            var keys = path.split(gaffa.pathSeparator()),
                reference = model;

            for (var keyIndex = 0; keyIndex < keys.length; keyIndex++) {

                //handle "Up A Level"s in the path.
                if (keys[keyIndex] === gaffa.upALevel()) {
                    keys.splice(Math.max(keyIndex - 1, 0), 2);
                    keyIndex--;

                }
                else {

/*
                        if the thing at the current key in the model is an object
                        or an array (both typeof to object),
                        set it as the thing we want to look into next.
                    */
                    if (typeof reference[keys[keyIndex]] === "object") {
                        reference = reference[keys[keyIndex]];

/*
                        else if there isn't anything at this key, exit the loop,
                        and return undefined.
                    */
                    }
                    else if (reference[keys[keyIndex]] === undefined) {
                        reference = undefined;
                        break;

/*
                        otherwise, we're at the end of the line. return whatever's
                        there
                    */
                    }
                    else {
                        reference = reference[keys[keyIndex]];
                        break;
                    }
                }
            }

            return reference;
        }
    }

    function set(path, value, model) {
        var keys = path.split(gaffa.pathSeparator()),
            reference = model,
            keyIndex;

        //handle "Up A Level"s in the path.
        //yeah yeah, its done differently up above...
        //ToDo: refactor.
        for (keyIndex = 0; keyIndex < keys.length; keyIndex++) {
            if (keys[keyIndex] === gaffa.upALevel()) {
                keys.splice(Math.max(keyIndex - 1, 0), 2);
                keyIndex--;
            }
        }

        for (keyIndex = 0; keyIndex < keys.length; keyIndex++) {

            //if we have hit a non-object and we have more keys after this one
            //make an object (or array) here and move on.
            if (typeof reference[keys[keyIndex]] !== "object" && keyIndex < keys.length - 1) {
                if (!isNaN(keys[keyIndex + 1])) {
                    reference[keys[keyIndex]] = [];
                    reference = reference[keys[keyIndex]];
                }
                else {
                    reference[keys[keyIndex]] = {};
                    reference = reference[keys[keyIndex]];
                }
            }
            else if (keyIndex === keys.length - 1) {
                // if we are at the end of the line, set to the model
                reference[keys[keyIndex]] = value;
                if (!isNaN(reference.length)) {
                    $(gaffa.model).trigger("change." + keys.slice(0, keys.length - 2).join("."));
                }
            }
                //otherwise, RECURSANIZE!
            else {
                reference = reference[keys[keyIndex]];
            }
        }
        for (keyIndex = 0; keyIndex < keys.length; keyIndex++) {
            $(gaffa.model).trigger(["change"].concat(keys.slice(0,keyIndex+1)).join("_"));
        }

        //ToDo: Fire events for array.length changes

        //IMA FIREIN MA CHANGEZOR!
        $(gaffa.model).trigger("change." + keys.join("."));
    }

    function renderView(view, parent) {
        //delegate rendering to happen as soon as possible, but not if it blocks the UI.
        //this will cause all kinds of hilariously stupid layout if you breakpoint during the render loop.
        setTimeout(function() {
            if(view.isArray && !view.isRendered){
                parent.append(view.join(""));
                view.isRendered = true;
            }else if (gaffa.views[view.type] !== undefined) {
                var renderedElement = gaffa.views[view.type].render(view);
                if (parent) {
                    parent[0].appendChild(renderedElement[0]);
                }
                for (var key in view.views) {
                    for (var i = 0; i < view.views[key].length; i++) {
                        renderView(view.views[key][i], view.viewContainers[key].element);
                    }
                }
                if (view.actions) {
                    for (var actionKey in view.actions) {
                        var eventActions = view.actions[actionKey];
                        view.renderedElement.bind(actionKey, function() {
                            for (var i = 0; i < eventActions.length; i++) {
                                bindAction(eventActions[i], view);
                            }
                        });
                    }
                }
            }
        }, 0);
    }

    //mostly just make sure all the relative bindings are made absolute. delegate actions to the appropriate action object.
    function bindAction(action, parent) {
        for (var key in action.bindings) {
            if (action.bindings[key] && action.bindings[key].binding !== undefined) {
                action.bindings[key].binding = gaffa.paths.getAbsolutePath(parent.binding, action.bindings[key].binding);
            }
        }
        if(typeof gaffa.actions[action.type] === "function"){
            gaffa.actions[action.type](action);
        }
    }

    //gaffa together view properties to model properties.
    function bindView(view, parentView, index) {
        if(gaffa.views[view.type] === undefined){
            return;
        }
        //ToDo: probs a better way to do this....
        $.extend(true, view, $.extend(true, {}, gaffa.views[view.type].defaults, view));

        var parentViewBinding = "";
        if (parentView) {
            parentViewBinding = parentView.binding;
            if(index !== undefined && !isNaN(index)){
                parentViewBinding += gaffa.pathSeparator() + index;
            }
        }

        //if this is a root level view, remove the relative binding.
        // this causes all bindings to cascade as nothing untill a real binding has been set.
        if(parentView){
            view.binding = gaffa.paths.getAbsolutePath(parentViewBinding, view.binding);
        }else{
            view.binding = parentViewBinding;
        }

        //bind each of the views properties to the model.
        for (var key in view.properties) {
            if (parentView && view.properties[key] && view.properties[key].binding) {
                view.properties[key].binding = gaffa.paths.getAbsolutePath(parentViewBinding, view.properties[key].binding);

                // this function is to create a closure so that 'key' is still the same key when the event fires.
                (function(key) {
                    if (view.properties[key].binding) {
                        view.properties[key].value = gaffa.model.get(view.properties[key].binding);

                        //jQuerys eventing system is full of winning and unicorn kisses.
                        //changing an object on the model will cause all bindings to its properties to fire
                        //due to event namespacing magic.
                        $(gaffa.model).bind(["change"].concat(view.properties[key].binding.split(gaffa.pathSeparator())).join("."), function() {
                            gaffa.views[view.type].update[key](view, gaffa.model.get(view.properties[key].binding));
                        });
                    }
                })(key);
            }
        }

        //recursivly bind child views.
        for (var key in view.views) {
            for (var i = 0; i < view.views[key].length; i++) {
                bindView(view.views[key][i], view);
            }
        }
    }

    function newGaffa() {

        function innerGaffa() {}

        innerGaffa.prototype = {
            paths: {
                //check if a binding is relative, and if it is, make it absolute.
                getAbsolutePath: function(parentBinding, childBinding) {
                    if (childBinding.indexOf(window.gaffa.relativePath()) === 0) {
                        childBinding = childBinding.replace(window.gaffa.relativePath(), "");
                        if (childBinding === "") {
                            return parentBinding;
                        }
                        return parentBinding + window.gaffa.pathSeparator() + childBinding;
                    }
                    else {
                        return childBinding;
                    }
                }
            },
            model: {
                get: function(path) {
                    return get(path, internalmodel);
                },
                set: function(path, value) {
                    return set(path, value, internalmodel);
                },
                update: function(path, value) {

                }
            },
            views: {
                renderTarget: null,
                //Render all, some, or one view/s to a parent or the render target.
                render: function(views, parent) { //parameters optional.
                    //if its a list of views, render them all
                    if (views && views.length) {
                        for (var i = 0; i < views.length; i++) {
                            renderView(views[i], parent);
                        }
                    }
                    //if its just one view, just render it
                    else if (views) {
                        renderView(views, parent);
                    }
                    //if nothing is passed in, render ALL the views!
                    else {
                        for (var i = 0; i < internalViews.length; i++) {
                            renderView(internalViews[i], this.renderTarget || $("body"));
                        }
                    }
                },
                //Add a view or views to another view, or the root list of views if a parent isnt passed.
                //Set up the views bindings as they are added.
                add: function(views, parentView, parentViewChildArray, index) {
                    //if the views isnt an array, make it one.
                    if (views && !views.length) {
                        views = [views];
                    }

                    for (var i = 0; i < views.length; i++) {
                        if(gaffa.views[views[i].type] !== undefined){
                            //if this view has a parent.
                            if (parentView && parentViewChildArray) {

                                //bind ALL the things!
                                bindView(views[i], parentView, index);

                                parentViewChildArray.push(views[i]);
                            }
                            //otherwise, this view should be in the root list of views.
                            else {
                                bindView(views[i]);

                                internalViews.push(views[i]);
                            }
                        }
                    }
                },

                //All views get extended with the object that this returns.
                base: function(viewType, createElement, defaults) {
                    return {

                        //This is executed when a view is inserted into the page
                        render: function(viewModel) {
                            //only render if the view has not previously been rendered.
                            if (viewModel.renderedElement) {
                                return viewModel.renderedElement;
                            }

                            //extend the passed in view with default options for that view type.
                            $.extend(true, viewModel, defaults, viewModel);

                            //create the root level element for the view
                            viewModel.renderedElement = createElement(viewModel);
                            viewModel.renderedElement[0].viewModel = viewModel;

                            //Automatically fire all of the update functions when the view is first rendered.
                            for (var key in viewModel.properties) {
                                var updateFunction = window.gaffa.views[viewType].update[key];
                                if (updateFunction && typeof updateFunction === "function") {
                                    updateFunction(viewModel, viewModel.properties[key].value, true);
                                }
                            }

                            return viewModel.renderedElement;
                        },

                        //functions under this are executed whenever the data bound to by properties of the same name changes.
                        update: {
                            //optionally put standard update methods in here, like for example view visibility:
                            visible: function(viewModel, value, firstRun) {
                                if(viewModel.properties.visible.value !== value || firstRun){
                                    viewModel.properties.visible.value = value;
                                    var element = viewModel.renderedElement;
                                    if(element){
                                        if(value !== false){
                                            element.show();
                                        }else{
                                            element.hide();
                                        }
                                    }
                                }
                            },
                            classes: function(viewModel, value, firstRun){
                                if(viewModel.properties.classes.value !== value || firstRun){
                                    var element = viewModel.renderedElement;
                                    if (element) {
                                        if(viewModel.properties.classes.value){
                                            element.removeClass(viewModel.properties.classes.value);
                                        }
                                        element.addClass(viewModel.properties.classes.value = value);
                                    }
                                }
                            }
                        },

                        defaults:{
                            //Set the default view binding to nothing but a relative path.
                            //This is so all relative bindings flow on nicely.
                            binding: gaffa.relativePath(),
                            properties: {
                                visible: {},
                                classes: {}
                            }
                        }
                    };
                }
            },
            actions: {
                //placeholder for actions
            },
            behaviours: {
                add: function(behaviours) {
                    //if the views isnt an array, make it one.
                    if (behaviours && !behaviours.length) {
                        behaviours = [behaviours];
                    }

                    for (var i = 0; i < behaviours.length; i++) {
                        var behaviourType = behaviours[i].type;
                        if(behaviourType === "pageLoad"){
                            (function(behaviour){
                                $(document).ready(function(){
                                        for(var i = 0; i < behaviour.actions.length; i++){
                                            if(gaffa.actions[behaviour.actions[i].type] !== undefined){
                                                gaffa.actions[behaviour.actions[i].type](behaviour.actions[i]);
                                            }
                                        }
                                });
                            })(behaviours[i]);
                        }else if(behaviourType === "modelChange"){
                            (function(behaviour){
                                $(gaffa.model).bind(['change'].concat(behaviour.binding.split('/')).join("_"), function(){
                                    for(var i = 0; i < behaviour.actions.length; i++){
                                        if(gaffa.actions[behaviour.actions[i].type] !== undefined){
                                            gaffa.actions[behaviour.actions[i].type](behaviour.actions[i]);
                                        }
                                    }
                                });
                            })(behaviours[i]);
                        }
                    }
                }
            },
            utils: {
                //See if a property exists on an object without doing if(obj && obj.prop && obj.prop.prop) etc...
                propExists: function(object, propertiesString){
                    var properties = propertiesString.split(".").reverse();
                    while(properties.length){
                        var nextProp = properties.pop();
                        if(object[nextProp] !== undefined){
                            object = object[nextProp];
                        }else{
                            return false;
                        }
                    }
                    return true;
                }
            }
        };

        return new innerGaffa();
    }
})();<commit_msg>quick update<commit_after><|endoftext|>


<commit_before>const Resource = require('../api-resource').Resource;

class AttemptLogResource extends Resource {
  static resourceName() {
    return 'attemptlog';
  }
  static idKey() {
    return 'pk';
  }
}

module.exports = AttemptLogResource;
<commit_msg>fix attemptLogResource promise resolved data parsing<commit_after>const Resource = require('../api-resource').Resource;

class AttemptLogResource extends Resource {
  static resourceName() {
    return 'attemptlog';
  }
  static idKey() {
    return 'id';
  }
}

module.exports = AttemptLogResource;
<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash');
var Promise = require('es6-promise').Promise;

var targetMap = require('../context/map');
var Target = require('../context/target');

module.exports = function () {
  return function (ctx) {
    return new Promise(function (resolve, reject) {
      // Retrieve the context map
      targetMap.get().then(function (result) {
        // Detect if prefs has disabled context
        result.disabled = !_.get(ctx, 'prefs.core.context', true);

        // Nullify context values if not enabled
        if (result.disabled) {
          result.context = null;
        }

        ctx.target = new Target(result);

        // Context is disabled, proceed no further
        if (ctx.target.disabled()) {
          return resolve();
        }

        // Apply default values from prefs
        ctx.target.defaults(_.get(ctx, 'prefs.default', {}));

        // Apply context related flags to the target
        var service = ctx.option('service') || {};
        var environment = ctx.option('environment') || {};
        ctx.target.flags({
          service: service.value,
          environment: environment.value
        });

        // Look up user's default environment
        if (ctx.loggedIn && !ctx.target.environment) {
          return ctx.api.users.self().then(function (user) {
            if (!user) {
              return reject(new Error('Could not find the user'));
            }

            ctx.target.flags({
              environment: 'dev-' + user.body.username
            });

            return resolve();
          });
        }

        return resolve();
      }).catch(reject);
    });
  };
};
<commit_msg>Ignore lookup error, use dev-${username} as default env<commit_after>'use strict';

var _ = require('lodash');
var Promise = require('es6-promise').Promise;

var targetMap = require('../context/map');
var Target = require('../context/target');

module.exports = function () {
  return function (ctx) {
    return new Promise(function (resolve, reject) {
      // Retrieve the context map
      targetMap.get().then(function (result) {
        // Detect if prefs has disabled context
        result.disabled = !_.get(ctx, 'prefs.core.context', true);

        // Nullify context values if not enabled
        if (result.disabled) {
          result.context = null;
        }

        ctx.target = new Target(result);

        // Context is disabled, proceed no further
        if (ctx.target.disabled()) {
          return resolve();
        }

        // Apply default values from prefs
        ctx.target.defaults(_.get(ctx, 'prefs.default', {}));

        // Apply context related flags to the target
        var service = ctx.option('service') || {};
        var environment = ctx.option('environment') || {};
        ctx.target.flags({
          service: service.value,
          environment: environment.value
        });

        // Look up user's default environment
        if (!ctx.target.environment) {
          return ctx.api.users.self().then(function (user) {
            if (user) {
              ctx.target.flags({
                environment: 'dev-' + user.body.username
              });
            }
            resolve();
          }).catch(function () {
            resolve();
          });
        }

        return resolve();
      }).catch(reject);
    });
  };
};
<|endoftext|>


<commit_before>function formatTime(num){
    var minute = '0' + String(Math.floor(num / 60));
    var second = '0' + String(num % 60);

    return minute.substr(-2) + ':' + second.substr(-2);
}

function count(current, maximum){
    if (current > maximum){
        return;
    }

    var timer = document.getElementById('timer');
    timer.innerText = formatTime(current);

    var timeoutId = window.setTimeout(count, 1000, current + 1, maximum);
    document.getElementById('stop').addEventListener('click', function(){
        window.clearTimeout(timeoutId);
    });
    if (current === maximum){
        timer.style.color = 'red';
    }
}

window.onload = function(){
    document.getElementById('start').addEventListener('click', function(){
        count(0, 60);
    });
};
<commit_msg>タイマーのリセットを実装<commit_after>function formatTime(num){
    var minute = '0' + String(Math.floor(num / 60));
    var second = '0' + String(num % 60);

    return minute.substr(-2) + ':' + second.substr(-2);
}

function count(current, maximum){
    if (current > maximum){
        return;
    }

    var timer = document.getElementById('timer');
    timer.innerText = formatTime(current);

    var timeoutId = window.setTimeout(count, 1000, current + 1, maximum);
    document.getElementById('stop').addEventListener('click', function(){
        window.clearTimeout(timeoutId);
    });
    if (current === maximum){
        timer.style.color = 'red';
    }
}

function resetTimer(){
    var timer = document.getElementById('timer');
    timer.innerText = '00:00';
    timer.style.color = 'lime';
}

window.onload = function(){
    document.getElementById('start').addEventListener('click', function(){
        count(0, 60);
    });
    document.getElementById('reset').addEventListener('click', function(){
        resetTimer();
    })
};
<|endoftext|>


<commit_before>var fs = require('fs'),
    // Internal Libs
    common = require('./common'),
    // External libs
    async = require('async'),
    request = require('request'),
    // Variables
    maxRequests = app.get('maxRequests'),
    client_id = 'b45b1aa10f1ac2941910a7f0d10f8e28';

/**
 * Possible results
 * callback(null, true);
 * callback(null, false); NOT FOUND!
 * callback(error);
 */

/**
 * scID is a partial-url like: ascoltadi/dirk-maassen-with-science
 * statusCallback is a function that gets called *MULTIPLE* times with a JSON object as only argument
 *                it takes care of updating the user about the download process, it may be null (in future!)
 * doneCallback is a function that gets called *ONE* time only with (error, JSON) a JSON object similar to the previous
 *              function, just reporting what has been done.
 */

module.exports = function (scID, statusCallback, doneCallback) {
  // Beautiful work, we redefine statusCallback as a throttled function
  statusCallback = common.throttle(1000, true, statusCallback);

  var trueID,
      declaredFileLength, // i'm gonna read the headers, this might be different from the real length! (YEAH, SERVERS DO LIE!)
      partialBytes = 0,
      title,
      hq;

  async.waterfall([
    function (callback) {
      // From such a request we get a giant object from soundcloud API, they are damn good.
      // I'll dump an example in the proj root
      request({ url: 'https://api.soundcloud.com/resolve',
        pool: maxRequests,
        json: true,
        qs: { client_id: client_id, url: 'https://soundcloud.com/' + scID } }, callback);
    },
    function (response, body, callback) {
      // the following is just a soundcloud 404 (most probably)
      if (response.statusCode !== 200) { return callback(null, false); }

      // set globals to be returned in the _VERY_ end
      title = body.title;
      trueID = body.id;
      hq = body.downloadable;
      statusCallback({ id: trueID, status: 'starting', title: title, hq: hq, service: 'sc' });

      if (body.downloadable) {
        callback(null, request({
          url: body.download_url,
          pool: maxRequests,
          qs: { client_id: client_id }
        }));
      } else {
        callback(null, request({
          url: body.stream_url,
          pool: maxRequests,
          qs: { client_id: client_id }
        }));
      }
    },
    function (httpClientRequest, callback) {
      var songStream;
      httpClientRequest.on('response', function (httpIncomingMessage) {
        declaredFileLength = parseInt(httpIncomingMessage.headers['content-length'], 10);
        songStream = fs.createWriteStream('assets/sc/' + trueID + '.mp3');

        // piping into the file
        httpIncomingMessage.pipe(songStream);
        httpIncomingMessage.on('data', function (chunk) {
          partialBytes += chunk.length;
          statusCallback({
            id: trueID,
            status: 'progress',
            totalBytes: declaredFileLength,
            partialBytes: partialBytes,
            progress: Math.round((partialBytes / declaredFileLength) * 100)
          });
        });
      });
      httpClientRequest.on('end', function () { callback(null, declaredFileLength); });
    }
  ], function (err, results) {
    if (err) { return doneCallback(err); }
    doneCallback(null, { id: trueID, status: 'complete', title: title, hq: hq, service: 'sc' });
  });
};

exports.getsound = null;

/**
 * First socket function, this gonna be A*W*E*S*O*M*E !!!
 *
exports.getsound = function (url, pubRedis, socketID) {
  var scReq = http.request({
    hostname: 'api.soundcloud.com',
    path: '/resolve?client_id='+client_id+'&url='+encodeURIComponent(url)
  }, function (scResponse) {
    var songID
      , bytesGot = 0
      , throttledConsole = common.throttle( 1000, function (bytes, totalBytes) {
          log(['bytes passed:', bytes]);
          pubRedis.publish(socketID, JSON.stringify({
            id: songID,
            size: totalBytes,
            progress: bytes
          }));
          bytesGot = 0;
        });

    // if the response is a redirect, that's what we want
    if (scResponse.statusCode === 302) {
      songID = parseInt(scResponse.headers.location.match(/tracks\/(\d+)/)[1], 10);
      // TODO - Check on REDIS if the file it has been already downloaded.
      // IF NOT, go on.
      // ELSE, send back to res the cached file!

      // nested Request to SoundCloud API
      var songURL = http.request({
        hostname: 'api.soundcloud.com',
        path: '/i1/tracks/'+songID+'/streams?client_id='+client_id
      }, function (songURLResponse) {
        var dataToParse = '';
        songURLResponse.setEncoding('utf8');
        songURLResponse.on('data', function (chunk) {
          dataToParse += chunk;
        });
        // when songURLResponse *FINALLY* ends, we have the responseURL!
        songURLResponse.on('end', function() {
          dataToParse = JSON.parse(dataToParse);
          // res.send(dataToParse.http_mp3_128_url);
          // So we now write the file to disk!
          var songDownload = http.request({
            hostname: dataToParse.http_mp3_128_url.match(/:\/\/(.*soundcloud.com)(.*)/)[1],
            path: dataToParse.http_mp3_128_url.match(/:\/\/(.*soundcloud.com)(.*)/)[2]
          }, function (songDWResponse) {
            // This is the correct moment to fetch the headers, to read the file size!
            var totalBytes = songDWResponse.headers['content-length'];
            // Create SongWriter and BUUURN ON DISK!
            var SongWriter = fs.createWriteStream('assets/soundcloud/'+songID+'.mp3');
            songDWResponse.pipe(SongWriter);
            songDWResponse.on('data', function (buffer) {
              bytesGot += buffer.length;
              throttledConsole(bytesGot, totalBytes);
            });
            // Send the complete response
            songDWResponse.on('end', function() {
              pubRedis.publish(socketID, JSON.stringify({
                id: songID,
                size: totalBytes,
                status: 'complete'
              }));
            });
          });
          // Close request, don't ever forget.
          songDownload.end();
        });
      });
      // Close request, don't ever forget.
      songURL.end();
    } else {
      // Send an error according to RFC if the response is not a redirect
      // something like: 'unexpected response'
      // res.send(403);
      // ** Converted reply to Websocket! :-)
      pubRedis.publish(socketID, JSON.stringify({
        url: url,
        error: 'unexpected response'
      }));
    }
  });

  // Close request, don't ever forget.
  scReq.end();
};
 **/
<commit_msg>soundcloud.js now creates also .ogg file!<commit_after>var fs = require('fs'),
    // Internal Libs
    common = require('./common'),
    // External libs
    async = require('async'),
    request = require('request'),
    ffmpeg = require('fluent-ffmpeg'),
    // Variables
    maxRequests = app.get('maxRequests'),
    client_id = 'b45b1aa10f1ac2941910a7f0d10f8e28';

/**
 * Possible results
 * callback(null, true);
 * callback(null, false); NOT FOUND!
 * callback(error);
 */

/**
 * scID is a partial-url like: ascoltadi/dirk-maassen-with-science
 * statusCallback is a function that gets called *MULTIPLE* times with a JSON object as only argument
 *                it takes care of updating the user about the download process, it may be null (in future!)
 * doneCallback is a function that gets called *ONE* time only with (error, JSON) a JSON object similar to the previous
 *              function, just reporting what has been done.
 */

module.exports = function (scID, statusCallback, doneCallback) {
  // Beautiful work, we redefine statusCallback as a throttled function
  statusCallback = common.throttle(1000, true, statusCallback);

  var trueID,
      declaredFileLength, // i'm gonna read the headers, this might be different from the real length! (YEAH, SERVERS DO LIE!)
      partialBytes = 0,
      title,
      hq,
      filesBitrate,
      oggProcess;

  async.waterfall([
    function (callback) {
      // From such a request we get a giant object from soundcloud API, they are damn good.
      // I'll dump an example in the proj root
      request({ url: 'https://api.soundcloud.com/resolve.json',
        pool: maxRequests,
        json: true,
        qs: { client_id: client_id, url: 'https://soundcloud.com/' + scID } }, callback);
    },
    function (response, body, callback) {
      // the following is just a soundcloud 404 (most probably)
      if (response.statusCode !== 200) { return callback(null, false); }

      // set globals to be returned in the _VERY_ end
      title = body.title;
      trueID = body.id;
      hq = body.downloadable;
      filesBitrate = (hq) ? '320k' : '128k';
      statusCallback({ id: trueID, status: 'starting', title: title, hq: hq, service: 'sc' });

      if (body.downloadable) {
        callback(null, request({
          url: body.download_url,
          pool: maxRequests,
          qs: { client_id: client_id }
        }));
      } else {
        callback(null, request({
          url: body.stream_url,
          pool: maxRequests,
          qs: { client_id: client_id }
        }));
      }
    },
    function (httpClientRequest, callback) {
      var songStream;
      httpClientRequest.on('response', function (httpIncomingMessage) {
        declaredFileLength = parseInt(httpIncomingMessage.headers['content-length'], 10);
        songStream = fs.createWriteStream('assets/sc/' + trueID + '.mp3');

        // piping into .ogg
        oggProcess = ffmpeg({ source: httpIncomingMessage, timeout: 600 })
          .withNoVideo(true)
          .withAudioCodec('libvorbis')
          .withAudioBitrate(filesBitrate)
          .toFormat('ogg')
          .saveToFile('assets/sc/' + trueID + '.ogg');

        // piping into the file
        httpIncomingMessage.pipe(songStream);
        httpIncomingMessage.on('data', function (chunk) {
          partialBytes += chunk.length;
          statusCallback({
            id: trueID,
            status: 'progress',
            totalBytes: declaredFileLength,
            partialBytes: partialBytes,
            progress: Math.round((partialBytes / declaredFileLength) * 100)
          });
        });
      });
      httpClientRequest.on('end', function () { callback(null, declaredFileLength); });
    }
  ], function (err, results) {
    if (err) { return doneCallback(err); }
    doneCallback(null, { id: trueID, status: 'complete', title: title, hq: hq, service: 'sc' });
  });
};

exports.getsound = null;

/**
 * First socket function, this gonna be A*W*E*S*O*M*E !!!
 *
exports.getsound = function (url, pubRedis, socketID) {
  var scReq = http.request({
    hostname: 'api.soundcloud.com',
    path: '/resolve?client_id='+client_id+'&url='+encodeURIComponent(url)
  }, function (scResponse) {
    var songID
      , bytesGot = 0
      , throttledConsole = common.throttle( 1000, function (bytes, totalBytes) {
          log(['bytes passed:', bytes]);
          pubRedis.publish(socketID, JSON.stringify({
            id: songID,
            size: totalBytes,
            progress: bytes
          }));
          bytesGot = 0;
        });

    // if the response is a redirect, that's what we want
    if (scResponse.statusCode === 302) {
      songID = parseInt(scResponse.headers.location.match(/tracks\/(\d+)/)[1], 10);
      // TODO - Check on REDIS if the file it has been already downloaded.
      // IF NOT, go on.
      // ELSE, send back to res the cached file!

      // nested Request to SoundCloud API
      var songURL = http.request({
        hostname: 'api.soundcloud.com',
        path: '/i1/tracks/'+songID+'/streams?client_id='+client_id
      }, function (songURLResponse) {
        var dataToParse = '';
        songURLResponse.setEncoding('utf8');
        songURLResponse.on('data', function (chunk) {
          dataToParse += chunk;
        });
        // when songURLResponse *FINALLY* ends, we have the responseURL!
        songURLResponse.on('end', function() {
          dataToParse = JSON.parse(dataToParse);
          // res.send(dataToParse.http_mp3_128_url);
          // So we now write the file to disk!
          var songDownload = http.request({
            hostname: dataToParse.http_mp3_128_url.match(/:\/\/(.*soundcloud.com)(.*)/)[1],
            path: dataToParse.http_mp3_128_url.match(/:\/\/(.*soundcloud.com)(.*)/)[2]
          }, function (songDWResponse) {
            // This is the correct moment to fetch the headers, to read the file size!
            var totalBytes = songDWResponse.headers['content-length'];
            // Create SongWriter and BUUURN ON DISK!
            var SongWriter = fs.createWriteStream('assets/soundcloud/'+songID+'.mp3');
            songDWResponse.pipe(SongWriter);
            songDWResponse.on('data', function (buffer) {
              bytesGot += buffer.length;
              throttledConsole(bytesGot, totalBytes);
            });
            // Send the complete response
            songDWResponse.on('end', function() {
              pubRedis.publish(socketID, JSON.stringify({
                id: songID,
                size: totalBytes,
                status: 'complete'
              }));
            });
          });
          // Close request, don't ever forget.
          songDownload.end();
        });
      });
      // Close request, don't ever forget.
      songURL.end();
    } else {
      // Send an error according to RFC if the response is not a redirect
      // something like: 'unexpected response'
      // res.send(403);
      // ** Converted reply to Websocket! :-)
      pubRedis.publish(socketID, JSON.stringify({
        url: url,
        error: 'unexpected response'
      }));
    }
  });

  // Close request, don't ever forget.
  scReq.end();
};
 **/
<|endoftext|>


<commit_before>$(document).ready(function(){
  var active_map;
  findUser();

  $('#address_submit').on('click', function(event){
    findAddress('#address');
  })

  $('#lower_address_submit').on('click', function(event){
    findAddress('#lower_address');
  })

});

function findUser() {
  if (navigator.geolocation){
    function success(position) {
      var latitude  = position.coords.latitude;
      var longitude = position.coords.longitude;
      var data = {latitude: latitude, longitude: longitude};

      updatePage(data, 'your current location')
    };
    navigator.geolocation.getCurrentPosition(success);
  }
}

function findAddress(selector){
  var address = $(selector).val();
  $(selector).val('')
  var geocoder = new google.maps.Geocoder();
  geocoder.geocode({'address': address + 'chicago'}, function(results, status){
    var lat = results[0].geometry.location.k;
    var lng = results[0].geometry.location.B;
    data = {latitude: lat, longitude: lng};
    updatePageFromAddress(data, address);
  });
}

function updatePage(data, location) {
  postCurrentLocation(data, location, pagePost);
}

function updatePageFromAddress(data, location) {
  postCurrentLocation(data, location, addressPost);
}

function postCurrentLocation(data, location, regionFunction) {
  $.post('/current_position', data, function(response){
    $('.copy p:nth-child(2)').html('The next street cleaning
for ' + location + ' is:
' + response.next_sweep);

    $('#next').html('
Next street cleaning for ' + location + ':
' + response.next_sweep);

    str = "

Street Cleaning Days

"

    var days = response.sweep_days;
    if (days.length > 0) {
      for (var i=0; i<days.length; i++) {
        str += '
' + days[i] + '
';
      }
    } else {
      str += '
none
';
    }
    $('#future').html(str + '
');
    regionFunction(data);
  }, 'JSON');
}

function addLegend(active_map) {
  legend.onAdd = function (map) {
     var div = L.DomUtil.create('div', 'info legend');
        div.innerHTML += 'Streets will next be swept in:

' +
              ' ' + 'less than a week

' + ' ' + 'a week or more';
      return div;
      };
    legend.addTo(active_map);
}

function addressPost(data) {
  $.post('/load_region_from_address', data, function(response){
    $('#active_map').replaceWith(response)
    addLegend(active_map);
  });
}

function pagePost(data) {
  $.post('/load_region', data, function(response){
    $('#active_map').append(response);
  });
}<commit_msg>Fix bug with next cleaning display<commit_after>$(document).ready(function(){
  var active_map;
  findUser();

  $('#address_submit').on('click', function(event){
    findAddress('#address');
  })

  $('#lower_address_submit').on('click', function(event){
    findAddress('#lower_address');
  })

});

function findUser() {
  if (navigator.geolocation){
    function success(position) {
      var latitude  = position.coords.latitude;
      var longitude = position.coords.longitude;
      var data = {latitude: latitude, longitude: longitude};

      updatePage(data, 'your current location')
    };
    navigator.geolocation.getCurrentPosition(success);
  }
}

function findAddress(selector){
  var address = $(selector).val();
  $(selector).val('')
  var geocoder = new google.maps.Geocoder();
  geocoder.geocode({'address': address + 'chicago'}, function(results, status){
    var lat = results[0].geometry.location.k;
    var lng = results[0].geometry.location.B;
    data = {latitude: lat, longitude: lng};
    updatePageFromAddress(data, address);
  });
}

function updatePage(data, location) {
  postCurrentLocation(data, location, pagePost);
}

function updatePageFromAddress(data, location) {
  postCurrentLocation(data, location, addressPost);
}

function postCurrentLocation(data, location, regionFunction) {
  $.post('/current_position', data, function(response){
    $('#next_cleaning p').html('The next street cleaning
for ' + location + ' is:
' + response.next_sweep);

    $('#next').html('
Next street cleaning for ' + location + ':
' + response.next_sweep);

    str = "

Street Cleaning Days

"

    var days = response.sweep_days;
    if (days.length > 0) {
      for (var i=0; i<days.length; i++) {
        str += '
' + days[i] + '
';
      }
    } else {
      str += '
none
';
    }
    $('#future').html(str + '
');
    regionFunction(data);
  }, 'JSON');
}

function addLegend(active_map) {
  legend.onAdd = function (map) {
     var div = L.DomUtil.create('div', 'info legend');
        div.innerHTML += 'Streets will next be swept in:

' +
              ' ' + 'less than a week

' + ' ' + 'a week or more';
      return div;
      };
    legend.addTo(active_map);
}

function addressPost(data) {
  $.post('/load_region_from_address', data, function(response){
    $('#active_map').replaceWith(response)
    addLegend(active_map);
  });
}

function pagePost(data) {
  $.post('/load_region', data, function(response){
    $('#active_map').append(response);
  });
}<|endoftext|>


<commit_before>import iDB from "../src/idb-instance"
import fakeIndexedDB from "fake-indexeddb"

import BackupActions, {
    createWalletObject, createWalletBackup,
    decryptWalletBackup
} from "actions/BackupActions"
import AccountActions from "../src/actions/AccountActions"
import WalletActions from "../src/actions/WalletActions"
import WalletDb from "../src/stores/WalletDb"

import ApiInstances from "../src/rpc_api/ApiInstances"
import WalletApi from "../src/rpc_api/WalletApi"
import ApplicationApi from "../src/rpc_api/ApplicationApi"
import PrivateKey from "../src/ecc/key_private"

import th from "./test_helper"
import secureRandom from "secure-random"
import assert from "assert"
import helper from "./test_helper"

var _catch = th.log_error

describe( "wallet_actions", ()=> {

    var api

    // broadcast with confirmation waits for a block
    //this == undefined ??
    //this.setTimeout(it(), 3 * 1000)

    beforeEach( done => {
        api = ApiInstances.instance()
        api.init_promise.then( ()=>  {
            iDB.set_impl(fakeIndexedDB)
            var suffix = secureRandom.randomBuffer(2).toString('hex').toLowerCase()
            //create a unique wallet name
            iDB.root.setProperty("current_wallet", "wallet" + suffix).then( ()=> {
                return iDB.init_instance().init_promise.then( ()=> {
                    done()
                })
            })
        }).catch( _catch )
    })

    afterEach(()=>{
        iDB.instance().db().close()
        // Does Not delete the database...
        fakeIndexedDB.deleteDatabase("graphene_db")
        api.close()
    })

    it( "wallet_backups", done => {
        var suffix = secureRandom.randomBuffer(2).toString('hex').toLowerCase()
        var public_name = "default_" + suffix
        helper.test_wallet( suffix ).then(()=>{

            return createWalletObject().then( wallet_object => {
                assert( wallet_object.wallet )
                var wallet_object_string = JSON.stringify(wallet_object, null, 0)
                var backup_private = PrivateKey.fromSeed("1")
                var backup_public = backup_private.toPublicKey()
                var backup_public_string = backup_public.toPublicKeyString()

                return createWalletBackup(
                    backup_public_string, wallet_object, 9,
                    secureRandom.randomBuffer(32).toString('binary')//"entropy"
                    ).then( binary_backup => {

                    //console.log('... binary_backup',binary_backup.length, "original", wallet_object_string.length, "bytes")

                    return decryptWalletBackup(backup_private.toWif(), binary_backup).then(
                        wallet_object2 => {
                        assert( wallet_object2.wallet )
                        var wallet_object2_string = JSON.stringify(wallet_object2, null, 0)
                        assert.equal(wallet_object_string, wallet_object2_string)
                        done()
                    })
                })
            })
        }).catch(_catch)
    })

    it( "wallet_create", done => {
        var suffix = secureRandom.randomBuffer(2).toString('hex').toLowerCase()
        var public_name = "default_" + suffix
        helper.test_wallet( suffix ).then(()=>{
            WalletDb.onLock()
            assert( WalletDb.isLocked(), "isLocked" )
            assert( WalletDb.getWallet() != null )
            assert( WalletDb.getCurrentWalletName() == public_name )
            WalletDb.validatePassword( "password", true )
            assert( ! WalletDb.isLocked() )
            assert( WalletDb.getBrainKey() == "brainkey" + suffix )
            WalletDb.onLock()
            done()
        }).catch(_catch)
    })

    it( "create_account_with_brain_key", done => {
        var suffix = secureRandom.randomBuffer(2).toString('hex').toLowerCase()
        helper.test_wallet( suffix ).then(()=>{
            return WalletActions.createAccount(
                "brainaccount-"+ suffix,
                "nathan", "nathan",
                100
            ).then(()=> {
                done()
            })
        }).catch(_catch)
    })

// todo
//    it( "import_balance", done => {
//        var suffix = secureRandom.randomBuffer(2).toString('hex').toLowerCase()
//        var wif_keys = [ PrivateKey.fromSeed("nathan").toWif() ]
//        test_wallet(suffix).then( ()=> {
//            return test_account( suffix ).then( account_name => {
//                return WalletActions.importBalance(
//                    account_name,
//                    wif_keys,
//                    true //broadcast
//                )
//            })
//        }).then(()=>done()).catch(_catch)
//    })

})

<commit_msg>Simple import keys test to help<commit_after>import iDB from "../src/idb-instance"
import fakeIndexedDB from "fake-indexeddb"

import BackupActions, {
    createWalletObject, createWalletBackup,
    decryptWalletBackup
} from "actions/BackupActions"
import AccountActions from "../src/actions/AccountActions"
import WalletActions from "../src/actions/WalletActions"
import WalletDb from "../src/stores/WalletDb"

import ApiInstances from "../src/rpc_api/ApiInstances"
import WalletApi from "../src/rpc_api/WalletApi"
import ApplicationApi from "../src/rpc_api/ApplicationApi"
import PrivateKey from "../src/ecc/key_private"

import th from "./test_helper"
import secureRandom from "secure-random"
import assert from "assert"
import helper from "./test_helper"

var _catch = th.log_error

describe( "wallet_actions", ()=> {

    var api

    // broadcast with confirmation waits for a block
    //this == undefined ??
    //this.setTimeout(it(), 3 * 1000)

    beforeEach( done => {
        api = ApiInstances.instance()
        api.init_promise.then( ()=>  {
            iDB.set_impl(fakeIndexedDB)
            var suffix = secureRandom.randomBuffer(2).toString('hex').toLowerCase()
            //create a unique wallet name
            iDB.root.setProperty("current_wallet", "wallet" + suffix).then( ()=> {
                return iDB.init_instance().init_promise.then( ()=> {
                    done()
                })
            })
        }).catch( _catch )
    })

    afterEach(()=>{
        iDB.instance().db().close()
        // Does Not delete the database...
        fakeIndexedDB.deleteDatabase("graphene_db")
        api.close()
    })

    it("import_keys", done => {
        var suffix = secureRandom.randomBuffer(2).toString('hex').toLowerCase()
        helper.test_wallet( suffix ).then(()=>{
            var private_key = PrivateKey.fromSeed("nathan")
            var wif = private_key.toWif()
            var private_key_obj = {
                wif,
                import_account_names: ["nathan"],
                public_key_string: private_key.toPublicKey().toPublicKeyString()
            }
            WalletDb.importKeys([ private_key_obj ]).then( result => {
                // console.log("importKeys", result)
                done()
            })
        }).catch(_catch)
    })

    it( "wallet_backups", done => {
        var suffix = secureRandom.randomBuffer(2).toString('hex').toLowerCase()
        var public_name = "default_" + suffix
        helper.test_wallet( suffix ).then(()=>{

            return createWalletObject().then( wallet_object => {
                assert( wallet_object.wallet )
                var wallet_object_string = JSON.stringify(wallet_object, null, 0)
                var backup_private = PrivateKey.fromSeed("1")
                var backup_public = backup_private.toPublicKey()
                var backup_public_string = backup_public.toPublicKeyString()

                return createWalletBackup(
                    backup_public_string, wallet_object, 9,
                    secureRandom.randomBuffer(32).toString('binary')//"entropy"
                    ).then( binary_backup => {

                    //console.log('... binary_backup',binary_backup.length, "original", wallet_object_string.length, "bytes")

                    return decryptWalletBackup(backup_private.toWif(), binary_backup).then(
                        wallet_object2 => {
                        assert( wallet_object2.wallet )
                        var wallet_object2_string = JSON.stringify(wallet_object2, null, 0)
                        assert.equal(wallet_object_string, wallet_object2_string)
                        done()
                    })
                })
            })
        }).catch(_catch)
    })

    it( "wallet_create", done => {
        var suffix = secureRandom.randomBuffer(2).toString('hex').toLowerCase()
        var public_name = "default_" + suffix
        helper.test_wallet( suffix ).then(()=>{
            WalletDb.onLock()
            assert( WalletDb.isLocked(), "isLocked" )
            assert( WalletDb.getWallet() != null )
            assert( WalletDb.getCurrentWalletName() == public_name )
            WalletDb.validatePassword( "password", true )
            assert( ! WalletDb.isLocked() )
            assert( WalletDb.getBrainKey() == "brainkey" + suffix )
            WalletDb.onLock()
            done()
        }).catch(_catch)
    })

    it( "create_account_with_brain_key", done => {
        var suffix = secureRandom.randomBuffer(2).toString('hex').toLowerCase()
        helper.test_wallet( suffix ).then(()=>{
            return WalletActions.createAccount(
                "brainaccount-"+ suffix,
                "nathan", "nathan",
                100
            ).then(()=> {
                done()
            })
        }).catch(_catch)
    })

// todo
//    it( "import_balance", done => {
//        var suffix = secureRandom.randomBuffer(2).toString('hex').toLowerCase()
//        var wif_keys = [ PrivateKey.fromSeed("nathan").toWif() ]
//        test_wallet(suffix).then( ()=> {
//            return test_account( suffix ).then( account_name => {
//                return WalletActions.importBalance(
//                    account_name,
//                    wif_keys,
//                    true //broadcast
//                )
//            })
//        }).then(()=>done()).catch(_catch)
//    })

})

<|endoftext|>


<commit_before>var React = require('react');
var PropTypes = React.PropTypes;

function Button (props) {
  return (
    <button type='submit'
      className='btn btn-success'>
        {props.children}
    </button>
  )
}

function generateRealmOptions (props) {
  return props.realmList.map(function(realm) {
    return <option key={realm.slug} value={realm.slug}>{realm.name}</option>;
  });
}

function RealmField (props) {
  return (
    <select
      className='form-control mr-sm-2'
      onChange={props.onUpdateRealm}
      value={props.charRealm}>
        <option value="" disabled>Realm</option>
        {generateRealmOptions(props)}
    </select>
  )
}

function NameField (props) {
  return (
    <input
      className='form-control mr-sm-2'
      onChange={props.onUpdateName}
      placeholder='Character Name'
      type='text'
      value={props.charName} />
  )
}

function GetChar (props) {
  return (
    <form className="form-inline"
    onClick={props.onSubmitChar}>
      <RealmField
        onUpdateRealm={props.onUpdateRealm}
        realmList={props.realmList}
        charRealm={props.charRealm} />
      <NameField
        onUpdateName={props.onUpdateName}
        charName={props.charName} />
      <Button>
          Inspect
      </Button>
    </form>
  )
}

GetChar.propTypes = {
  realmList: PropTypes.array.isRequired,
  onUpdateName: PropTypes.func.isRequired,
  onUpdateRealm: PropTypes.func.isRequired,
  onSubmitChar: PropTypes.func.isRequired,
  charName: PropTypes.string.isRequired,
  charRealm: PropTypes.string.isRequired
}

module.exports = GetChar;
<commit_msg>fix form action<commit_after>var React = require('react');
var PropTypes = React.PropTypes;

function Button (props) {
  return (
    <button type='submit'
      className='btn btn-success'>
        {props.children}
    </button>
  )
}

function generateRealmOptions (props) {
  return props.realmList.map(function(realm) {
    return <option key={realm.slug} value={realm.slug}>{realm.name}</option>;
  });
}

function RealmField (props) {
  return (
    <select
      className='form-control mr-sm-2'
      onChange={props.onUpdateRealm}
      value={props.charRealm}>
        <option value="" disabled>Realm</option>
        {generateRealmOptions(props)}
    </select>
  )
}

function NameField (props) {
  return (
    <input
      className='form-control mr-sm-2'
      onChange={props.onUpdateName}
      placeholder='Character Name'
      type='text'
      value={props.charName} />
  )
}

function GetChar (props) {
  return (
    <form className="form-inline"
    onSubmit={props.onSubmitChar}>
      <RealmField
        onUpdateRealm={props.onUpdateRealm}
        realmList={props.realmList}
        charRealm={props.charRealm} />
      <NameField
        onUpdateName={props.onUpdateName}
        charName={props.charName} />
      <Button>
          Inspect
      </Button>
    </form>
  )
}

GetChar.propTypes = {
  realmList: PropTypes.array.isRequired,
  onUpdateName: PropTypes.func.isRequired,
  onUpdateRealm: PropTypes.func.isRequired,
  onSubmitChar: PropTypes.func.isRequired,
  charName: PropTypes.string.isRequired,
  charRealm: PropTypes.string.isRequired
}

module.exports = GetChar;
<|endoftext|>


<commit_before>(function($angular, $crossfilter, $array) {

    "use strict";

    /**
     * @module ngCrossfilter
     * @author Adam Timberlake
     * @link http://github.com/Wildhoney/ngCrossfilter
     */
    var ngCrossfilter = $angular.module('ngCrossfilter', []);

    /**
     * @module ngCrossfilter
     * @submodule CrossfilterFilter
     */
    ngCrossfilter.filter('crossfilter', function CrossfilterFilter() {

        return function ngCrossfilterFilter(collection) {

            return [1, 2, 3];

        };

    });

    /**
     * @module ngCrossfilter
     * @submodule CrossfilterService
     */
    ngCrossfilter.service('Crossfilter', function CrossfilterService() {

        /**
         * @module ngCrossfilter
         * @submodule ngCrossfilterService
         * @constructor
         */
        var Service = function ngCrossfilterService(collection, primaryKey) {

            // Initialise the Crossfilter with the array of models.
            this._initialise(collection, primaryKey);

        };

        /**
         * @property prototype
         * @type {Object}
         */
        Service.prototype = {

            /**
             * @property collection
             * @type {crossfilter}
             * @private
             */
            _collection: {},

            /**
             * @property _dimensions
             * @type {Array}
             * @private
             */
            _dimensions: [],

            /**
             * @property _primaryKey
             * @type {String}
             * @private
             */
            _primaryKey: '',

            /**
             * @property _lastFilter
             * @type {String}
             * @private
             */
            _lastFilter: '',

            /**
             * @property strategy
             * @type {String}
             * @return {void}
             */
            _strategy: 'persistent',

            /**
             * @method _initialise
             * @param collection {Array}
             * @param primaryKey {String}
             * @param strategy {String} Either "persistent" or "transient"
             * @return {void}
             * @private
             */
            _initialise: function _initialise(collection, primaryKey, strategy) {

                if (typeof $array.isArray === 'function' && !$array.isArray(collection)) {

                    // Determine if the collection is a valid array.
                    this._throwException("Collection must be an array");

                }

                if (typeof strategy !== 'undefined' && ['persistent', 'transient'].indexOf(strategy) === -1) {

                    // Determine if the strategy has been defined as either persistent or transient.
                    this._throwException("Strategy must be either 'persistent' or 'transient'");

                }

                // Discover the unique properties in the collection.
                var properties = this._getProperties(collection[0]);

                // Initialise the Crossfilter collection, with the primary key.
                this._collection = $crossfilter(collection);
                this._primaryKey = primaryKey || properties[0];
                this._strategy   = strategy;

                // Iterate over each property to create its related dimension.
                $angular.forEach(properties, function(property) {

                    this._dimensions[property] = this._collection.dimension(function(model) {
                        return model[property];
                    });

                }.bind(this));

            },

            /**
             * @method filterBy
             * @param property {String}
             * @param value {String}
             * @param customFilter {Function}
             * @return {void}
             */
            filterBy: function filterBy(property, value, customFilter) {

                if (typeof customFilter !== 'undefined' && typeof customFilter !== 'function') {

                    // Ensure the third argument is a function, if it has been defined.
                    throw this._throwException("Custom filter method must be a function");

                }

                // Store the last filter so we can filter anew.
                this._lastFilter = property;

            },

            /**
             * @method unfilterBy
             * @param property {String}
             * @return {void}
             */
            unfilterBy: function unfilterBy(property) {},

            /**
             * @method sortBy
             * @param property {String}
             * @param direction {String}
             * @return {void}
             */
            sortBy: function sortBy(property, direction) {},

            /**
             * @method unsortBy
             * @param property {String}
             * @return {void}
             */
            unsortBy: function unsortBy(property) {},

            /**
             * @method pageNext
             * @return {void}
             */
            pageNext: function pageNext() {},

            /**
             * @method pagePrevious
             * @return {void}
             */
            pagePrevious: function pagePrevious() {},

            /**
             * @method pageLimit
             * @param limit {Number}
             * @return {void}
             */
            pageLimit: function(limit) {},

            /**
             * @method pageNumber
             * @param number {Number}
             * @return {void}
             */
            pageNumber: function pageNumber(number) {},

            /**
             * @method _getProperties
             * @param model {Object}
             * @return {Array}
             * @private
             */
            _getProperties: function _getProperties(model) {

                var properties = [];

                for (var property in model) {

                    if (model.hasOwnProperty(property)) {
                        properties.push(property);
                    }

                }

                return properties;

            },

            /**
             * @method _throwException
             * @param message {String}
             * @return {void}
             * @private
             */
            _throwException: function _throwException(message) {
                throw "ngCrossfilter: " + message + ".";
            }

        };

        return Service;

    });

})(window.angular, window.crossfilter, window.Array);<commit_msg>Added checks for dependencies<commit_after>(function($angular, $crossfilter, $array) {

    "use strict";

    /**
     * @method _throwException
     * @param message {String}
     * @return {void}
     * @private
     */
    var _throwException = function _throwException(message) {
        throw "ngCrossfilter: " + message + ".";
    };

    if (typeof $angular === 'undefined') {

        // Add a check for Angular.
        _throwException("Angular dependency is a requirement");

    }

    if (typeof $crossfilter === 'undefined') {

        // Add a check for Crossfilter.
        _throwException("Crossfilter dependency is a requirement");

    }

    /**
     * @module ngCrossfilter
     * @author Adam Timberlake
     * @link http://github.com/Wildhoney/ngCrossfilter
     */
    var ngCrossfilter = $angular.module('ngCrossfilter', []);

    /**
     * @module ngCrossfilter
     * @submodule CrossfilterFilter
     */
    ngCrossfilter.filter('crossfilter', function CrossfilterFilter() {

        return function ngCrossfilterFilter(collection) {

            return [1, 2, 3];

        };

    });

    /**
     * @module ngCrossfilter
     * @submodule CrossfilterService
     */
    ngCrossfilter.service('Crossfilter', function CrossfilterService() {

        /**
         * @module ngCrossfilter
         * @submodule ngCrossfilterService
         * @constructor
         */
        var Service = function ngCrossfilterService(collection, primaryKey) {

            // Initialise the Crossfilter with the array of models.
            this._initialise(collection, primaryKey);

        };

        /**
         * @property prototype
         * @type {Object}
         */
        Service.prototype = {

            /**
             * @property collection
             * @type {crossfilter}
             * @private
             */
            _collection: {},

            /**
             * @property _dimensions
             * @type {Array}
             * @private
             */
            _dimensions: [],

            /**
             * @property _primaryKey
             * @type {String}
             * @private
             */
            _primaryKey: '',

            /**
             * @property _lastFilter
             * @type {String}
             * @private
             */
            _lastFilter: '',

            /**
             * @property strategy
             * @type {String}
             * @return {void}
             */
            _strategy: 'persistent',

            /**
             * @method _initialise
             * @param collection {Array}
             * @param primaryKey {String}
             * @param strategy {String} Either "persistent" or "transient"
             * @return {void}
             * @private
             */
            _initialise: function _initialise(collection, primaryKey, strategy) {

                if (typeof $array.isArray === 'function' && !$array.isArray(collection)) {

                    // Determine if the collection is a valid array.
                    _throwException("Collection must be an array");

                }

                if (typeof strategy !== 'undefined' && ['persistent', 'transient'].indexOf(strategy) === -1) {

                    // Determine if the strategy has been defined as either persistent or transient.
                    _throwException("Strategy must be either 'persistent' or 'transient'");

                }

                // Discover the unique properties in the collection.
                var properties = this._getProperties(collection[0]);

                // Initialise the Crossfilter collection, with the primary key.
                this._collection = $crossfilter(collection);
                this._primaryKey = primaryKey || properties[0];
                this._strategy   = strategy;

                // Iterate over each property to create its related dimension.
                $angular.forEach(properties, function(property) {

                    this._dimensions[property] = this._collection.dimension(function(model) {
                        return model[property];
                    });

                }.bind(this));

            },

            /**
             * @method filterBy
             * @param property {String}
             * @param value {String}
             * @param customFilter {Function}
             * @return {void}
             */
            filterBy: function filterBy(property, value, customFilter) {

                if (typeof customFilter !== 'undefined' && typeof customFilter !== 'function') {

                    // Ensure the third argument is a function, if it has been defined.
                    throw _throwException("Custom filter method must be a function");

                }

                // Store the last filter so we can filter anew.
                this._lastFilter = property;

            },

            /**
             * @method unfilterBy
             * @param property {String}
             * @return {void}
             */
            unfilterBy: function unfilterBy(property) {},

            /**
             * @method sortBy
             * @param property {String}
             * @param direction {String}
             * @return {void}
             */
            sortBy: function sortBy(property, direction) {},

            /**
             * @method unsortBy
             * @param property {String}
             * @return {void}
             */
            unsortBy: function unsortBy(property) {},

            /**
             * @method pageNext
             * @return {void}
             */
            pageNext: function pageNext() {},

            /**
             * @method pagePrevious
             * @return {void}
             */
            pagePrevious: function pagePrevious() {},

            /**
             * @method pageLimit
             * @param limit {Number}
             * @return {void}
             */
            pageLimit: function(limit) {},

            /**
             * @method pageNumber
             * @param number {Number}
             * @return {void}
             */
            pageNumber: function pageNumber(number) {},

            /**
             * @method _getProperties
             * @param model {Object}
             * @return {Array}
             * @private
             */
            _getProperties: function _getProperties(model) {

                var properties = [];

                for (var property in model) {

                    if (model.hasOwnProperty(property)) {
                        properties.push(property);
                    }

                }

                return properties;

            }

        };

        return Service;

    });

})(window.angular, window.crossfilter, window.Array);<|endoftext|>


<commit_before>/**
 * Spectra.js
 *
 * Wrapping a value with Spectra() returns a Spectra object.
 *
 * The object's color value is as follows:
 * {
 *   rgb: {
 *     r: 0 to 255,
 *     g: 0 to 255,
 *     b: 0 to 255,
 *   }
 *   hsv: {
 *     h: 0 to 360,
 *     s: 0 to 1,
 *     v: 0 to 1
 *   }
 *   a: 0 to 1 // Alpha
 * }
 */

 (function() {
  var root = this;
  var oldSpectra = root.Spectra;

  /** Conversion functions between formats. */
  var rgbToHsv = function(rgb) {
    var hsv = {};
    var r = Number(rgb.r || rgb.red || 0) / 255;
    var g = Number(rgb.g || rgb.green || 0) / 255;
    var b = Number(rgb.b || rgb.blue || 0) / 255;
    var max = Math.max(r, g, b);
    var min = Math.min(r, g, b);
    var delta = max - min;

    hsv.v = max;
    if (hsv.v === 0) {
      hsv.h = 0;
      hsv.s = 0;
    } else {
      hsv.s = (max - min) / max;
      if (hsv.s === 0) {
        hsv.h = 0;
      } else {
        if (max === r) {
          hsv.h = (g - b) / delta;
        } else if (max === g) {
          hsv.h = 2 + (b - r) / delta;
        } else {
          hsv.h = 4 + (r - g) / delta;
        }
        hsv.h *= 60;
        if (hsv.h < 0) {
          hsv.h += 360;
        }
      }
    }

    return hsv;
  };

  var hsvToRgb = function(hsv) {
    var rgb = {r: 0, g: 0, b: 0};

    var h = Number(hsv.h || 0);
    var s = Number(hsv.s || 0);
    var v = Number(hsv.v || 0);
    var chroma = s * v;
    var hDash = h / 60;
    var x = chroma * (1 - Math.abs((hDash % 2) - 1));

    if(hDash < 1.0) {
      rgb.r = chroma;
      rgb.g = x;
    } else if (hDash < 2) {
      rgb.r = x;
      rgb.g = chroma;
    } else if (hDash < 3) {
      rgb.g = chroma;
      rgb.b = x;
    } else if (hDash < 4) {
      rgb.g= x;
      rgb.b = chroma;
    } else if (hDash < 5) {
      rgb.r = x;
      rgb.b = chroma;
    } else if (hDash <= 6) {
      rgb.r = chroma;
      rgb.b = x;
    }

    var min = v - chroma;

    rgb.r += min;
    rgb.g += min;
    rgb.b += min;

    rgb.r *= 255;
    rgb.g *= 255;
    rgb.b *= 255;

    return rgb;
  };

  var parseCss = function(css) {
    var color = {};
    var shorthandRegex = /^#[0-9a-f]{3}$/i;
    var shorthandMatch = css.match(shorthandRegex);
    if (shorthandMatch) {
      color.rgb = {
        r: parseInt(css.charAt(1), 16) * 0x11,
        g: parseInt(css.charAt(2), 16) * 0x11,
        b: parseInt(css.charAt(3), 16) * 0x11
      };
      return normalize(color);
    }
    var longhandRegex = /^#[0-9a-f]{6}$/i;
    var longhandMatch = css.match(longhandRegex);
    if (longhandMatch) {
      color.rgb = {
        r: parseInt(css.slice(1,3), 16),
        g: parseInt(css.slice(3,5), 16),
        b: parseInt(css.slice(5,7), 16)
      };
      return normalize(color);
    }
    var rgbRegex = /^rgb\(\s*([0-9]+),\s*([0-9]+),\s*([0-9]+)\s*\)$/i;
    var rgbMatch = css.match(rgbRegex);
    if (rgbMatch) {
      color.rgb = {
        r: parseInt(rgbMatch[1], 10),
        g: parseInt(rgbMatch[2], 10),
        b: parseInt(rgbMatch[3], 10)
      };
      return normalize(color);
    }
    var rgbaRegex = /^rgba\(\s*([0-9]+),\s*([0-9]+),\s*([0-9]+),\s*([0-9\.]+)\s*\)$/i;
    var rgbaMatch = css.match(rgbaRegex);
    if (rgbaMatch) {
      color.rgb = {
        r: parseInt(rgbaMatch[1], 10),
        g: parseInt(rgbaMatch[2], 10),
        b: parseInt(rgbaMatch[3], 10)
      };
      color.a = parseFloat(rgbaMatch[4], 10);
      return normalize(color);
    }
  };

  /** Normalization functions */
  var normalize = function(arg) {
    var color = arg;
    color.a = color.a || 1;

    if (color.rgb !== undefined) {
      color.hsv = rgbToHsv(color.rgb);
    } else if (color.hsv !== undefined) {
      color.rgb = hsvToRgb(color.hsv);
    } else if (color.css !== undefined) {
      return parseCss(color.css);
    }

    if (color.rgb.red !== undefined) {
      color.rgb.r = color.rgb.red;
    }
    if (color.rgb.green !== undefined) {
      color.rgb.g = color.rgb.green;
    }
    if (color.rgb.blue !== undefined) {
      color.rgb.b = color.rgb.blue;
    }

    return color;
  };

  /** Wrapper */
  var Spectra = function(arg) {
    if (typeof arg == 'object') {
      if (arg.r !== undefined || arg.red !== undefined) {
        this.color = normalize({rgb: arg, a: arg.a});
      }
      if (arg.v !== undefined || arg.value !== undefined) {
        this.color = normalize({hsv: arg, a: arg.a});
      }
    } else if (typeof arg == 'string') {
      this.color = normalize({css: arg});
    }
    return this;
  };

  /** Getters and Setters */
  Spectra.prototype.red = function(arg) {
    var color = this.color;
    if (arg) {
      color.rgb.r = arg;
      this.color = normalize({rgb: color.rgb});
      return this;
    } else {
      return Math.round(color.rgb.r);
    }
  };
  Spectra.prototype.green = function(arg) {
    var color = this.color;
    if (arg) {
      color.rgb.g = arg;
      this.color = normalize({rgb: color.rgb});
      return this;
    } else {
      return Math.round(color.rgb.g);
    }
  };
  Spectra.prototype.blue = function(arg) {
    var color = this.color;
    if (arg) {
      color.rgb.b = arg;
      this.color = normalize({rgb: color.rgb});
      return this;
    } else {
      return Math.round(color.rgb.b);
    }
  };

  Spectra.prototype.hue = function(arg) {
    var color = this.color;
    if (arg) {
      color.hsv.h = arg;
      this.color = normalize({hsv: color.hsv});
      return this;
    } else {
      return Math.round(color.hsv.h);
    }
  };
  Spectra.prototype.saturation = function(arg) {
    var color = this.color;
    if (arg) {
      color.hsv.s = arg;
      this.color = normalize({hsv: color.hsv});
      return this;
    } else {
      return color.hsv.s;
    }
  };
  Spectra.prototype.value = function(arg) {
    var color = this.color;
    if (arg) {
      color.hsv.v = arg;
      this.color = normalize({hsv: color.hsv});
      return this;
    } else {
      return color.hsv.v;
    }
  };

  Spectra.prototype.alpha = function(arg) {
    var color = this.color;
    if (arg) {
      color.a = arg;
      return this;
    } else {
      return color.a;
    }
  };

  /** Complement function */
  Spectra.prototype.complement = function() {
    var hsv = this.color.hsv;
    var newHsv = {s: hsv.s, v: hsv.v};
    newHsv.h = (hsv.h + 180) % 360;
    return new Spectra(newHsv);
  };

  /** Wrapper */
  var spectraWrapper = function(arg) {
    return new Spectra(arg);
  };

  Spectra.noConflict = function() {
    root.Spectra = oldSpectra;
    return this;
  };

  root.Spectra = spectraWrapper;
}).call(this);
<commit_msg>Update description in spectra.js.<commit_after>/**
 * Spectra.js
 *
 * Wrapping a value with Spectra() returns a Spectra object.
 *
 * The object's color value is as follows:
 * {
 *   rgb: {
 *     r: 0 to 255 [int],
 *     g: 0 to 255 [int],
 *     b: 0 to 255 [int],
 *   },
 *   hsv: {
 *     h: 0 to 360 [int],
 *     s: 0 to 1 [float],
 *     v: 0 to 1 [float]
 *   },
 *   a: 0 to 1 [float] // Alpha
 * }
 */

 (function() {
  var root = this;
  var oldSpectra = root.Spectra;

  /** Conversion functions between formats. */
  var rgbToHsv = function(rgb) {
    var hsv = {};
    var r = Number(rgb.r || rgb.red || 0) / 255;
    var g = Number(rgb.g || rgb.green || 0) / 255;
    var b = Number(rgb.b || rgb.blue || 0) / 255;
    var max = Math.max(r, g, b);
    var min = Math.min(r, g, b);
    var delta = max - min;

    hsv.v = max;
    if (hsv.v === 0) {
      hsv.h = 0;
      hsv.s = 0;
    } else {
      hsv.s = (max - min) / max;
      if (hsv.s === 0) {
        hsv.h = 0;
      } else {
        if (max === r) {
          hsv.h = (g - b) / delta;
        } else if (max === g) {
          hsv.h = 2 + (b - r) / delta;
        } else {
          hsv.h = 4 + (r - g) / delta;
        }
        hsv.h *= 60;
        if (hsv.h < 0) {
          hsv.h += 360;
        }
      }
    }

    return hsv;
  };

  var hsvToRgb = function(hsv) {
    var rgb = {r: 0, g: 0, b: 0};

    var h = Number(hsv.h || 0);
    var s = Number(hsv.s || 0);
    var v = Number(hsv.v || 0);
    var chroma = s * v;
    var hDash = h / 60;
    var x = chroma * (1 - Math.abs((hDash % 2) - 1));

    if(hDash < 1.0) {
      rgb.r = chroma;
      rgb.g = x;
    } else if (hDash < 2) {
      rgb.r = x;
      rgb.g = chroma;
    } else if (hDash < 3) {
      rgb.g = chroma;
      rgb.b = x;
    } else if (hDash < 4) {
      rgb.g= x;
      rgb.b = chroma;
    } else if (hDash < 5) {
      rgb.r = x;
      rgb.b = chroma;
    } else if (hDash <= 6) {
      rgb.r = chroma;
      rgb.b = x;
    }

    var min = v - chroma;

    rgb.r += min;
    rgb.g += min;
    rgb.b += min;

    rgb.r *= 255;
    rgb.g *= 255;
    rgb.b *= 255;

    return rgb;
  };

  var parseCss = function(css) {
    var color = {};
    var shorthandRegex = /^#[0-9a-f]{3}$/i;
    var shorthandMatch = css.match(shorthandRegex);
    if (shorthandMatch) {
      color.rgb = {
        r: parseInt(css.charAt(1), 16) * 0x11,
        g: parseInt(css.charAt(2), 16) * 0x11,
        b: parseInt(css.charAt(3), 16) * 0x11
      };
      return normalize(color);
    }
    var longhandRegex = /^#[0-9a-f]{6}$/i;
    var longhandMatch = css.match(longhandRegex);
    if (longhandMatch) {
      color.rgb = {
        r: parseInt(css.slice(1,3), 16),
        g: parseInt(css.slice(3,5), 16),
        b: parseInt(css.slice(5,7), 16)
      };
      return normalize(color);
    }
    var rgbRegex = /^rgb\(\s*([0-9]+),\s*([0-9]+),\s*([0-9]+)\s*\)$/i;
    var rgbMatch = css.match(rgbRegex);
    if (rgbMatch) {
      color.rgb = {
        r: parseInt(rgbMatch[1], 10),
        g: parseInt(rgbMatch[2], 10),
        b: parseInt(rgbMatch[3], 10)
      };
      return normalize(color);
    }
    var rgbaRegex = /^rgba\(\s*([0-9]+),\s*([0-9]+),\s*([0-9]+),\s*([0-9\.]+)\s*\)$/i;
    var rgbaMatch = css.match(rgbaRegex);
    if (rgbaMatch) {
      color.rgb = {
        r: parseInt(rgbaMatch[1], 10),
        g: parseInt(rgbaMatch[2], 10),
        b: parseInt(rgbaMatch[3], 10)
      };
      color.a = parseFloat(rgbaMatch[4], 10);
      return normalize(color);
    }
  };

  /** Normalization functions */
  var normalize = function(arg) {
    var color = arg;
    color.a = color.a || 1;

    if (color.rgb !== undefined) {
      color.hsv = rgbToHsv(color.rgb);
    } else if (color.hsv !== undefined) {
      color.rgb = hsvToRgb(color.hsv);
    } else if (color.css !== undefined) {
      return parseCss(color.css);
    }

    if (color.rgb.red !== undefined) {
      color.rgb.r = color.rgb.red;
    }
    if (color.rgb.green !== undefined) {
      color.rgb.g = color.rgb.green;
    }
    if (color.rgb.blue !== undefined) {
      color.rgb.b = color.rgb.blue;
    }

    return color;
  };

  /** Wrapper */
  var Spectra = function(arg) {
    if (typeof arg == 'object') {
      if (arg.r !== undefined || arg.red !== undefined) {
        this.color = normalize({rgb: arg, a: arg.a});
      }
      if (arg.v !== undefined || arg.value !== undefined) {
        this.color = normalize({hsv: arg, a: arg.a});
      }
    } else if (typeof arg == 'string') {
      this.color = normalize({css: arg});
    }
    return this;
  };

  /** Getters and Setters */
  Spectra.prototype.red = function(arg) {
    var color = this.color;
    if (arg) {
      color.rgb.r = arg;
      this.color = normalize({rgb: color.rgb});
      return this;
    } else {
      return Math.round(color.rgb.r);
    }
  };
  Spectra.prototype.green = function(arg) {
    var color = this.color;
    if (arg) {
      color.rgb.g = arg;
      this.color = normalize({rgb: color.rgb});
      return this;
    } else {
      return Math.round(color.rgb.g);
    }
  };
  Spectra.prototype.blue = function(arg) {
    var color = this.color;
    if (arg) {
      color.rgb.b = arg;
      this.color = normalize({rgb: color.rgb});
      return this;
    } else {
      return Math.round(color.rgb.b);
    }
  };

  Spectra.prototype.hue = function(arg) {
    var color = this.color;
    if (arg) {
      color.hsv.h = arg;
      this.color = normalize({hsv: color.hsv});
      return this;
    } else {
      return Math.round(color.hsv.h);
    }
  };
  Spectra.prototype.saturation = function(arg) {
    var color = this.color;
    if (arg) {
      color.hsv.s = arg;
      this.color = normalize({hsv: color.hsv});
      return this;
    } else {
      return color.hsv.s;
    }
  };
  Spectra.prototype.value = function(arg) {
    var color = this.color;
    if (arg) {
      color.hsv.v = arg;
      this.color = normalize({hsv: color.hsv});
      return this;
    } else {
      return color.hsv.v;
    }
  };

  Spectra.prototype.alpha = function(arg) {
    var color = this.color;
    if (arg) {
      color.a = arg;
      return this;
    } else {
      return color.a;
    }
  };

  /** Complement function */
  Spectra.prototype.complement = function() {
    var hsv = this.color.hsv;
    var newHsv = {s: hsv.s, v: hsv.v};
    newHsv.h = (hsv.h + 180) % 360;
    return new Spectra(newHsv);
  };

  /** Wrapper */
  var spectraWrapper = function(arg) {
    return new Spectra(arg);
  };

  Spectra.noConflict = function() {
    root.Spectra = oldSpectra;
    return this;
  };

  root.Spectra = spectraWrapper;
}).call(this);
<|endoftext|>


<commit_before>/* jslint node: true */
'use strict';

var MenuView		= require('./menu_view.js').MenuView;
var ansi			= require('./ansi_term.js');
var strUtil			= require('./string_util.js');
var miscUtil		= require('./misc_util.js');

var util			= require('util');
var assert			= require('assert');
var _				= require('lodash');

exports.VerticalMenuView		= VerticalMenuView;

function VerticalMenuView(options) {
	options.cursor = options.cursor || 'hide';

	MenuView.call(this, options);

	var self = this;

	//
	//	:TODO: view.setDimens() would set autoSize to false. Otherwise, we cna scale @ setItems()
	//	topViewIndex = top visibile item
	//	itemsInView = height * (1 + itemSpacing)

	this.updateViewable = function() {
		var viewableItems = self.dimens.height / ((self.itemSpacing + 1) - self.itemSpacing);
console.log(viewableItems)
		this.viewableRange = {
			top		: self.focusedItemIndex,
			bottom	: viewableItems - self.focusedItemIndex,
		};

		console.log(this.viewableRange)
	};

	this.scaleDimension = function() {
		if(this.autoScale) {
			this.dimens.height = (self.items.length * (self.itemSpacing + 1)) - (self.itemSpacing);
			this.dimens.height = Math.min(this.dimens.height, self.client.term.termHeight - self.position.x);

			var l = 0;
			self.items.forEach(function item(i) {
				if(i.text.length > l) {
					l = Math.min(i.text.length, self.client.term.termWidth - self.position.y);
				}
			});
			self.dimens.width = l;
		}
	};

	/*
	this.calculateDimens = function() {
		if(!self.dimens || !self.dimens.width) {
			var l = 0;
			self.items.forEach(function onItem(item) {
				if(item.text.length > l) {
					l = item.text.length;
				}
			});
			self.dimens = self.dimens || {};
			self.dimens.width = l;
		}

		if(this.items.length > 0) {
			this.dimens.height = (self.items.length * (self.itemSpacing + 1)) - (self.itemSpacing);
		} else {
			this.dimens.height = 0;
		}
	};
	*/

	this.scaleDimension();

	this.cacheVisiblePositions = function() {
		if(self.positionCacheExpired) {
			var x = self.position.x;
			for(var i = this.viewableRange.top; i < this.viewableRange.bottom; ++i) {
				if(i > 0) {
					x += self.itemSpacing + 1;
				}
				self.items[i].xPosition = x;
			}

			self.positionCacheExpired = false;
		}
	};

	this.scrollToVisible = function() {

	};

	this.cachePositions = function() {
		if(self.positionCacheExpired) {
			var count = this.items.length;
			var x = self.position.x;
			for(var i = 0; i < count; ++i) {
				if(i > 0) {
					x += self.itemSpacing + 1;
				}

				self.items[i].xPosition = x;
			}
			self.positionCacheExpired = false;
		}
	};

	this.changeSelection = function(fromIndex, toIndex) {
		assert(!self.positionCacheExpired);
		assert(fromIndex >= 0 && fromIndex <= self.items.length);
		assert(toIndex >= 0 && toIndex <= self.items.length);

		self.items[fromIndex].focused	= false;
		self.drawItem(fromIndex);

		self.items[toIndex].focused 	= true;
		self.focusedItemIndex			= toIndex;
		self.drawItem(toIndex);
	};

	this.drawItem = function(index) {
		assert(self.positionCacheExpired === false);

		var item = self.items[index];
		if(!item) {
			return;
		}

		self.client.term.write(ansi.goto(item.xPosition, self.position.y));
		self.client.term.write(index === self.focusedItemIndex ? self.getFocusSGR() : self.getSGR());

		var text = strUtil.stylizeString(item.text, item.focused ? self.focusTextStyle : self.textStyle);

		self.client.term.write(
			strUtil.pad(text, this.dimens.width, this.fillChar, this.justify));
	};
}

util.inherits(VerticalMenuView, MenuView);

VerticalMenuView.prototype.redraw = function() {
	//VerticalMenuView.super_.prototype.redrawAllItems.call(this);
	VerticalMenuView.super_.prototype.redraw.call(this);

	for(var i = this.viewableRange.top; i < this.viewableRange.bottom; ++i) {
		this.items[i].focused = this.focusedItemIndex === i;
		this.drawItem(i);
	}
};

VerticalMenuView.prototype.setPosition = function(pos) {
	VerticalMenuView.super_.prototype.setPosition.call(this, pos);

	this.positionCacheExpired = true;
};

VerticalMenuView.prototype.setFocus = function(focused) {
	VerticalMenuView.super_.prototype.setFocus.call(this, focused);

	this.redraw();
};

VerticalMenuView.prototype.onSpecialKeyPress = function(keyName) {

	var prevFocusedItemIndex = this.focusedItemIndex;

	if(this.isSpecialKeyMapped('up', keyName)) {
		if(0 === this.focusedItemIndex) {
			this.focusedItemIndex = this.items.length - 1;
		} else {
			this.focusedItemIndex--;
		}
	} else if(this.isSpecialKeyMapped('down', keyName)) {
		if(this.items.length - 1 === this.focusedItemIndex) {
			this.focusedItemIndex = 0;
		} else {
			this.focusedItemIndex++;
		}
	}

	if(prevFocusedItemIndex !== this.focusedItemIndex) {
		this.changeSelection(prevFocusedItemIndex, this.focusedItemIndex);
	}

	VerticalMenuView.super_.prototype.onSpecialKeyPress.call(this, keyName);
};

VerticalMenuView.prototype.getData = function() {
	return this.focusedItemIndex;
};

VerticalMenuView.prototype.setItems = function(items) {
	VerticalMenuView.super_.prototype.setItems.call(this, items);

	this.positionCacheExpired = true;
	this.cachePositions();
	this.scaleDimension();

	this.updateViewable();
};<commit_msg>* More WIP on VM redesign<commit_after>/* jslint node: true */
'use strict';

var MenuView		= require('./menu_view.js').MenuView;
var ansi			= require('./ansi_term.js');
var strUtil			= require('./string_util.js');
var miscUtil		= require('./misc_util.js');

var util			= require('util');
var assert			= require('assert');
var _				= require('lodash');

exports.VerticalMenuView		= VerticalMenuView;

function VerticalMenuView(options) {
	options.cursor = options.cursor || 'hide';

	MenuView.call(this, options);

	var self = this;

	//
	//	:TODO: view.setDimens() would set autoSize to false. Otherwise, we cna scale @ setItems()
	//	topViewIndex = top visible item
	//	itemsInView = height * (1 + itemSpacing)
	this.jumpVisibleToTop = function() {
		this.visibleRange = {
			top		: 0,
			bottom	: this.maxVisibleItems,
		};
	};

	this.jumpVisibleToBottom = function() {
		this.visibleRange = {
			top		: this.items.length - this.jumpVisibleToTop,
			bottom	: this.items.length,
		};
	};

	this.scaleDimension = function() {
		if(this.autoScale) {
			this.dimens.height = (self.items.length * (self.itemSpacing + 1)) - (self.itemSpacing);
			this.dimens.height = Math.min(this.dimens.height, self.client.term.termHeight - self.position.x);

			var l = 0;
			self.items.forEach(function item(i) {
				if(i.text.length > l) {
					l = Math.min(i.text.length, self.client.term.termWidth - self.position.y);
				}
			});
			self.dimens.width = l;
		}
	};

	/*
	this.calculateDimens = function() {
		if(!self.dimens || !self.dimens.width) {
			var l = 0;
			self.items.forEach(function onItem(item) {
				if(item.text.length > l) {
					l = item.text.length;
				}
			});
			self.dimens = self.dimens || {};
			self.dimens.width = l;
		}

		if(this.items.length > 0) {
			this.dimens.height = (self.items.length * (self.itemSpacing + 1)) - (self.itemSpacing);
		} else {
			this.dimens.height = 0;
		}
	};
	*/

	this.scaleDimension();

	this.cacheVisiblePositions = function() {
		if(self.positionCacheExpired) {
			var x = self.position.x;
			for(var i = this.visibleRange.top; i < this.visibleRange.bottom; ++i) {
				if(i > 0) {
					x += self.itemSpacing + 1;
				}
				self.items[i].xPosition = x;
			}

			self.positionCacheExpired = false;
		}
	};

	this.scrollToVisible = function() {

	};

	this.cachePositions = function() {
		if(self.positionCacheExpired) {
			var count = this.items.length;
			var x = self.position.x;
			for(var i = 0; i < count; ++i) {
				if(i > 0) {
					x += self.itemSpacing + 1;
				}

				self.items[i].xPosition = x;
			}
			self.positionCacheExpired = false;
		}
	};

	this.changeSelection2 = function(fromIndex, toIndex) {
		assert(!self.positionCacheExpired);
		assert(fromIndex >= 0 && fromIndex <= self.items.length);
		assert(toIndex >= 0 && toIndex <= self.items.length);

		if(fromIndex === self.items.length - 1 && fromIndex > toIndex) {
			console.log('jump to top')
			this.redraw();
			return;
		} else if(0 === fromIndex && toIndex > fromIndex) {
			console.log('jump to bottom')
			this.redraw();
			return;
		}

		/*if(fromIndex > toIndex && self.items.length === fromIndex) {
			console.log('jump to top')
			this.jumpVisibleToTop();
		} else if(0 === fromIndex && fromIndex < toIndex) {
			console.log('jump to bottom')
			this.jumpVisibleToBottom();
		}*/

	};

	this.changeSelection = function(fromIndex, toIndex) {
		assert(!self.positionCacheExpired);
		assert(fromIndex >= 0 && fromIndex <= self.items.length);
		assert(toIndex >= 0 && toIndex <= self.items.length);

		self.items[fromIndex].focused	= false;
		self.drawItem(fromIndex);

		self.items[toIndex].focused 	= true;
		self.focusedItemIndex			= toIndex;
		self.drawItem(toIndex);
	};

	this.drawItem = function(index) {
		assert(self.positionCacheExpired === false);

		var item = self.items[index];
		if(!item) {
			return;
		}

		self.client.term.write(ansi.goto(item.xPosition, self.position.y));
		self.client.term.write(index === self.focusedItemIndex ? self.getFocusSGR() : self.getSGR());

		var text = strUtil.stylizeString(item.text, item.focused ? self.focusTextStyle : self.textStyle);

		self.client.term.write(
			strUtil.pad(text, this.dimens.width, this.fillChar, this.justify));
	};
}

util.inherits(VerticalMenuView, MenuView);

VerticalMenuView.prototype.redraw = function() {
	VerticalMenuView.super_.prototype.redraw.call(this);

	for(var i = this.visibleRange.top; i < this.visibleRange.bottom; ++i) {
		this.items[i].focused = this.focusedItemIndex === i;
		this.drawItem(i);
	}
};

VerticalMenuView.prototype.setPosition = function(pos) {
	VerticalMenuView.super_.prototype.setPosition.call(this, pos);

	this.positionCacheExpired = true;
};

VerticalMenuView.prototype.setFocus = function(focused) {
	VerticalMenuView.super_.prototype.setFocus.call(this, focused);

	this.redraw();
};

VerticalMenuView.prototype.onSpecialKeyPress = function(keyName) {

	var prevFocusedItemIndex = this.focusedItemIndex;

	if(this.isSpecialKeyMapped('up', keyName)) {
		if(0 === this.focusedItemIndex) {
			this.focusedItemIndex = this.items.length - 1;
		} else {
			this.focusedItemIndex--;
		}
	} else if(this.isSpecialKeyMapped('down', keyName)) {
		if(this.items.length - 1 === this.focusedItemIndex) {
			this.focusedItemIndex = 0;
		} else {
			this.focusedItemIndex++;
		}
	}

	if(prevFocusedItemIndex !== this.focusedItemIndex) {
		this.changeSelection(prevFocusedItemIndex, this.focusedItemIndex);

		this.changeSelection2(prevFocusedItemIndex, this.focusedItemIndex);
	}

	VerticalMenuView.super_.prototype.onSpecialKeyPress.call(this, keyName);
};

VerticalMenuView.prototype.getData = function() {
	return this.focusedItemIndex;
};

VerticalMenuView.prototype.setItems = function(items) {
	VerticalMenuView.super_.prototype.setItems.call(this, items);

	this.positionCacheExpired = true;
	this.cachePositions();
	this.scaleDimension();

	this.maxVisibleItems = this.dimens.height / (this.itemSpacing + 1);

	this.jumpVisibleToTop();
};<|endoftext|>