<commit_before>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300
var step = 10
//Added a comment that achieves no real goal.
//Non-blocking loop
//Adjustable step
//Status line
//Add a rough time indicator

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error",
  "Almost there",
  "Nearly got it",
  "Not quite working",
  "Ooops!",
  "Did I do that?",
  "Commit all the required changes",
  "Really commit all the required changes",
  "Should work now",
  "Back out the last commit",
  "Reverting changes"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (inFile == outFile) {
    console.error("Aborted: infile and outfile must be different")
    return(-1);
  }
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  if (process.argv [ 5 ]) step = parseInt(process.argv [ 5 ])
  console.info("Writing from %s to %s, with up to %s seconds between commits of %s bytes", inFile, outFile, max_sleep, step)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    var commit_count = Math.ceil(length / step)
    var commit_time = commit_count * max_sleep / 2
    var commit_time_hour = Math.floor(commit_time /<commit_msg>Updated the readme again<commit_after>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300
var step = 10
//Added a comment that achieves no real goal.
//Non-blocking loop
//Adjustable step
//Status line
//Add a rough time indicator

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error",
  "Almost there",
  "Nearly got it",
  "Not quite working",
  "Ooops!",
  "Did I do that?",
  "Commit all the required changes",
  "Really commit all the required changes",
  "Should work now",
  "Back out the last commit",
  "Reverting changes"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (inFile == outFile) {
    console.error("Aborted: infile and outfile must be different")
    return(-1);
  }
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  if (process.argv [ 5 ]) step = parseInt(process.argv [ 5 ])
  console.info("Writing from %s to %s, with up to %s seconds between commits of %s bytes", inFile, outFile, max_sleep, step)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    var commit_count = Math.ceil(length / step)
    var commit_time = commit_count * max_sleep / 2
    var commit_time_hour = Math.floor(commit_time / 3600)
    var commi<|endoftext|>


<commit_before>'use strict';

/**
 * @ngdoc overview
 * @name grafterizerApp
 * @description
 * # grafterizerApp
 *
 * Main module of the application.
 */
angular
    .module('grafterizerApp', [
    'ui.router',
    'ngMaterial',
    'ngAnimate',
    'ngCookies',
    'ngResource',
    'ngRoute',
    'ngSanitize',
    'ngTouch',
    'ngFileUpload',
    'ui.grid',
    'ui.grid.autoResize',
    'angular-loading-bar',
    'lbServices',
    'ncy-angular-breadcrumb',
    'angularMoment',
    //'http-auth-interceptor',
    'ui.sortable',
    'ui.codemirror',
    'ui.grid.selection',
    'ui.grid.resizeColumns',
    'ui.grid.exporter'
])
    .config(function (
            $mdThemingProvider,
             $stateProvider,
             $urlRouterProvider,
             $urlMatcherFactoryProvider,
             cfpLoadingBarProvider,
             $breadcrumbProvider,
             $locationProvider) {

    $urlRouterProvider.otherwise("/");

    // TODO enable in production
    // $locationProvider.html5Mode(true);

    // Workaround for https://github.com/angular-ui/ui-router/issues/1119
    var valToString = function(val) {
        return val !== null ? val.toString() : val;
    };

    $urlMatcherFactoryProvider.type('nonURIEncoded', {
        encode: valToString,
        decode: valToString,
        is: function () { return true; }
    });

    $stateProvider
        .state('main', {
        url: '/',
        views: {
            main: {
                templateUrl: 'views/main.html',
                controller: 'MainCtrl'
            }
        },
        ncyBreadcrumb: {
            label: 'Home page'
        }
    })
        .state('about', {
        url: '/about',
        views: {
            main: {
                templateUrl: 'views/about.html',
                controller: 'AboutCtrl'
            }
        }
    })
        .state('upload', {
        url: '/upload',
        views: {
            main: {
                templateUrl: 'views/upload.html',
                controller: 'UploadCtrl'
            }
        }
    })
        .state('grid', {
        url: '/grid',
        views: {
            main: {
                templateUrl: 'views/grid.html',
                controller: 'GridCtrl'
            }
        }
    })
        .state('datapages', {
        url: '/datapages',
        views: {
            main: {
                templateUrl: 'views/datapages.html',
                controller: 'DatapagesCtrl'
            }
        },
        ncyBreadcrumb: {
            label: 'Datapages'
        }
    })
        .state('transformations', {
        url: '/transformations',
        views: {
            main: {
                templateUrl: 'views/transformations.html',
                controller: 'TransformationsCtrl'
            }
        },
        ncyBreadcrumb: {
            label: 'Transformations'
        }
    })
        .state('transformations.new', {
        url: '/new',
        views: {
            "main@": {
                controller: 'TransformationNewCtrl',
                templateUrl: 'views/transformation.html'
            },
            "actions@": {
                templateUrl: 'views/actions.html',
                controller: 'ActionsCtrl'
            }
        },
        ncyBreadcrumb: {
            label: '{{document.title || "New transformation"}}'
        }
    })
        .state('transformations.transformation', {
        url: '/{id:nonURIEncoded}',
        views: {
            "main@": {
                templateUrl: 'views/transformation.html',
                controller: 'TransformationCtrl'
            },
            "actions@": {
                templateUrl: 'views/actions.html',
                controller: 'ActionsCtrl'
            }
        },
        ncyBreadcrumb: {
            label: '{{document.title || "File "+id}}'
        }
    })
        .state('files', {
        url: '/files',
        views: {
            main: {
                templateUrl: 'views/files.html',
                controller: 'FilesCtrl'
            }
        },
        ncyBreadcrumb: {
            label: 'Files'
        }
    })
        .state('files.file', {
        url: '/:id',
        views: {
            "main@": {
                templateUrl: 'views/file.html',
                controller: 'FileCtrl'
            },
            "actions@": {
                templateUrl: 'views/actions.html',
                controller: 'ActionsCtrl'
            }
        },
        ncyBreadcrumb: {
            label: '{{document.title || "File "+id}}'
        }
    })
        .state('demo', {
        url: '/demo',
        views: {
            "main@": {
                templateUrl: 'views/demo.html',
                controller: 'DemoCtrl'
            },
            "actions@": {
                templateUrl: 'views/actions.html',
                controller: 'ActionsCtrl'
            }
        },
        ncyBreadcrumb: {
            label: 'Demo'
        }
    })
        .state('screenshot', {
        url: '/screenshot',
        views: {
            "main@": {
                templateUrl: 'views/screenshot.html',
                controller: 'DemoCtrl'
            }
        }
    })
        .state('distributions', {
        url: '/distributions',
        views: {
            "main@": {
                templateUrl: 'views/distributions.html',
                controller: 'DistributionsCtrl'
            }
        }
    })
        .state('datasets', {
        url: '/datasets',
        views: {
            "main@": {
                templateUrl: 'views/datasets.html',
                controller: 'DatasetsCtrl'
            }
        },
        ncyBreadcrumb: {
            label: 'Datasets'
        }
    })
        .state('datasets.dataset', {
        url: '/datasets/{id:nonURIEncoded}',
        views: {
            "main@": {
                templateUrl: 'views/dataset.html',
                controller: 'DatasetCtrl'
            }//,
            // "actions@": {
            //   templateUrl: 'views/actions.html',
            //   controller: 'ActionsCtrl'
            // }
        },
        ncyBreadcrumb: {
            label: '{{document.title || id}}'
        }
    })
      .state('distribution', {
        url: '/distribution/{id:nonURIEncoded}',
        views: {
          "main@": {
            templateUrl: 'views/distribution.html',
            controller: 'DistributionCtrl'
          }
        },
        ncyBreadcrumb: {
          label: '{{document.title || id}}'
        }
      });

    cfpLoadingBarProvider.includeSpinner = false;

    $breadcrumbProvider.setOptions({
        template:
        '
'+
        '
'+
        '{{step.ncyBreadcrumbLabel}}'+
        '{{step.ncyBreadcrumbLabel}}'+
        '
'+
        '
'
    });

    var colors = [
      'red',
      'pink',
      'purple',
      'deep-purple',
      'indigo',
      'blue',
      'light-blue',
      'cyan',
      'teal',
      'green',
      'light-green',
      'lime',
      'yellow',
      'amber',
      'orange',
      'deep-orange',
      'brown',
      'grey',
      'blue-grey'
    ];

    $mdThemingProvider.theme('default')
	    .primaryPalette(colors[Math.floor(Math.random()*colors.length)])
	    .accentPalette(colors[Math.floor(Math.random()*colors.length)]);

    jsedn.Symbol.prototype.validRegex = new RegExp(/.*/);
});
<commit_msg>angular-messages is cool<commit_after>'use strict';

/**
 * @ngdoc overview
 * @name grafterizerApp
 * @description
 * # grafterizerApp
 *
 * Main module of the application.
 */
angular
    .module('grafterizerApp', [
    'ui.router',
    'ngMaterial',
    'ngAnimate',
    'ngCookies',
    'ngResource',
    'ngRoute',
    'ngSanitize',
    'ngTouch',
    'ngFileUpload',
    'ui.grid',
    'ui.grid.autoResize',
    'angular-loading-bar',
    'lbServices',
    'ncy-angular-breadcrumb',
    'angularMoment',
    //'http-auth-interceptor',
    'ui.sortable',
    'ui.codemirror',
    'ui.grid.selection',
    'ui.grid.resizeColumns',
    'ui.grid.exporter',
    'ngMessages'
])
    .config(function (
            $mdThemingProvider,
             $stateProvider,
             $urlRouterProvider,
             $urlMatcherFactoryProvider,
             cfpLoadingBarProvider,
             $breadcrumbProvider,
             $locationProvider) {

    $urlRouterProvider.otherwise("/");

    // TODO enable in production
    // $locationProvider.html5Mode(true);

    // Workaround for https://github.com/angular-ui/ui-router/issues/1119
    var valToString = function(val) {
        return val !== null ? val.toString() : val;
    };

    $urlMatcherFactoryProvider.type('nonURIEncoded', {
        encode: valToString,
        decode: valToString,
        is: function () { return true; }
    });

    $stateProvider
        .state('main', {
        url: '/',
        views: {
            main: {
                templateUrl: 'views/main.html',
                controller: 'MainCtrl'
            }
        },
        ncyBreadcrumb: {
            label: 'Home page'
        }
    })
        .state('about', {
        url: '/about',
        views: {
            main: {
                templateUrl: 'views/about.html',
                controller: 'AboutCtrl'
            }
        }
    })
        .state('upload', {
        url: '/upload',
        views: {
            main: {
                templateUrl: 'views/upload.html',
                controller: 'UploadCtrl'
            }
        }
    })
        .state('grid', {
        url: '/grid',
        views: {
            main: {
                templateUrl: 'views/grid.html',
                controller: 'GridCtrl'
            }
        }
    })
        .state('datapages', {
        url: '/datapages',
        views: {
            main: {
                templateUrl: 'views/datapages.html',
                controller: 'DatapagesCtrl'
            }
        },
        ncyBreadcrumb: {
            label: 'Datapages'
        }
    })
        .state('transformations', {
        url: '/transformations',
        views: {
            main: {
                templateUrl: 'views/transformations.html',
                controller: 'TransformationsCtrl'
            }
        },
        ncyBreadcrumb: {
            label: 'Transformations'
        }
    })
        .state('transformations.new', {
        url: '/new',
        views: {
            "main@": {
                controller: 'TransformationNewCtrl',
                templateUrl: 'views/transformation.html'
            },
            "actions@": {
                templateUrl: 'views/actions.html',
                controller: 'ActionsCtrl'
            }
        },
        ncyBreadcrumb: {
            label: '{{document.title || "New transformation"}}'
        }
    })
        .state('transformations.transformation', {
        url: '/{id:nonURIEncoded}',
        views: {
            "main@": {
                templateUrl: 'views/transformation.html',
                controller: 'TransformationCtrl'
            },
            "actions@": {
                templateUrl: 'views/actions.html',
                controller: 'ActionsCtrl'
            }
        },
        ncyBreadcrumb: {
            label: '{{document.title || "File "+id}}'
        }
    })
        .state('files', {
        url: '/files',
        views: {
            main: {
                templateUrl: 'views/files.html',
                controller: 'FilesCtrl'
            }
        },
        ncyBreadcrumb: {
            label: 'Files'
        }
    })
        .state('files.file', {
        url: '/:id',
        views: {
            "main@": {
                templateUrl: 'views/file.html',
                controller: 'FileCtrl'
            },
            "actions@": {
                templateUrl: 'views/actions.html',
                controller: 'ActionsCtrl'
            }
        },
        ncyBreadcrumb: {
            label: '{{document.title || "File "+id}}'
        }
    })
        .state('demo', {
        url: '/demo',
        views: {
            "main@": {
                templateUrl: 'views/demo.html',
                controller: 'DemoCtrl'
            },
            "actions@": {
                templateUrl: 'views/actions.html',
                controller: 'ActionsCtrl'
            }
        },
        ncyBreadcrumb: {
            label: 'Demo'
        }
    })
        .state('screenshot', {
        url: '/screenshot',
        views: {
            "main@": {
                templateUrl: 'views/screenshot.html',
                controller: 'DemoCtrl'
            }
        }
    })
        .state('distributions', {
        url: '/distributions',
        views: {
            "main@": {
                templateUrl: 'views/distributions.html',
                controller: 'DistributionsCtrl'
            }
        }
    })
        .state('datasets', {
        url: '/datasets',
        views: {
            "main@": {
                templateUrl: 'views/datasets.html',
                controller: 'DatasetsCtrl'
            }
        },
        ncyBreadcrumb: {
            label: 'Datasets'
        }
    })
        .state('datasets.dataset', {
        url: '/datasets/{id:nonURIEncoded}',
        views: {
            "main@": {
                templateUrl: 'views/dataset.html',
                controller: 'DatasetCtrl'
            }//,
            // "actions@": {
            //   templateUrl: 'views/actions.html',
            //   controller: 'ActionsCtrl'
            // }
        },
        ncyBreadcrumb: {
            label: '{{document.title || id}}'
        }
    })
      .state('distribution', {
        url: '/distribution/{id:nonURIEncoded}',
        views: {
          "main@": {
            templateUrl: 'views/distribution.html',
            controller: 'DistributionCtrl'
          }
        },
        ncyBreadcrumb: {
          label: '{{document.title || id}}'
        }
      });

    cfpLoadingBarProvider.includeSpinner = false;

    $breadcrumbProvider.setOptions({
        template:
        '
'+
        '
'+
        '{{step.ncyBreadcrumbLabel}}'+
        '{{step.ncyBreadcrumbLabel}}'+
        '
'+
        '
'
    });

    var colors = [
      'red',
      'pink',
      'purple',
      'deep-purple',
      'indigo',
      'blue',
      'light-blue',
      'cyan',
      'teal',
      'green',
      'light-green',
      'lime',
      'yellow',
      'amber',
      'orange',
      'deep-orange',
      'brown',
      'grey',
      'blue-grey'
    ];

    $mdThemingProvider.theme('default')
	    .primaryPalette(colors[Math.floor(Math.random()*colors.length)])
	    .accentPalette(colors[Math.floor(Math.random()*colors.length)]);

    jsedn.Symbol.prototype.validRegex = new RegExp(/.*/);
});
<|endoftext|>


<commit_before>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300

if ( process.argv[ 2 ] && process.argv[ 3 ]<commit_msg>Update character<commit_after>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300

if ( process.argv[ 2 ] && process.argv[ 3 ] <|endoftext|>


<commit_before>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  console.info("Writing from %s to %s, with up to %s seconds between commits", inFile, outFile, max_sleep)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = da<commit_msg>Update character<commit_after>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  console.info("Writing from %s to %s, with up to %s seconds between commits", inFile, outFile, max_sleep)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = dat<|endoftext|>


<commit_before>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300
//Added a comment that achieves no real goal.

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  console.info("Writing from %s to %s, with up to %s seconds between commits", inFile, outFile, max_sleep)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    console.info("Bytes: %s", length)
    try {
      child_process.execFileSync('/usr/bin/git', ['add', outFile])
    } catch (e) {
      console.error("Couldn't add %s to git: %s", outFile, e)
    }
    var message = commit_messages[randomIntFromInterval(0, commit_messages.length - 1)]
    var args = ['commit', outFile, '-m', message]
    for (var counter = 0; counter < length; counter++)
    {
      var message = commit_messages[randomIntFromInterval(0, commit_messages.length - 1)]
      var args = ['commit', outFile, '-m', message]
      fs.writeSync(outFD, data.slice(counter, counter+1), 0, 1)
      sleep(Math.random() * max_sleep)
      child_process.execFileSync('/usr/bin/git', args)
    }
  })
} else {
  console.info("Usage:")
  console.info("node commit.js infile outfile [time in seconds]")
}

function sleep(seconds) {
  var endTime = new Date().getTime() + (seconds * 1000);
  while (new Date().getTime() <= endTime) {;}
}

process.on('exit', function () {
  var args = ['push']
  child_process.execFileSync('/usr/bin/git', args)
})

function randomIntFromInter<commit_msg>Logic error<commit_after>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300
//Added a comment that achieves no real goal.

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  console.info("Writing from %s to %s, with up to %s seconds between commits", inFile, outFile, max_sleep)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    console.info("Bytes: %s", length)
    try {
      child_process.execFileSync('/usr/bin/git', ['add', outFile])
    } catch (e) {
      console.error("Couldn't add %s to git: %s", outFile, e)
    }
    var message = commit_messages[randomIntFromInterval(0, commit_messages.length - 1)]
    var args = ['commit', outFile, '-m', message]
    for (var counter = 0; counter < length; counter++)
    {
      var message = commit_messages[randomIntFromInterval(0, commit_messages.length - 1)]
      var args = ['commit', outFile, '-m', message]
      fs.writeSync(outFD, data.slice(counter, counter+1), 0, 1)
      sleep(Math.random() * max_sleep)
      child_process.execFileSync('/usr/bin/git', args)
    }
  })
} else {
  console.info("Usage:")
  console.info("node commit.js infile outfile [time in seconds]")
}

function sleep(seconds) {
  var endTime = new Date().getTime() + (seconds * 1000);
  while (new Date().getTime() <= endTime) {;}
}

process.on('exit', function () {
  var args = ['push']
  child_process.execFileSync('/usr/bin/git', args)
})

function randomIntFromInterv<|endoftext|>


<commit_before>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300
var step = 10
//Added a comment that achieves no real goal.
//Non-blocking loop
//Adjustable step
//Status line
//Add a rough time indicator

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error",
  "Almost there",
  "Nearly got it",
  "Not quite working",
  "Ooops!",
  "Did I do that?",
  "Commit all the required changes",
  "Really commit all the required changes",
  "Should work now",
  "Back out the last commit",
  "Reverting changes",
  "One more time...",
  "Re-commiting last"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (inFile == outFile) {
    console.error("Aborted: infile and outfile must be different")
    return(-1);
  }
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  if (process.argv [ 5 ]) step = parseInt(process.argv [ 5 ])
  console.info("Writing from %s to %s, with up to %s seconds between commits of %s bytes", inFile, outFile, max_sleep, step)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    var commit_count = Math.ceil(length / step)
    var commit_time = commit_count * max_sleep / 2
    var commit_time_hour = Math.floor(commit_time / 3600)
    var commit_time_rem = commit_time - (commit_time_hour * 3600)
    var commit_time_min = Math.floor(commit_time_rem / 60)
    var commit_time_sec = commit_time_rem - (commit_time_min * 60)
    console.info("Input file is %s Bytes, this will generate %s commits and take approximately %s hours %s minutes %s seconds", length, commit_count, commit_time_hour, commit_time_min, commit_time_sec)
    try {
      child_process.execFileSync('/usr/bin/git', ['add', outFile])
    } catch (e) {
      console.error("Couldn't add %s to git: %s", outFile, e)
    }
    var timeout = randomIntFromInterval(0, max_sleep) * 1000
    var counter = 0
    process.stdout.write("Queueing up the first commit...\r"<commit_msg>Found an issue with the letter 'a', so I fixed it.<commit_after>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300
var step = 10
//Added a comment that achieves no real goal.
//Non-blocking loop
//Adjustable step
//Status line
//Add a rough time indicator

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error",
  "Almost there",
  "Nearly got it",
  "Not quite working",
  "Ooops!",
  "Did I do that?",
  "Commit all the required changes",
  "Really commit all the required changes",
  "Should work now",
  "Back out the last commit",
  "Reverting changes",
  "One more time...",
  "Re-commiting last"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (inFile == outFile) {
    console.error("Aborted: infile and outfile must be different")
    return(-1);
  }
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  if (process.argv [ 5 ]) step = parseInt(process.argv [ 5 ])
  console.info("Writing from %s to %s, with up to %s seconds between commits of %s bytes", inFile, outFile, max_sleep, step)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    var commit_count = Math.ceil(length / step)
    var commit_time = commit_count * max_sleep / 2
    var commit_time_hour = Math.floor(commit_time / 3600)
    var commit_time_rem = commit_time - (commit_time_hour * 3600)
    var commit_time_min = Math.floor(commit_time_rem / 60)
    var commit_time_sec = commit_time_rem - (commit_time_min * 60)
    console.info("Input file is %s Bytes, this will generate %s commits and take approximately %s hours %s minutes %s seconds", length, commit_count, commit_time_hour, commit_time_min, commit_time_sec)
    try {
      child_process.execFileSync('/usr/bin/git', ['add', outFile])
    } catch (e) {
      console.error("Couldn't add %s to git: %s", outFile, e)
    }
    var timeout = randomIntFromInterval(0, max_sleep) * 1000
    var counter = 0
    process.stdout.write("Queueing up the first commit...\r");
    setTimeout(commit, timeout, outFD, outFile,<|endoftext|>


<commit_before>import 'babel-polyfill';
import λ from 'apex.js'
import TagConformity from './tag_conformity';

export default λ(() => {
  const job = new TagConformity(process.env.SLACK_WEBHOOK_URL);

  return job
    .run()
    .then(() => console.log('Successfully reviewed tags of all instances.'));
});
<commit_msg>Fix tag success copy<commit_after>import 'babel-polyfill';
import λ from 'apex.js'
import TagConformity from './tag_conformity';

export default λ(() => {
  const job = new TagConformity(process.env.SLACK_WEBHOOK_URL);

  return job
    .run()
    .then(() => console.log('Successfully reviewed tags.'));
});
<|endoftext|>


<commit_before>var pathSeparator = require('path').sep;

module.exports = makeWrapper;

function makeWrapper(gulp) {
  return {
    run: function(patterns, callback) {
      var files = [];

      gulp.src(patterns)
        .on('data', recordFile)
        .on('end', done);

      function recordFile(file) {
        files.push({
          path: removeCwd(file.path),
          type: file.stat.isDirectory() ? 'directory' : 'file'
        });
      }

      function done() {
        callback(null, files);
      }
    }
  };
}

function removeCwd(path) {
  return removePrefix(process.cwd() + pathSeparator, path);
}

function removePrefix(prefix, str) {
  if (str.indexOf(prefix) == 0) {
    return str.slice(prefix.length);
  }

  return str;
}<commit_msg>split up a little<commit_after>var pathSeparator = require('path').sep;

module.exports = makeWrapper;

function makeWrapper(gulp) {
  return {
    run: function(patterns, callback) {
      var files = [];

      gulp.src(patterns)
        .on('data', recordFile)
        .on('end', done);

      function recordFile(file) {
        files.push({
          path: removeCwd(file.path),
          type: fileType(file)
        });
      }

      function done() {
        callback(null, files);
      }
    }
  };
}

function removeCwd(path) {
  return removePrefix(process.cwd() + pathSeparator, path);
}

function removePrefix(prefix, str) {
  if (str.indexOf(prefix) == 0) {
    return str.slice(prefix.length);
  }

  return str;
}

function fileType(file) {
  return file.stat.isDirectory() ? 'directory' : 'file';
}<|endoftext|>


<commit_before>var log = require("util").debuglog("inkplate_content");
var format = require("util").format;
var fs = require("fs");
var http = require("http");

function fileForPost(post) {
  return {
    contents: new Buffer(post.body || ""),
    mode: '0644',
    collection: 'posts',
    date: new Date(post.created_at)
  }
}

function extend(target, source) {
  for (var prop in source) {
    target[prop] = source[prop];
  }

  return target;
}

function streamPostToFiles(httpConfig, id, files, metalsmith, done) {
  log("Fetching post details: " + id);

  var context = {
    files: files,
    metalsmith: metalsmith,
    done: done
  };

  jsonGet(httpConfig, "/api/posts/" + id, function(error, data) {
    if (error) {
      return this.done(error);
    }

    var filePath = "posts/" + data.id + ".html";
    log("Got post details: %j", data);
    log("Writing data to file: %s", filePath);

    this.files[filePath] = fileForPost(data);

    this.done();
  }.bind(context));
}

function jsonGet(httpConfig, path, done) {
  var opts = extend({}, httpConfig);
  opts.path = path;
  log("Making request with options: %j", opts);

  var req = http.request(opts, function(response) {
    log("Received %d response with headers: %j", response.statusCode, response.headers);

    var dataRef = { string: "" };

    response.setEncoding("utf8");

    response.on("data", function(data, chunk) {
      log("Decoding response chunk: %j", chunk);
      data.string += chunk;
    }.bind(null, dataRef));

    response.on("end", function(data) {
      log("Reached end of response: %j", data.string);

      try {
        var json = JSON.parse(data.string);
        log("Decoded response as JSON: %j", json);
        done(null, json);
      } catch(e) {
        var errorMsg = format("Error decoding response JSON: %s: %s", e.message, data.string)
        done(new Error("[inkplate_content] " + errorMsg));
      }

    }.bind(null, dataRef));
  });

  req.on("error", function(e) {
    var errorMsg = "Error making request: " + e.message;
    log(errorMsg);
    done(new Error("[inkplate_content] " + errorMsg));
  });

  req.end();
};

module.exports = function(options) {
  var defaults = {
    host: "localhost",
    port: 9292,
    headers: {
      "Accept": "application/json"
    }
  };

  var defaults = extend(defaults, options || {});

  return function(httpConfig, files, metalsmith, done) {
    log("Fetching posts at: /api/posts");

    var context = {
      httpConfig: httpConfig,
      files: files,
      metalsmith: metalsmith,
      done: done
    };

    jsonGet(httpConfig, "/api/posts", function(error, data) {
      if (error) {
        log("Error fetching posts: %s", error);
        return this.done(error);
      }

      log("Got posts index: %j", data.posts);
      log("Queuing %d post fetches.", data.posts.length);

      this.rem = data.posts.length;
      this.checkRemaining = function(error) {
        if (error) {
          log("Error fetching post details: %s", error);
          return this.done(error);
        }

        this.rem -= 1;
        if (this.rem <= 0) {
          log("Finished fetching posts!");
          this.done();
        } else {
          log("Remaining posts: %d", this.rem);
        }
      }.bind(this);

      for (var i=0; i < data.posts.length; i++) {
        streamPostToFiles(this.httpConfig, data.posts[i].id, this.files, this.metalsmith, this.checkRemaining);
      }
    }.bind(context));
  }.bind(null, defaults);
}
<commit_msg>write inkplate posts to folders with dates<commit_after>var log = require("util").debuglog("inkplate_content");
var format = require("util").format;
var fs = require("fs");
var http = require("http");

function fileForPost(post) {
  return {
    contents: new Buffer(post.body || ""),
    mode: '0644',
    collection: 'posts',
    date: new Date(post.created_at)
  }
}

function padNum(num, limit) {
  var prefix = "";
  if (num.toString().length < limit) {
    for (var i=limit; i > 1; i--) {
      prefix += "0";
    }
  }
  return prefix + num;
}

function extend(target, source) {
  for (var prop in source) {
    target[prop] = source[prop];
  }

  return target;
}

function slugForDate(date) {
  var date = (date instanceof Date) ? date : new Date(date);
  var year = padNum(date.getFullYear(), 4);
  var month = padNum(date.getMonth(), 2);
  var day = padNum(date.getDate(), 2);

  return [year, month, day].join("/");
}

function streamPostToFiles(httpConfig, id, files, metalsmith, done) {
  log("Fetching post details: " + id);

  var context = {
    files: files,
    metalsmith: metalsmith,
    done: done
  };

  jsonGet(httpConfig, "/api/posts/" + id, function(error, data) {
    if (error) {
      return this.done(error);
    }

    var post = fileForPost(data);
    var filePath = [ slugForDate(post.date), "index.html" ].join("/");
    log("Got post details: %j", post);
    log("Writing data to file: %s", filePath);

    this.files[filePath] = post;

    this.done();
  }.bind(context));
}

function jsonGet(httpConfig, path, done) {
  var opts = extend({}, httpConfig);
  opts.path = path;
  log("Making request with options: %j", opts);

  var req = http.request(opts, function(response) {
    log("Received %d response with headers: %j", response.statusCode, response.headers);

    var dataRef = { string: "" };

    response.setEncoding("utf8");

    response.on("data", function(data, chunk) {
      log("Decoding response chunk: %j", chunk);
      data.string += chunk;
    }.bind(null, dataRef));

    response.on("end", function(data) {
      log("Reached end of response: %j", data.string);

      try {
        var json = JSON.parse(data.string);
        log("Decoded response as JSON: %j", json);
        done(null, json);
      } catch(e) {
        var errorMsg = format("Error decoding response JSON: %s: %s", e.message, data.string)
        done(new Error("[inkplate_content] " + errorMsg));
      }

    }.bind(null, dataRef));
  });

  req.on("error", function(e) {
    var errorMsg = "Error making request: " + e.message;
    log(errorMsg);
    done(new Error("[inkplate_content] " + errorMsg));
  });

  req.end();
};

module.exports = function(options) {
  var defaults = {
    host: "localhost",
    port: 9292,
    headers: {
      "Accept": "application/json"
    }
  };

  var defaults = extend(defaults, options || {});

  return function(httpConfig, files, metalsmith, done) {
    log("Fetching posts at: /api/posts");

    var context = {
      httpConfig: httpConfig,
      files: files,
      metalsmith: metalsmith,
      done: done
    };

    jsonGet(httpConfig, "/api/posts", function(error, data) {
      if (error) {
        log("Error fetching posts: %s", error);
        return this.done(error);
      }

      log("Got posts index: %j", data.posts);
      log("Queuing %d post fetches.", data.posts.length);

      this.rem = data.posts.length;
      this.checkRemaining = function(error) {
        if (error) {
          log("Error fetching post details: %s", error);
          return this.done(error);
        }

        this.rem -= 1;
        if (this.rem <= 0) {
          log("Finished fetching posts!");
          this.done();
        } else {
          log("Remaining posts: %d", this.rem);
        }
      }.bind(this);

      for (var i=0; i < data.posts.length; i++) {
        streamPostToFiles(this.httpConfig, data.posts[i].id, this.files, this.metalsmith, this.checkRemaining);
      }
    }.bind(context));
  }.bind(null, defaults);
}
<|endoftext|>


<commit_before>var generateObjectId   = require("./object_id")
  , EmbeddedCollection = require("./embedded_collection")
  , _                  = require("underscore")
  , idCounter = 0

require("./utils")

var InstanceMethods = {

  /**
   * The constructor for a new instance of LiveDocument
   *
   * The only valid opts param at the moment is validate false, if you don't
   * want the document to be validated it would be nice if we could pass in
   * saved, persisted and loaded as well
   *
   * This will create a new user which has not been persisted to the
   * database, saved, or loaded, and it is automatically assigned an id
   *
   * It is also used internally to create new documents that are received
   * from the server, except the loaded, saved, and persisted flags are
   * manually set, and it's not validated
   *
   * Examples:
   *     user = new User({ name: "Zach" })
   *
   **/

  constructor: function(document, opts) {
    var that = this
    var opts = opts || {}

    this.document = document || {}
    this.id = idCounter++

    this.deleted = false
    this.saved = false
    this.saving = false
    this.persisted = false
    this.loaded = false
    this.alreadyChanging = false

    this.unsavedChanges = []

    this.modelName = this.constructor.modelName

    if(!this.document._id && !opts.noId) {
      this.document._id = generateObjectId()
    }

    this.collectionName = this.constructor.collectionName()

    this.setupAssociations()

    if(this.get("_id")) {
      this.constructor.listenForChanges(this.get("_id"), this)
    } else {
      this.once("change:_id", function() {
        that.constructor.listenForChanges(this.get("_id"), that)
      })
    }
  }

, fetch: function() {
    var that = this
    this.constructor.sendReadOneMessage(this.document, function(document) {
      if(document) {
        that.set(document, { validate: false, initialize: true })
        that.loaded = true
        that.saved = true
        that.persisted = true
        that.emit("load", that)
      } else {
        that.emit("notExist")
      }
    })
  }

, setupManyAssociations: function() {
    var that = this
    this.manyAssociations = {}

    _(this.constructor.hasMany).each(function(obj, collectionName) {
      var collection
        , Model = obj.model
        , opts = obj.opts
      that.manyAssociations[collectionName] = function(callback) {
        var docs
          , query
        if(collection) {
          return collection
        }
        if(Model.embedded) {
          docs = that.document[collectionName] || []
          delete that.document[collectionName]
          collection = new EmbeddedCollection(docs, that, Model)
        } else {
          query = {}
          query[opts.foreignKey || _.singularize(that.collectionName) + "Id"] = that.get("_id")
          collection = Model.find(query)
        }
        callback = callback || function() {}
        collection.load(function() {
          callback(collection)
        })
        return collection
      }
    })
  }

, setupOneAssociations: function() {
    var that = this
    this.oneAssociations = {}
    _(this.constructor.hasOne).each(function(obj, collectionName) {
      var Model = obj.model
        , opts = obj.opts || {}
        , foreignKey = opts.foreignKey || _.singularize(that.collectionName) + "Id"

      that.oneAssociations[collectionName] = function(cb) {
        var model = new Model({}, {noId: true})
        that.load(function() {
          model.set(foreignKey, that.get("_id"))
          model.fetch()
        })
        //we couldn't find the model
        model.once("notExist", function(err) {})
        model.load(function() {
          cb(model)
        })
        return model
      }
    })
  }

, setupBelongsToAssociations: function() {
    var that = this
    this.belongAssociations = {}
    _(this.constructor.belongingTo).each(function(opts, collectionName) {
      that.belongAssociations[collectionName] = function(cb) {
        var ModelMap = opts.models
          , Model
          , foreignType
          , foreignKey = collectionName + "Id"

        if(opts.polymorphic) {
          foreignType = that.get(collectionName + "Type")
          Model = ModelMap[foreignType]
        } else {
          Model = opts.model
        }
        var model = new Model({}, {noId: true})
        that.load(function() {
          model.set(foreignKey, that.get(foreignKey))
          model.fetch()
        })
        model.once("notExist", function(err) {})
        model.load(function() {
          cb(model)
        })
        return model
      }

    })

  }

, setupAssociations: function() {
    this.setupManyAssociations()
    this.setupOneAssociations()
    this.setupBelongsToAssociations()
  }

, stopListening: function() {
    this.constructor.stopListening(this.get("_id"), this)
  }

 /*
  * listen for changes to documents with this id
  * since it's coming from the server we'll assume
  * it validates
  */
, handleChange: function(changes) {
    this.set(changes, {validate: false, initialize:true})
  }

 /*
  * listens for this document having been deleted, if it has
  * emit the delete event and set the deleted attribute to false
  */
, handleRemove: function() {
    this.deleted = true
    this.emit("delete", this)
  }

, sendUpdate: function(query, document, callback) {
    this.constructor.sendUpdateMessage(query, document, callback)
  }

, sendCreate: function(document, callback) {
    this.constructor.sendCreateMessage(document, callback)
  }

, performSave: function(cb) {
    var that = this
      , doc
      , time = (new Date()).getTime()

    this.set("updatedAt", time)

    this.saving = true
    this.emit("saving", that)

    //if the document has not been already persisted to the database before
    //then its a create event
    //
    if(!this.persisted) {
      this.set("createdAt", time)
      this.unsavedChanges = []
      this.sendCreate(this.document, function() {
        that.saving = false
        that.saved = true
        that.persisted = true
        if(!that.loaded) {
          that.emit("load", that)
        }
        that.loaded = true
        that.emit("saved", that)
        cb(that)
      })
    } else {
      var doc = {}
        , changed = _.clone(this.unsavedChanges)

      _(changed).each(function(key) {
        if(key === "_id") {
          return
        }

        that.emit("saving:" + key, that)
        doc[key] = that.document[key]
      })

      this.unsavedChanges = []
      this.sendUpdate({ _id: that.get("_id") }, doc, function(doc) {
        that.lastPersisted = _.clone(that.document)
        that.saved = true
        that.saving = false
        cb(that)
        _(changed).each(function(key) {
          if(key === "_id") {
            return
          }
          that.emit("saved:" + key, that)
        })
        that.emit("saved", that)
      })
    }
  }

 /**
  * Save will create the document on the server if it has not yet been
  * persisted to the database, otherwise it will update the version in the
  * database, calls the callback with itself, returns itself for chaining
  */

, save: function(cb) {
    cb = cb || function() {}
    var that = this
      , doc
      , callNext
      , beforeSaves = []
      , beforeSave

    if(!this.document._id) {
      throw new Error("document doesn't have an _id, maybe it hasn't loaded yet?")
    }

    if(this.constructor.isServer) {
      //it's a create save
      if(!this.persisted) {
        beforeSaves.push.apply(beforeSaves, that.constructor.serverBeforeCreateFunctions || [])
      }
      beforeSaves.push.apply(beforeSaves, that.constructor.serverBeforeSaveFunctions || [])
    } else {
      if(!this.persisted) {
        beforeSaves.push.apply(beforeSaves, that.constructor.beforeCreateFunctions || [])
      }
      beforeSaves.push.apply(beforeSaves, that.constructor.beforeSaveFunctions || [])
    }

    beforeSaves.unshift(function(inst, cb) {
      that.validate(function(inst, errors) {
        //dont pass the errors to the callback, because
        //validate emits it's own invalid event
        if(!errors) {
          cb()
        }
      })
    })

    // Run this after all the beforeSave functions have been called in order
    // to actually save the document, unless any of them have errors
    beforeSaves.push(function() {
      that.performSave(cb)
    })

    _.asyncEach(beforeSaves, function(beforeSave, next) {
      _(beforeSave).bind(that)(that, function(err) {
        if(!err) {
          next()
        } else {
          process.nextTick(function() {
            that.emit("error", err)
          })
        }
      })
    })
    return this
  }

 /**
  * Gets the value of field, takes in an optional function as second
  * parameter, which will get called once the field is available, and every
  * time the field is changed. Great for binding
  *
  * If the callback has arity one, it passes the value, otherwise it passes
  * (key, value)
  **/

, get: function(field) {
    return this.document[field]
  }

, assoc: function(assoc, callback) {
    var callback = callback || function() {}
      , model
    if(this.oneAssociations[assoc]) {
      return this.oneAssociations[assoc](callback)
    } else if(this.belongAssociations[assoc]) {
      return this.belongAssociations[assoc](callback)
    } else if (this.manyAssociations[assoc]) {
      return this.manyAssociations[assoc](callback)
    } else {
      throw new Error("No such association " + assoc)
    }
  }

 /**
  * takes in a hash of keys and values to set, or a string as the first arg
  * and a value(anything serializable) as the second.
  * fires a change event, which happens after all of the changes have been made
  *
  * If you call set from inside of a change event, it won't call another change
  * event, phew!
  **/

, set: function(field, value, opts) {
    opts = opts || {}

    if(typeof field === "undefined") {
      throw new Error("Must at least provide a field to set")
    }

    if(typeof field === "object" && typeof value === "object") {
      opts = value
    }

    if(field === "_id" && typeof this.document._id !== "undefined" && this.document._id !== value) {
      throw new Error("Can't change _id after its been set")
    }

    var that = this
      , alreadyChanging = this.alreadyChanging
      , oldValue

    this.alreadyChanging = true
    // we're initiating the changes, so we'll store the old values
    if(alreadyChanging == false) {
      this.previousDocument = _.clone(this.document)
    }

    if(typeof field == "object") {
      _.each(field, function(v, k) {
        that.set(k, v, opts)
      })
    } else if(that.manyAssociations[field]) {
      _.each(value, function(doc) {
        that.manyAssociations[field]().add(doc)
      })
    } else {
      oldValue = this.document[field]
      if(this.document[field] != value) {
        this.document[field] = value
        this.emit("change:" + field, value, oldValue, this)
      }
      if(!opts.initialize) {
        this.unsavedChanges = _.union(this.unsavedChanges, [field])
      }
    }

    // if THIS instance of set started the changes, it should emit the change
    // event and then end the changingness
    if(alreadyChanging == false) {
      this.triggerChange(opts)
    }
    return this
  }

, triggerChange: function(opts) {
    var that = this
      , fields = _.union(_.keys(this.document), _.keys(this.previousDocument))
      , changedFields = _.filter(fields, function(key) {
          return that.document[key] != that.previousDocument[key]
        })

    // if something actually changed
    if(changedFields.length > 0) {
      this.saved = false
      this.emit("change", this, changedFields)
      _(changedFields).each(function(field) {
        if(opts.validate !== false) {
          that.validateField(field)
        }
      })
    }
    this.previousDocument = _.clone(this.document)
    this.alreadyChanging = false
  }

, remove: function(callback) {
    callback = callback || function() {}
    var that = this
    this.constructor.sendDeleteMessage({ _id: this.get("_id") }, function(document) {
      callback(that)
    })
  }

, validateField: function(field, callback, opts) {
    opts = opts || {}
    callback = callback || function() {}

    var that = this
    var validations = (this.constructor.validations || {})[field]
    var valid = []
    _.asyncEach(validations, function(value, rule, next) {
      if(rule === "min" && that.get(field) && that.get(field).length < value) {
        valid.push("short")
        next()
      } else if(rule === "isInt" && that.get(field) && (parseFloat(that.get(field)) != parseInt(that.get(field)) || isNaN(that.get(field)))) {
        valid.push("isInt")
        next()
      } else if(rule === "max" && that.get(field) && that.get(field).length >= value) {
        valid.push("long")
        next()
      } else if(rule === "required" && !that.get(field)) {
        valid.push("required")
        next()
      } else if(rule === "unique") {
        that.isUnique(field, that.get(field), function(unique) {
          if(!unique) {
            valid.push("unique")
          }
          next()
        })
      } else {
        next()
      }
    }, function() {
      if(valid.length > 0) {
        if(!opts.silent) {
          that.emit("invalid:" + field, that, valid)
        }
        callback(that, valid)
      } else {
        // emit an event when a field is valid
        // useful for removing error messages
        if(!opts.silent) {
          that.emit("valid:" + field, that)
        }
        callback(that)
      }
    })
  }

, validate: function(cb, opts) {
    cb = cb || function() {}

    opts = opts || {}
    var that = this
    _.asyncMap(this.constructor.validations, function(validations, field, next) {
      that.validateField(field, function(instance, errors) {
        if(errors) {
          next(field, errors)
        } else {
          next()
        }
      }, opts)
    }, function(valid) {
      if(_.keys(valid).length != 0) {
        cb(that, valid)
        if(!opts.silent) {
          process.nextTick(function() {
            that.emit("invalid", that, valid)
          })
        }
      } else {
        cb(that)
      }
    })
  }

, isUnique: function(property, value, done) {
    var obj = {_id: {$ne : this.get("_id")}}
    value = value || ""
    obj[property] = value
    this.constructor.find(obj, function(things) {
      done(things.length === 0)
    })
  }
  /**
   * Called as soon as the document is loaded, if the document is already
   * loaded, call it right away
   */
, load: function(callback) {
    if(this.loaded) {
      process.nextTick(callback)
    } else {
      this.once("load", callback)
    }
  }

, keys: function() {
    var keys = _.clone(this.constructor.keys)
    keys.push("_id")
    keys.push("createdAt")
    keys.push("updatedAt")
    return keys
  }

, oneAssocs: function() {
    var assocs = _.union(
      _.keys(this.constructor.hasOne || {})
    , _.keys(this.constructor.belongingTo || {})
    , _.keys(this.constructor.polymorphicBelongingTo || {})
    )
    return assocs
  }
, manyAssocs: function() {
    return _.keys(this.constructor.hasMany || {})
  }
, assocs: function() {
   return this.oneAssocs().concat(this.manyAssocs)
  }
}
module.exports = InstanceMethods
<commit_msg>fixed an issue<commit_after>var generateObjectId   = require("./object_id")
  , EmbeddedCollection = require("./embedded_collection")
  , _                  = require("underscore")
  , idCounter = 0

require("./utils")

var InstanceMethods = {

  /**
   * The constructor for a new instance of LiveDocument
   *
   * The only valid opts param at the moment is validate false, if you don't
   * want the document to be validated it would be nice if we could pass in
   * saved, persisted and loaded as well
   *
   * This will create a new user which has not been persisted to the
   * database, saved, or loaded, and it is automatically assigned an id
   *
   * It is also used internally to create new documents that are received
   * from the server, except the loaded, saved, and persisted flags are
   * manually set, and it's not validated
   *
   * Examples:
   *     user = new User({ name: "Zach" })
   *
   **/

  constructor: function(document, opts) {
    var that = this
    var opts = opts || {}

    this.document = document || {}
    this.id = idCounter++

    this.deleted = false
    this.saved = false
    this.saving = false
    this.persisted = false
    this.loaded = false
    this.alreadyChanging = false

    this.unsavedChanges = []

    this.modelName = this.constructor.modelName

    if(!this.document._id && !opts.noId) {
      this.document._id = generateObjectId()
    }

    this.collectionName = this.constructor.collectionName()

    this.setupAssociations()

    if(this.get("_id")) {
      this.constructor.listenForChanges(this.get("_id"), this)
    } else {
      this.once("change:_id", function() {
        that.constructor.listenForChanges(this.get("_id"), that)
      })
    }
  }

, fetch: function() {
    var that = this
    this.constructor.sendReadOneMessage(this.document, function(document) {
      if(document) {
        that.set(document, { validate: false, initialize: true })
        that.loaded = true
        that.saved = true
        that.persisted = true
        that.emit("load", that)
      } else {
        that.emit("notExist")
      }
    })
  }

, setupManyAssociations: function() {
    var that = this
    this.manyAssociations = {}

    _(this.constructor.hasMany).each(function(obj, collectionName) {
      var collection
        , Model = obj.model
        , opts = obj.opts
      that.manyAssociations[collectionName] = function(callback) {
        var docs
          , query
        if(collection) {
          return collection
        }
        if(Model.embedded) {
          docs = that.document[collectionName] || []
          delete that.document[collectionName]
          collection = new EmbeddedCollection(docs, that, Model)
        } else {
          query = {}
          query[opts.foreignKey || _.singularize(that.collectionName) + "Id"] = that.get("_id")
          collection = Model.find(query)
        }
        callback = callback || function() {}
        collection.load(function() {
          callback(collection)
        })
        return collection
      }
    })
  }

, setupOneAssociations: function() {
    var that = this
    this.oneAssociations = {}
    _(this.constructor.hasOne).each(function(obj, collectionName) {
      var Model = obj.model
        , opts = obj.opts || {}
        , foreignKey = opts.foreignKey || _.singularize(that.collectionName) + "Id"

      that.oneAssociations[collectionName] = function(cb) {
        var model = new Model({}, {noId: true})
        that.load(function() {
          model.set(foreignKey, that.get("_id"))
          model.fetch()
        })
        //we couldn't find the model
        model.once("notExist", function(err) {})
        model.load(function() {
          cb(model)
        })
        return model
      }
    })
  }

, setupBelongsToAssociations: function() {
    var that = this
    this.belongAssociations = {}
    _(this.constructor.belongingTo).each(function(opts, collectionName) {
      that.belongAssociations[collectionName] = function(cb) {
        var ModelMap = opts.models
          , Model
          , foreignType
          , foreignKey = collectionName + "Id"

        if(opts.polymorphic) {
          foreignType = that.get(collectionName + "Type")
          Model = ModelMap[foreignType]
        } else {
          Model = opts.model
        }
        var model = new Model({}, {noId: true})
        that.load(function() {
          model.set("_id", that.get(foreignKey))
          model.fetch()
        })
        model.once("notExist", function(err) {})
        model.load(function() {
          cb(model)
        })
        return model
      }

    })

  }

, setupAssociations: function() {
    this.setupManyAssociations()
    this.setupOneAssociations()
    this.setupBelongsToAssociations()
  }

, stopListening: function() {
    this.constructor.stopListening(this.get("_id"), this)
  }

 /*
  * listen for changes to documents with this id
  * since it's coming from the server we'll assume
  * it validates
  */
, handleChange: function(changes) {
    this.set(changes, {validate: false, initialize:true})
  }

 /*
  * listens for this document having been deleted, if it has
  * emit the delete event and set the deleted attribute to false
  */
, handleRemove: function() {
    this.deleted = true
    this.emit("delete", this)
  }

, sendUpdate: function(query, document, callback) {
    this.constructor.sendUpdateMessage(query, document, callback)
  }

, sendCreate: function(document, callback) {
    this.constructor.sendCreateMessage(document, callback)
  }

, performSave: function(cb) {
    var that = this
      , doc
      , time = (new Date()).getTime()

    this.set("updatedAt", time)

    this.saving = true
    this.emit("saving", that)

    //if the document has not been already persisted to the database before
    //then its a create event
    //
    if(!this.persisted) {
      this.set("createdAt", time)
      this.unsavedChanges = []
      this.sendCreate(this.document, function() {
        that.saving = false
        that.saved = true
        that.persisted = true
        if(!that.loaded) {
          that.emit("load", that)
        }
        that.loaded = true
        that.emit("saved", that)
        cb(that)
      })
    } else {
      var doc = {}
        , changed = _.clone(this.unsavedChanges)

      _(changed).each(function(key) {
        if(key === "_id") {
          return
        }

        that.emit("saving:" + key, that)
        doc[key] = that.document[key]
      })

      this.unsavedChanges = []
      this.sendUpdate({ _id: that.get("_id") }, doc, function(doc) {
        that.lastPersisted = _.clone(that.document)
        that.saved = true
        that.saving = false
        cb(that)
        _(changed).each(function(key) {
          if(key === "_id") {
            return
          }
          that.emit("saved:" + key, that)
        })
        that.emit("saved", that)
      })
    }
  }

 /**
  * Save will create the document on the server if it has not yet been
  * persisted to the database, otherwise it will update the version in the
  * database, calls the callback with itself, returns itself for chaining
  */

, save: function(cb) {
    cb = cb || function() {}
    var that = this
      , doc
      , callNext
      , beforeSaves = []
      , beforeSave

    if(!this.document._id) {
      throw new Error("document doesn't have an _id, maybe it hasn't loaded yet?")
    }

    if(this.constructor.isServer) {
      //it's a create save
      if(!this.persisted) {
        beforeSaves.push.apply(beforeSaves, that.constructor.serverBeforeCreateFunctions || [])
      }
      beforeSaves.push.apply(beforeSaves, that.constructor.serverBeforeSaveFunctions || [])
    } else {
      if(!this.persisted) {
        beforeSaves.push.apply(beforeSaves, that.constructor.beforeCreateFunctions || [])
      }
      beforeSaves.push.apply(beforeSaves, that.constructor.beforeSaveFunctions || [])
    }

    beforeSaves.unshift(function(inst, cb) {
      that.validate(function(inst, errors) {
        //dont pass the errors to the callback, because
        //validate emits it's own invalid event
        if(!errors) {
          cb()
        }
      })
    })

    // Run this after all the beforeSave functions have been called in order
    // to actually save the document, unless any of them have errors
    beforeSaves.push(function() {
      that.performSave(cb)
    })

    _.asyncEach(beforeSaves, function(beforeSave, next) {
      _(beforeSave).bind(that)(that, function(err) {
        if(!err) {
          next()
        } else {
          process.nextTick(function() {
            that.emit("error", err)
          })
        }
      })
    })
    return this
  }

 /**
  * Gets the value of field, takes in an optional function as second
  * parameter, which will get called once the field is available, and every
  * time the field is changed. Great for binding
  *
  * If the callback has arity one, it passes the value, otherwise it passes
  * (key, value)
  **/

, get: function(field) {
    return this.document[field]
  }

, assoc: function(assoc, callback) {
    var callback = callback || function() {}
      , model
    if(this.oneAssociations[assoc]) {
      return this.oneAssociations[assoc](callback)
    } else if(this.belongAssociations[assoc]) {
      return this.belongAssociations[assoc](callback)
    } else if (this.manyAssociations[assoc]) {
      return this.manyAssociations[assoc](callback)
    } else {
      throw new Error("No such association " + assoc)
    }
  }

 /**
  * takes in a hash of keys and values to set, or a string as the first arg
  * and a value(anything serializable) as the second.
  * fires a change event, which happens after all of the changes have been made
  *
  * If you call set from inside of a change event, it won't call another change
  * event, phew!
  **/

, set: function(field, value, opts) {
    opts = opts || {}

    if(typeof field === "undefined") {
      throw new Error("Must at least provide a field to set")
    }

    if(typeof field === "object" && typeof value === "object") {
      opts = value
    }

    if(field === "_id" && typeof this.document._id !== "undefined" && this.document._id !== value) {
      throw new Error("Can't change _id after its been set")
    }

    var that = this
      , alreadyChanging = this.alreadyChanging
      , oldValue

    this.alreadyChanging = true
    // we're initiating the changes, so we'll store the old values
    if(alreadyChanging == false) {
      this.previousDocument = _.clone(this.document)
    }

    if(typeof field == "object") {
      _.each(field, function(v, k) {
        that.set(k, v, opts)
      })
    } else if(that.manyAssociations[field]) {
      _.each(value, function(doc) {
        that.manyAssociations[field]().add(doc)
      })
    } else {
      oldValue = this.document[field]
      if(this.document[field] != value) {
        this.document[field] = value
        this.emit("change:" + field, value, oldValue, this)
      }
      if(!opts.initialize) {
        this.unsavedChanges = _.union(this.unsavedChanges, [field])
      }
    }

    // if THIS instance of set started the changes, it should emit the change
    // event and then end the changingness
    if(alreadyChanging == false) {
      this.triggerChange(opts)
    }
    return this
  }

, triggerChange: function(opts) {
    var that = this
      , fields = _.union(_.keys(this.document), _.keys(this.previousDocument))
      , changedFields = _.filter(fields, function(key) {
          return that.document[key] != that.previousDocument[key]
        })

    // if something actually changed
    if(changedFields.length > 0) {
      this.saved = false
      this.emit("change", this, changedFields)
      _(changedFields).each(function(field) {
        if(opts.validate !== false) {
          that.validateField(field)
        }
      })
    }
    this.previousDocument = _.clone(this.document)
    this.alreadyChanging = false
  }

, remove: function(callback) {
    callback = callback || function() {}
    var that = this
    this.constructor.sendDeleteMessage({ _id: this.get("_id") }, function(document) {
      callback(that)
    })
  }

, validateField: function(field, callback, opts) {
    opts = opts || {}
    callback = callback || function() {}

    var that = this
    var validations = (this.constructor.validations || {})[field]
    var valid = []
    _.asyncEach(validations, function(value, rule, next) {
      if(rule === "min" && that.get(field) && that.get(field).length < value) {
        valid.push("short")
        next()
      } else if(rule === "isInt" && that.get(field) && (parseFloat(that.get(field)) != parseInt(that.get(field)) || isNaN(that.get(field)))) {
        valid.push("isInt")
        next()
      } else if(rule === "max" && that.get(field) && that.get(field).length >= value) {
        valid.push("long")
        next()
      } else if(rule === "required" && !that.get(field)) {
        valid.push("required")
        next()
      } else if(rule === "unique") {
        that.isUnique(field, that.get(field), function(unique) {
          if(!unique) {
            valid.push("unique")
          }
          next()
        })
      } else {
        next()
      }
    }, function() {
      if(valid.length > 0) {
        if(!opts.silent) {
          that.emit("invalid:" + field, that, valid)
        }
        callback(that, valid)
      } else {
        // emit an event when a field is valid
        // useful for removing error messages
        if(!opts.silent) {
          that.emit("valid:" + field, that)
        }
        callback(that)
      }
    })
  }

, validate: function(cb, opts) {
    cb = cb || function() {}

    opts = opts || {}
    var that = this
    _.asyncMap(this.constructor.validations, function(validations, field, next) {
      that.validateField(field, function(instance, errors) {
        if(errors) {
          next(field, errors)
        } else {
          next()
        }
      }, opts)
    }, function(valid) {
      if(_.keys(valid).length != 0) {
        cb(that, valid)
        if(!opts.silent) {
          process.nextTick(function() {
            that.emit("invalid", that, valid)
          })
        }
      } else {
        cb(that)
      }
    })
  }

, isUnique: function(property, value, done) {
    var obj = {_id: {$ne : this.get("_id")}}
    value = value || ""
    obj[property] = value
    this.constructor.find(obj, function(things) {
      done(things.length === 0)
    })
  }
  /**
   * Called as soon as the document is loaded, if the document is already
   * loaded, call it right away
   */
, load: function(callback) {
    if(this.loaded) {
      process.nextTick(callback)
    } else {
      this.once("load", callback)
    }
  }

, keys: function() {
    var keys = _.clone(this.constructor.keys)
    keys.push("_id")
    keys.push("createdAt")
    keys.push("updatedAt")
    return keys
  }

, oneAssocs: function() {
    var assocs = _.union(
      _.keys(this.constructor.hasOne || {})
    , _.keys(this.constructor.belongingTo || {})
    , _.keys(this.constructor.polymorphicBelongingTo || {})
    )
    return assocs
  }
, manyAssocs: function() {
    return _.keys(this.constructor.hasMany || {})
  }
, assocs: function() {
   return this.oneAssocs().concat(this.manyAssocs())
  }
}
module.exports = InstanceMethods
<|endoftext|>


<commit_before>'use strict';

var CtrlProto;
var forIn              = require('./utils/forIn');
var webRootHandlers    = require('./entryHandlers/web-root');
var normalizeEntryName = require('./helpers').normalizeEntryName;

var hasOwn = Object.prototype.hasOwnProperty;

var starterList    = ['_', '.'];
var starterListLen = starterList.length;

//  !isEmpty
var hasProps = function (obj) {
	var key;

    for (key in obj) { if ( hasOwn.call(obj, key) ) {
    	return true;
    }}

    return false;
};

function shouldBeIgnored (entry) {
	if ( matchStartWith(entry) ) return true;

	return false;
}

function matchStartWith (name) {
	var starter, starterLen, nameStart, i;

	for (i = 0; i < starterListLen; i+=1) {
		starter    = starterList[i];
		starterLen = starter.length;
		nameStart  = name.substr(0, starterLen);

		if (nameStart === starter) {
			return true;
		}
	}

	return false;
}

var has = {
	verbs: function hasVerbs (ctrl) {
		 /*
		 | because ctrl.verbs also contain 'noVerb'
		*/
		var verbs = ctrl.verbs;

		if (verbs.get || verbs.post || verbs.put || verbs.delete){
			return true;
		}

		return false;
	},

	methods: function hasMethods (ctrl) {
		var sharedMethods;

		var ownMethods = (Object.keys (ctrl.methods).length > 0);

		if (ctrl.global._shared_methods) {
			sharedMethods = (Object.keys (ctrl.global._shared_methods).length > 0);
		}

		return ownMethods || sharedMethods;
	},

	subCtrls: function hasSubCtrls (ctrl) {
		var sharedCtrls;

		var ownCtrls = (Object.keys (ctrl.subCtrls).length > 0);

		if (ctrl.global._shared_ctrls) {
			sharedCtrls = (Object.keys (ctrl.global._shared_ctrls).length > 0);
		}

		return ownCtrls || sharedCtrls;
	}
};

/*
  ┌─────────────────────────────────────────────────────────────────────
  │ 	run = {
  │		.verb()    - on request (in chain)
  │		.method()  - on request (in chain)
  │		.subCtrl() - on request (in chain)
  │	}
  │	all 3 are being pushed to chains and called with: .call(ctrl, io)
 */
var run = {
	verb: function (io) {
		var verbs = this.verbs;
		var verb  = verbs[io.req.method.toLowerCase()];

		if (verb) {
			verb.call(this, io);
		}
		else if (verbs.noVerb) {
			verbs.noVerb.call(this, io);
		}
		else {
			this.next(io);
		}
	},

	method: function (io) {
		var method;
		var next = io.params[0];

		method = this.methods[next.toLowerCase()];

		if (method) {
			io.params.shift();

			method.call(this, io);
		}

	},

	subCtrl: function (io) {
		var subCtrl;
		var next = io.params[0];

		subCtrl = this.subCtrls[next.toLowerCase()];

		if (subCtrl) {
			subCtrl.parent = this;
			subCtrl.checkIn(io);
		}
	}
};

/*
 ┌────────────────────────────────────────────────
 │ ctrl.id is its parent.id + /name.
 │ id is unique, name isn't.
 │ examples:
 │     id:   '/foo' │ '/foo/bar' │ '/foo/bar/foo'
 │     name: 'foo'  │ 'bar'      │ 'foo'
*/
function setID (ctrl) {
	var buildID = '';

	// is RC? id = '/'
	if (ctrl.isRC) return '/';

	// RC's direct child - avoid double slashes
	if (ctrl.parent && !ctrl.parent.isRC) buildID += ctrl.parent.id;

	// all
	buildID += '/' + ctrl.name;

	return buildID;
}

/*
 ┌─────────────────────────────────────────
 │ this method gets a folder-map obj and sets the ctrl with its different props and
 │ functionalities.
 │ forEach entry in the folder:
 │   ignore _
 │   handle if has an entryHandler
 │     or
 │   set as a ctrl's method/subCtrl
*/
function parseFolderMap (ctrl, folderMap) {
	forIn(folderMap.entries, function (key, entryMap) {
		var isFile, name;

		// normalizeEntryName = lowerCase, remove extension
		name = normalizeEntryName(key, isFile);

		/* Deal Breaker */ if (shouldBeIgnored(name)) {return;} // ignore preceding '_'

		isFile = entryMap.type;

		// if such entryHandler exists
		if (hasOwn.call(webRootHandlers, name)) {
			webRootHandlers[name].call(ctrl, entryMap);
		}
		else {
			if (isFile) {
				ctrl.methods[name] = require(entryMap.path);
			}
			else {
				ctrl.subCtrls[name] = entryMap;
			}
		}
	});
}

/*
  ┌──────────────────────────────────────────────────────────────────────────────────────────
  │ delegated means when exists in a ctrl, all of its sub-ctrl will get it too (inheritance)
 */
function delegateNoVerb (ctrl) {
	var verbs = ctrl.verbs;

	// if doesn't own: take from parent
	if (!verbs.noVerb && ctrl.parent) {
		verbs.noVerb = ctrl.parent.verbs.noVerb;
	}
}

/*
  ┌────────────────────────────────────────────────────────────────────────────────────────────
  │ examples:
  │     0. parentChain = [first, runSub, last]
  │     1. targetChain = [first, runVerb, last]
  │     2. methodChain = [first, runMethod, last]
  │
  │ "setupChains" fn creates an array of 3 chains (3 arrays) of methods to run in all cases.
  │ this.chains = [[...],[...],[...]];
  │
 */
function setupChains (ctrl) {
	var targetChain = [];
	var methodChain = [];
	var parentChain = [];

	// first
	if (ctrl.first) {
		targetChain.push(ctrl.first);
		methodChain.push(ctrl.first);
		parentChain.push(ctrl.first);
	}

	// targetChain
	if (ctrl.index) {
		targetChain.push(ctrl.index);
	}

	if (has.verbs(ctrl)) {
		targetChain.push(run.verb);
	}

	if (ctrl.afterVerb) {
		targetChain.push(ctrl.afterVerb);
	}

	// methodChain
	if (has.methods(ctrl)) {
		if (ctrl.preMethod) {
			methodChain.push(ctrl.preMethod);
		}

		methodChain.push(run.method);

		if (ctrl.postMethod) {
			methodChain.push(ctrl.postMethod);
		}
	}

	// parentChain
	if (has.subCtrls(ctrl)) {
		if (ctrl.preSub) {
			parentChain.push(ctrl.preSub);
		}

		parentChain.push(run.subCtrl);

		if (ctrl.postSub) {
			parentChain.push(ctrl.postSub);
		}
	}

	// last
	if (ctrl.last) {
		targetChain.push(ctrl.last);
		methodChain.push(ctrl.last);
		parentChain.push(ctrl.last);
	}

	// 0: parentChain
	// 1: targetChain
	// 2: methodChain
	ctrl.chains = [parentChain, targetChain, methodChain];
}

function initSubCtrls (ctrl) {
	var subCtrls = ctrl.subCtrls;

	forIn(subCtrls, function (name, subCtrlMap) {
		subCtrls[name] = new Ctrl(subCtrlMap, name, ctrl);
	});
}

/*
  ┌──────────────────────────────────────
  │ example:
  │ 	url:  /A/B/C
  │		on "RC" check-in:
  │ 		io.params = ['A','B','C']
  │
  │		on "A" ctrl check-in:
  │ 		io.params = ['B','C']
 */
function removeSelfName (ctrl, io) {
	var first = io.params[0];

	// if (first == ctrl.name)
	if (first && first.toLowerCase() === ctrl.name) {

		// remove first
		io.params.shift();
	}
}

// ==========================================
//  Ctrl Constructor & Constructor.prototype
// ==========================================
function Ctrl (folderMap, name, parent, global, isRC) {
	// meta
	this.folderMap = folderMap;
	this.isRC      = isRC   || false;
	this.parent    = parent || null;
	this.global    = global || parent.global;
	this.name      = (isRC)?  'RC' : name;
	this.id        = setID(this);

	this.verbs    = Object.create(null);
	this.methods  = Object.create(this.global._shared_methods || null);
	this.subCtrls = Object.create(this.global._shared_ctrls   || null);

	// register
	this.global.ctrls[this.id] = this;

	// init
	parseFolderMap(this, folderMap);
	delegateNoVerb(this);
	setupChains(this);
	initSubCtrls(this);
}

CtrlProto = Ctrl.prototype;

/*
  ┌──────────────────────────────────────────────────
  │ remove self name from io.params
  │ profile io
  │ run first in chain
 */
CtrlProto.checkIn = function (io) {
	removeSelfName(this, io);

	// create profile
	io._profiles[this.id] = {
		idx        : 0,
		chainIndex : this.getChainIndex(io)
	};

	this.next(io);
};

/*
  ┌────────────────────────────────────────────────────────────────────────────
  │ test on checkIn, if this ctrl is the target ctrl for the current request.
  │ checks if the next param is an existing sub
  │
  │ returns
  │ 	0: parent
  │ 	1: target
  │ 	2: method
 */
CtrlProto.getChainIndex = function (io) {
	var next = io.params[0];

	if (next) {
		next = next.toLowerCase();

		if (this.methods[next]) {
			return 2;
		}
		else if (this.subCtrls[next]) {
			return 0;
		}
		else {
			return 1;
		}
	}

	return 1;
};

/*
  ┌──────────────────────────────────────────────────
  │ called by io.next()
 */
CtrlProto.next = function (io, profile) {
	var i, chainIndex, chain;

	// set current handling ctrl
	io._ctrl = this;

	// get profile
	profile = profile || io._profiles[this.id];

	i = profile.idx++;

	// is target? 0: sub, 1: target, 2: method
	chainIndex = (profile.chainIndex);

	// get corresponding chain
	chain = this.chains[chainIndex];

	// if there's more in the chain to run - run it. else - checkOut
	if (chain[i]) {
		chain[i].call(this, io);
	}
	else {
		this.checkOut(io);
	}
};

/*
  ┌──────────────────────────────────────────────────
  │ call parent next or end response (RC)
 */
CtrlProto.checkOut = function (io) {
	if (this.isRC) { // end response
		io.res.end();
	}
	else {
		this.parent.next(io);
	}
};

// ------------------------------
module.exports.Ctrl  = Ctrl;
module.exports.proto = CtrlProto;<commit_msg>a small var decalaration change<commit_after>'use strict';

var CtrlProto;
var forIn              = require('./utils/forIn');
var webRootHandlers    = require('./entryHandlers/web-root');
var normalizeEntryName = require('./helpers').normalizeEntryName;

var hasOwn = Object.prototype.hasOwnProperty;

var starterList    = ['_', '.'];
var starterListLen = starterList.length;

//  !isEmpty
var hasProps = function (obj) {
	var key;

    for (key in obj) { if ( hasOwn.call(obj, key) ) {
    	return true;
    }}

    return false;
};

function shouldBeIgnored (entry) {
	if ( matchStartWith(entry) ) return true;

	return false;
}

function matchStartWith (name) {
	var starter, starterLen, nameStart, i;

	for (i = 0; i < starterListLen; i+=1) {
		starter    = starterList[i];
		starterLen = starter.length;
		nameStart  = name.substr(0, starterLen);

		if (nameStart === starter) {
			return true;
		}
	}

	return false;
}

var has = {
	verbs: function hasVerbs (ctrl) {
		 /*
		 | because ctrl.verbs also contain 'noVerb'
		*/
		var verbs = ctrl.verbs;

		if (verbs.get || verbs.post || verbs.put || verbs.delete){
			return true;
		}

		return false;
	},

	methods: function hasMethods (ctrl) {
		var sharedMethods;

		var ownMethods = (Object.keys (ctrl.methods).length > 0);

		if (ctrl.global._shared_methods) {
			sharedMethods = (Object.keys (ctrl.global._shared_methods).length > 0);
		}

		return ownMethods || sharedMethods;
	},

	subCtrls: function hasSubCtrls (ctrl) {
		var sharedCtrls;

		var ownCtrls = (Object.keys (ctrl.subCtrls).length > 0);

		if (ctrl.global._shared_ctrls) {
			sharedCtrls = (Object.keys (ctrl.global._shared_ctrls).length > 0);
		}

		return ownCtrls || sharedCtrls;
	}
};

/*
  ┌─────────────────────────────────────────────────────────────────────
  │ 	run = {
  │		.verb()    - on request (in chain)
  │		.method()  - on request (in chain)
  │		.subCtrl() - on request (in chain)
  │	}
  │	all 3 are being pushed to chains and called with: .call(ctrl, io)
 */
var run = {
	verb: function (io) {
		var verbs = this.verbs;
		var verb  = verbs[io.req.method.toLowerCase()];

		if (verb) {
			verb.call(this, io);
		}
		else if (verbs.noVerb) {
			verbs.noVerb.call(this, io);
		}
		else {
			this.next(io);
		}
	},

	method: function (io) {
		var next   = io.params[0];
		var method = this.methods[next.toLowerCase()];

		if (method) {
			io.params.shift();

			method.call(this, io);
		}

	},

	subCtrl: function (io) {
		var subCtrl;
		var next = io.params[0];

		subCtrl = this.subCtrls[next.toLowerCase()];

		if (subCtrl) {
			subCtrl.parent = this;
			subCtrl.checkIn(io);
		}
	}
};

/*
 ┌────────────────────────────────────────────────
 │ ctrl.id is its parent.id + /name.
 │ id is unique, name isn't.
 │ examples:
 │     id:   '/foo' │ '/foo/bar' │ '/foo/bar/foo'
 │     name: 'foo'  │ 'bar'      │ 'foo'
*/
function setID (ctrl) {
	var buildID = '';

	// is RC? id = '/'
	if (ctrl.isRC) return '/';

	// RC's direct child - avoid double slashes
	if (ctrl.parent && !ctrl.parent.isRC) buildID += ctrl.parent.id;

	// all
	buildID += '/' + ctrl.name;

	return buildID;
}

/*
 ┌─────────────────────────────────────────
 │ this method gets a folder-map obj and sets the ctrl with its different props and
 │ functionalities.
 │ forEach entry in the folder:
 │   ignore _
 │   handle if has an entryHandler
 │     or
 │   set as a ctrl's method/subCtrl
*/
function parseFolderMap (ctrl, folderMap) {
	forIn(folderMap.entries, function (key, entryMap) {
		var isFile, name;

		// normalizeEntryName = lowerCase, remove extension
		name = normalizeEntryName(key, isFile);

		/* Deal Breaker */ if (shouldBeIgnored(name)) {return;} // ignore preceding '_'

		isFile = entryMap.type;

		// if such entryHandler exists
		if (hasOwn.call(webRootHandlers, name)) {
			webRootHandlers[name].call(ctrl, entryMap);
		}
		else {
			if (isFile) {
				ctrl.methods[name] = require(entryMap.path);
			}
			else {
				ctrl.subCtrls[name] = entryMap;
			}
		}
	});
}

/*
  ┌──────────────────────────────────────────────────────────────────────────────────────────
  │ delegated means when exists in a ctrl, all of its sub-ctrl will get it too (inheritance)
 */
function delegateNoVerb (ctrl) {
	var verbs = ctrl.verbs;

	// if doesn't own: take from parent
	if (!verbs.noVerb && ctrl.parent) {
		verbs.noVerb = ctrl.parent.verbs.noVerb;
	}
}

/*
  ┌────────────────────────────────────────────────────────────────────────────────────────────
  │ examples:
  │     0. parentChain = [first, runSub, last]
  │     1. targetChain = [first, runVerb, last]
  │     2. methodChain = [first, runMethod, last]
  │
  │ "setupChains" fn creates an array of 3 chains (3 arrays) of methods to run in all cases.
  │ this.chains = [[...],[...],[...]];
  │
 */
function setupChains (ctrl) {
	var targetChain = [];
	var methodChain = [];
	var parentChain = [];

	// first
	if (ctrl.first) {
		targetChain.push(ctrl.first);
		methodChain.push(ctrl.first);
		parentChain.push(ctrl.first);
	}

	// targetChain
	if (ctrl.index) {
		targetChain.push(ctrl.index);
	}

	if (has.verbs(ctrl)) {
		targetChain.push(run.verb);
	}

	if (ctrl.afterVerb) {
		targetChain.push(ctrl.afterVerb);
	}

	// methodChain
	if (has.methods(ctrl)) {
		if (ctrl.preMethod) {
			methodChain.push(ctrl.preMethod);
		}

		methodChain.push(run.method);

		if (ctrl.postMethod) {
			methodChain.push(ctrl.postMethod);
		}
	}

	// parentChain
	if (has.subCtrls(ctrl)) {
		if (ctrl.preSub) {
			parentChain.push(ctrl.preSub);
		}

		parentChain.push(run.subCtrl);

		if (ctrl.postSub) {
			parentChain.push(ctrl.postSub);
		}
	}

	// last
	if (ctrl.last) {
		targetChain.push(ctrl.last);
		methodChain.push(ctrl.last);
		parentChain.push(ctrl.last);
	}

	// 0: parentChain
	// 1: targetChain
	// 2: methodChain
	ctrl.chains = [parentChain, targetChain, methodChain];
}

function initSubCtrls (ctrl) {
	var subCtrls = ctrl.subCtrls;

	forIn(subCtrls, function (name, subCtrlMap) {
		subCtrls[name] = new Ctrl(subCtrlMap, name, ctrl);
	});
}

/*
  ┌──────────────────────────────────────
  │ example:
  │ 	url:  /A/B/C
  │		on "RC" check-in:
  │ 		io.params = ['A','B','C']
  │
  │		on "A" ctrl check-in:
  │ 		io.params = ['B','C']
 */
function removeSelfName (ctrl, io) {
	var first = io.params[0];

	// if (first == ctrl.name)
	if (first && first.toLowerCase() === ctrl.name) {

		// remove first
		io.params.shift();
	}
}

// ==========================================
//  Ctrl Constructor & Constructor.prototype
// ==========================================
function Ctrl (folderMap, name, parent, global, isRC) {
	// meta
	this.folderMap = folderMap;
	this.isRC      = isRC   || false;
	this.parent    = parent || null;
	this.global    = global || parent.global;
	this.name      = (isRC)?  'RC' : name;
	this.id        = setID(this);

	this.verbs    = Object.create(null);
	this.methods  = Object.create(this.global._shared_methods || null);
	this.subCtrls = Object.create(this.global._shared_ctrls   || null);

	// register
	this.global.ctrls[this.id] = this;

	// init
	parseFolderMap(this, folderMap);
	delegateNoVerb(this);
	setupChains(this);
	initSubCtrls(this);
}

CtrlProto = Ctrl.prototype;

/*
  ┌──────────────────────────────────────────────────
  │ remove self name from io.params
  │ profile io
  │ run first in chain
 */
CtrlProto.checkIn = function (io) {
	removeSelfName(this, io);

	// create profile
	io._profiles[this.id] = {
		idx        : 0,
		chainIndex : this.getChainIndex(io)
	};

	this.next(io);
};

/*
  ┌────────────────────────────────────────────────────────────────────────────
  │ test on checkIn, if this ctrl is the target ctrl for the current request.
  │ checks if the next param is an existing sub
  │
  │ returns
  │ 	0: parent
  │ 	1: target
  │ 	2: method
 */
CtrlProto.getChainIndex = function (io) {
	var next = io.params[0];

	if (next) {
		next = next.toLowerCase();

		if (this.methods[next]) {
			return 2;
		}
		else if (this.subCtrls[next]) {
			return 0;
		}
		else {
			return 1;
		}
	}

	return 1;
};

/*
  ┌──────────────────────────────────────────────────
  │ called by io.next()
 */
CtrlProto.next = function (io, profile) {
	var i, chainIndex, chain;

	// set current handling ctrl
	io._ctrl = this;

	// get profile
	profile = profile || io._profiles[this.id];

	i = profile.idx++;

	// is target? 0: sub, 1: target, 2: method
	chainIndex = (profile.chainIndex);

	// get corresponding chain
	chain = this.chains[chainIndex];

	// if there's more in the chain to run - run it. else - checkOut
	if (chain[i]) {
		chain[i].call(this, io);
	}
	else {
		this.checkOut(io);
	}
};

/*
  ┌──────────────────────────────────────────────────
  │ call parent next or end response (RC)
 */
CtrlProto.checkOut = function (io) {
	if (this.isRC) { // end response
		io.res.end();
	}
	else {
		this.parent.next(io);
	}
};

// ------------------------------
module.exports.Ctrl  = Ctrl;
module.exports.proto = CtrlProto;<|endoftext|>