<commit_before>/*
 * gaze
 * https://github.com/shama/gaze
 *
 * Copyright (c) 2014 Kyle Robinson Young
 * Licensed under the MIT license.
 */

'use strict';

// libs
var util = require('util');
var EE = require('events').EventEmitter;
var fs = require('fs');
var path = require('path');
var globule = require('globule');
var nextback = require('nextback');
var helper = require('./helper');
var platform = require('./platform');

// keep track of instances to call multiple times for backwards compatibility
var instances = [];

// `Gaze` EventEmitter object to return in the callback
function Gaze(patterns, opts, done) {
  var self = this;
  EE.call(self);

  // If second arg is the callback
  if (typeof opts === 'function') {
    done = opts;
    opts = {};
  }

  // Default options
  opts = opts || {};
  opts.mark = true;
  opts.interval = opts.interval || 500;
  opts.debounceDelay = opts.debounceDelay || 500;
  opts.cwd = opts.cwd || process.cwd();
  this.options = opts;

  // File watching mode to use when adding files to the platform
  this._mode = opts.mode || 'auto';

  // Default done callback
  done = done || function() {};

  // Remember our watched dir:files
  this._watched = Object.create(null);

  // Store watchers
  this._watchers = Object.create(null);

  // Store watchFile listeners
  this._pollers = Object.create(null);

  // Store patterns
  this._patterns = [];

  // Cached events for debouncing
  this._cached = Object.create(null);

  // Set maxListeners
  if (this.options.maxListeners) {
    this.setMaxListeners(this.options.maxListeners);
    Gaze.super_.prototype.setMaxListeners(this.options.maxListeners);
    delete this.options.maxListeners;
  }

  // Initialize the watch on files
  if (patterns) {
    this.add(patterns, done);
  }

  // keep the process alive
  this._keepalive = setInterval(platform.tick.bind(platform), opts.interval);

  // Keep track of all instances created
  this._instanceNum = instances.length;
  instances.push(this);

  // Keep track of safewriting and debounce timeouts
  this._safewriting = null;
  this._safewriteTimeout = null;
  this._timeoutId = null;

  return this;
}
util.inherits(Gaze, EE);

// Main entry point. Start watching and call done when setup
module.exports = function gaze(patterns, opts, done) {
  return new Gaze(patterns, opts, done);
};
module.exports.Gaze = Gaze;

// Override the emit function to emit `all` events
// and debounce on duplicate events per file
Gaze.prototype.emit = function() {
  var self = this;
  var args = arguments;
  //console.log('GAZE EMIT', arguments)

  var e = args[0];
  var filepath = args[1];

  // If not added/deleted/changed/renamed then just emit the event
  if (e.slice(-2) !== 'ed') {
    Gaze.super_.prototype.emit.apply(self, args);
    return this;
  }

  // Detect rename event, if added and previous deleted is in the cache
  if (e === 'added') {
    Object.keys(this._cached).forEach(function(oldFile) {
      if (self._cached[oldFile].indexOf('deleted') !== -1) {
        args[0] = e = 'renamed';
        [].push.call(args, oldFile);
        delete self._cached[oldFile];
        return false;
      }
    });
  }

  // Detect safewrite events, if file is deleted and then added/renamed, assume a safewrite happened
  if (e === 'deleted' && this._safewriting == null) {
    this._safewriting = filepath;
    this._safewriteTimeout = setTimeout(function() {
      // Just a normal delete, carry on
      Gaze.super_.prototype.emit.apply(self, args);
      Gaze.super_.prototype.emit.apply(self, ['all', e].concat([].slice.call(args, 1)));
      self._safewriting = null;
    }, this.options.debounceDelay);
    return this;
  } else if ((e === 'added' || e === 'renamed') && this._safewriting === filepath) {
    clearTimeout(this._safewriteTimeout);
    this._safewriteTimeout = setTimeout(function() {
      self._safewriting = null;
    }, this.options.debounceDelay);
    args[0] = e = 'changed';
  } else if (e === 'deleted' && this._safewriting === filepath) {
    return this;
  }

  // If cached doesnt exist, create a delay before running the next
  // then emit the event
  var cache = this._cached[filepath] || [];
  if (cache.indexOf(e) === -1) {
    helper.objectPush(self._cached, filepath, e);
    clearTimeout(this._timeoutId);
    this._timeoutId = setTimeout(function() {
      delete self._cached[filepath];
    }, this.options.debounceDelay);
    // Emit the event and `all` event
    Gaze.super_.prototype.emit.apply(self, args);
    Gaze.super_.prototype.emit.apply(self, ['all', e].concat([].slice.call(args, 1)));
  }

  // Detect if new folder added to trigger for matching files within folder
  if (e === 'added') {
    if (helper.isDir(filepath)) {
      fs.readdirSync(filepath).map(function(file) {
        return path.join(filepath, file);
      }).filter(function(file) {
        return globule.isMatch(self._patterns, file, self.options);
      }).forEach(function(file) {
        self.emit('added', file);
      });
    }
  }

  return this;
};

// Close watchers
Gaze.prototype.close = function(_reset) {
  instances.splice(this._instanceNum, 1);
  platform.closeAll();
  this.emit('end');
};

// Add file patterns to be watched
Gaze.prototype.add = function(files, done) {
  var self = this;
  //console.log('ADD', files);
  if (typeof files === 'string') { files = [files]; }
  this._patterns = helper.unique.apply(null, [this._patterns, files]);
  files = globule.find(this._patterns, this.options);

  // If no matching files
  if (files.length < 1) {
    // Defer to emitting to give a chance to attach event handlers.
    nextback(function() {
      self.emit('ready', self);
      if (done) done.call(self, null, self);
      self.emit('nomatch');
    })();
    return;
  }

  // Set the platform mode before adding files
  platform.mode = self._mode;

  for (var i = 0; i < files.length; i++) {
    platform(path.join(this.options.cwd, files[i]), this._trigger.bind(this));
  }
  platform(this.options.cwd, this._trigger.bind(this));

  // A little delay here for backwards compatibility, lol
  setTimeout(function() {
    self.emit('ready', self);
    if (done) done.call(self, null, self);
  }, 10);
};

// Call when the platform has triggered
Gaze.prototype._trigger = function(error, event, filepath, newFile) {
  if (error) { return this.emit('error', error); }

  // Set the platform mode before adding files
  platform.mode = this._mode;

  if (event === 'change' && helper.isDir(filepath)) {
    this._wasAdded(filepath);
  } else if (event === 'change') {
    this._emitAll('changed', filepath);
  } else if (event === 'delete') {
    // Close out deleted filepaths (important to make safewrite detection work)
    platform.close(filepath);
    this._emitAll('deleted', filepath);
  } else if (event === 'rename') {
    // TODO: This occasionally throws, figure out why or use the old style rename detect
    // The handle(26) returned by watching [filename] is the same with an already watched path([filename])
    this._emitAll('renamed', newFile, filepath);
  }
};

// If a folder received a change event, investigate
Gaze.prototype._wasAdded = function(dir) {
  var self = this;
  var dirstat = fs.statSync(dir);
  fs.readdir(dir, function(err, current) {
    for (var i = 0; i < current.length; i++) {
      var filepath = path.join(dir, current[i]);
      if (!fs.existsSync(filepath)) continue;
      var stat = fs.lstatSync(filepath);
      if ((dirstat.mtime - stat.mtime) <= 0) {
        var relpath = path.relative(self.options.cwd, filepath);
        if (stat.isDirectory()) {
          // If it was a dir, watch the dir and emit that it was added
          platform(filepath, self._trigger.bind(self));
          self._emitAll('added', filepath);
          self._wasAddedSub(filepath);
        } else if (globule.isMatch(self._patterns, relpath, self.options)) {
          // Otherwise if the file matches, emit added
          platform(filepath, self._trigger.bind(self));
          self._emitAll('added', filepath);
        }
      }
    }
  });
};

// If a sub folder was added, investigate further
// Such as with grunt.file.write('new_dir/tmp.js', '') as it will create the folder and file simultaneously
Gaze.prototype._wasAddedSub = function(dir) {
  var self = this;
  fs.readdir(dir, function(err, current) {
    for (var i = 0; i < current.length; i++) {
      var filepath = path.join(dir, current[i]);
      var relpath = path.relative(self.options.cwd, filepath);
      if (fs.lstatSync(filepath).isDirectory()) {
        self._wasAdded(filepath);
      } else if (globule.isMatch(self._patterns, relpath, self.options)) {
        // Make sure to watch the newly added sub file
        platform(filepath, self._trigger.bind(self));
        self._emitAll('added', filepath);
      }
    }
  });
};

// Wrapper for emit to ensure we emit on all instances
Gaze.prototype._emitAll = function() {
  var args = Array.prototype.slice.call(arguments);
  for (var i = 0; i < instances.length; i++) {
    instances[i].emit.apply(instances[i], args);
  }
};

// Remove file/dir from `watched`
Gaze.prototype.remove = function(file) {
  platform.close(file);
  return this;
};

// Return watched files
Gaze.prototype.watched = function(done) {
  done = nextback(done || function() {});
  helper.flatToTree(platform.getWatchedPaths(), this.options.cwd, false, done);
  return this;
};

// Returns `watched` files with relative paths to cwd
Gaze.prototype.relative = function(dir, unixify, done) {
  if (typeof dir === 'function') {
    done = dir;
    dir = null;
    unixify = false;
  }
  if (typeof unixify === 'function') {
    done = unixify;
    unixify = false;
  }
  done = nextback(done || function() {});
  helper.flatToTree(platform.getWatchedPaths(), this.options.cwd, true, unixify, function(err, relative) {
    if (dir) {
      if (unixify) {
        dir = helper.unixifyPathSep(dir);
      }
      // Better guess what to return for backwards compatibility
      return done(null, relative[dir] || relative[dir + (unixify ? '/' : path.sep)] || []);
    }
    return done(null, relative);
  });
  return this;
};
<commit_msg>Clean up<commit_after>/*
 * gaze
 * https://github.com/shama/gaze
 *
 * Copyright (c) 2014 Kyle Robinson Young
 * Licensed under the MIT license.
 */

'use strict';

// libs
var util = require('util');
var EE = require('events').EventEmitter;
var fs = require('fs');
var path = require('path');
var globule = require('globule');
var nextback = require('nextback');
var helper = require('./helper');
var platform = require('./platform');

// keep track of instances to call multiple times for backwards compatibility
var instances = [];

// `Gaze` EventEmitter object to return in the callback
function Gaze(patterns, opts, done) {
  var self = this;
  EE.call(self);

  // If second arg is the callback
  if (typeof opts === 'function') {
    done = opts;
    opts = {};
  }

  // Default options
  opts = opts || {};
  opts.mark = true;
  opts.interval = opts.interval || 500;
  opts.debounceDelay = opts.debounceDelay || 500;
  opts.cwd = opts.cwd || process.cwd();
  this.options = opts;

  // File watching mode to use when adding files to the platform
  this._mode = opts.mode || 'auto';

  // Default done callback
  done = done || function() {};

  // Remember our watched dir:files
  this._watched = Object.create(null);

  // Store watchers
  this._watchers = Object.create(null);

  // Store watchFile listeners
  this._pollers = Object.create(null);

  // Store patterns
  this._patterns = [];

  // Cached events for debouncing
  this._cached = Object.create(null);

  // Set maxListeners
  if (this.options.maxListeners) {
    this.setMaxListeners(this.options.maxListeners);
    Gaze.super_.prototype.setMaxListeners(this.options.maxListeners);
    delete this.options.maxListeners;
  }

  // Initialize the watch on files
  if (patterns) {
    this.add(patterns, done);
  }

  // keep the process alive
  this._keepalive = setInterval(platform.tick.bind(platform), opts.interval);

  // Keep track of all instances created
  this._instanceNum = instances.length;
  instances.push(this);

  // Keep track of safewriting and debounce timeouts
  this._safewriting = null;
  this._safewriteTimeout = null;
  this._timeoutId = null;

  return this;
}
util.inherits(Gaze, EE);

// Main entry point. Start watching and call done when setup
module.exports = function gaze(patterns, opts, done) {
  return new Gaze(patterns, opts, done);
};
module.exports.Gaze = Gaze;

// Override the emit function to emit `all` events
// and debounce on duplicate events per file
Gaze.prototype.emit = function() {
  var self = this;
  var args = arguments;

  var e = args[0];
  var filepath = args[1];

  // If not added/deleted/changed/renamed then just emit the event
  if (e.slice(-2) !== 'ed') {
    Gaze.super_.prototype.emit.apply(self, args);
    return this;
  }

  // Detect rename event, if added and previous deleted is in the cache
  if (e === 'added') {
    Object.keys(this._cached).forEach(function(oldFile) {
      if (self._cached[oldFile].indexOf('deleted') !== -1) {
        args[0] = e = 'renamed';
        [].push.call(args, oldFile);
        delete self._cached[oldFile];
        return false;
      }
    });
  }

  // Detect safewrite events, if file is deleted and then added/renamed, assume a safewrite happened
  if (e === 'deleted' && this._safewriting == null) {
    this._safewriting = filepath;
    this._safewriteTimeout = setTimeout(function() {
      // Just a normal delete, carry on
      Gaze.super_.prototype.emit.apply(self, args);
      Gaze.super_.prototype.emit.apply(self, ['all', e].concat([].slice.call(args, 1)));
      self._safewriting = null;
    }, this.options.debounceDelay);
    return this;
  } else if ((e === 'added' || e === 'renamed') && this._safewriting === filepath) {
    clearTimeout(this._safewriteTimeout);
    this._safewriteTimeout = setTimeout(function() {
      self._safewriting = null;
    }, this.options.debounceDelay);
    args[0] = e = 'changed';
  } else if (e === 'deleted' && this._safewriting === filepath) {
    return this;
  }

  // If cached doesnt exist, create a delay before running the next
  // then emit the event
  var cache = this._cached[filepath] || [];
  if (cache.indexOf(e) === -1) {
    helper.objectPush(self._cached, filepath, e);
    clearTimeout(this._timeoutId);
    this._timeoutId = setTimeout(function() {
      delete self._cached[filepath];
    }, this.options.debounceDelay);
    // Emit the event and `all` event
    Gaze.super_.prototype.emit.apply(self, args);
    Gaze.super_.prototype.emit.apply(self, ['all', e].concat([].slice.call(args, 1)));
  }

  // Detect if new folder added to trigger for matching files within folder
  if (e === 'added') {
    if (helper.isDir(filepath)) {
      fs.readdirSync(filepath).map(function(file) {
        return path.join(filepath, file);
      }).filter(function(file) {
        return globule.isMatch(self._patterns, file, self.options);
      }).forEach(function(file) {
        self.emit('added', file);
      });
    }
  }

  return this;
};

// Close watchers
Gaze.prototype.close = function(_reset) {
  instances.splice(this._instanceNum, 1);
  platform.closeAll();
  this.emit('end');
};

// Add file patterns to be watched
Gaze.prototype.add = function(files, done) {
  var self = this;
  if (typeof files === 'string') { files = [files]; }
  this._patterns = helper.unique.apply(null, [this._patterns, files]);
  files = globule.find(this._patterns, this.options);

  // If no matching files
  if (files.length < 1) {
    // Defer to emitting to give a chance to attach event handlers.
    nextback(function() {
      self.emit('ready', self);
      if (done) done.call(self, null, self);
      self.emit('nomatch');
    })();
    return;
  }

  // Set the platform mode before adding files
  platform.mode = self._mode;

  for (var i = 0; i < files.length; i++) {
    platform(path.join(this.options.cwd, files[i]), this._trigger.bind(this));
  }
  platform(this.options.cwd, this._trigger.bind(this));

  // A little delay here for backwards compatibility, lol
  setTimeout(function() {
    self.emit('ready', self);
    if (done) done.call(self, null, self);
  }, 10);
};

// Call when the platform has triggered
Gaze.prototype._trigger = function(error, event, filepath, newFile) {
  if (error) { return this.emit('error', error); }

  // Set the platform mode before adding files
  platform.mode = this._mode;

  if (event === 'change' && helper.isDir(filepath)) {
    this._wasAdded(filepath);
  } else if (event === 'change') {
    this._emitAll('changed', filepath);
  } else if (event === 'delete') {
    // Close out deleted filepaths (important to make safewrite detection work)
    platform.close(filepath);
    this._emitAll('deleted', filepath);
  } else if (event === 'rename') {
    // TODO: This occasionally throws, figure out why or use the old style rename detect
    // The handle(26) returned by watching [filename] is the same with an already watched path([filename])
    this._emitAll('renamed', newFile, filepath);
  }
};

// If a folder received a change event, investigate
Gaze.prototype._wasAdded = function(dir) {
  var self = this;
  var dirstat = fs.statSync(dir);
  fs.readdir(dir, function(err, current) {
    for (var i = 0; i < current.length; i++) {
      var filepath = path.join(dir, current[i]);
      if (!fs.existsSync(filepath)) continue;
      var stat = fs.lstatSync(filepath);
      if ((dirstat.mtime - stat.mtime) <= 0) {
        var relpath = path.relative(self.options.cwd, filepath);
        if (stat.isDirectory()) {
          // If it was a dir, watch the dir and emit that it was added
          platform(filepath, self._trigger.bind(self));
          self._emitAll('added', filepath);
          self._wasAddedSub(filepath);
        } else if (globule.isMatch(self._patterns, relpath, self.options)) {
          // Otherwise if the file matches, emit added
          platform(filepath, self._trigger.bind(self));
          self._emitAll('added', filepath);
        }
      }
    }
  });
};

// If a sub folder was added, investigate further
// Such as with grunt.file.write('new_dir/tmp.js', '') as it will create the folder and file simultaneously
Gaze.prototype._wasAddedSub = function(dir) {
  var self = this;
  fs.readdir(dir, function(err, current) {
    for (var i = 0; i < current.length; i++) {
      var filepath = path.join(dir, current[i]);
      var relpath = path.relative(self.options.cwd, filepath);
      if (fs.lstatSync(filepath).isDirectory()) {
        self._wasAdded(filepath);
      } else if (globule.isMatch(self._patterns, relpath, self.options)) {
        // Make sure to watch the newly added sub file
        platform(filepath, self._trigger.bind(self));
        self._emitAll('added', filepath);
      }
    }
  });
};

// Wrapper for emit to ensure we emit on all instances
Gaze.prototype._emitAll = function() {
  var args = Array.prototype.slice.call(arguments);
  for (var i = 0; i < instances.length; i++) {
    instances[i].emit.apply(instances[i], args);
  }
};

// Remove file/dir from `watched`
Gaze.prototype.remove = function(file) {
  platform.close(file);
  return this;
};

// Return watched files
Gaze.prototype.watched = function(done) {
  done = nextback(done || function() {});
  helper.flatToTree(platform.getWatchedPaths(), this.options.cwd, false, done);
  return this;
};

// Returns `watched` files with relative paths to cwd
Gaze.prototype.relative = function(dir, unixify, done) {
  if (typeof dir === 'function') {
    done = dir;
    dir = null;
    unixify = false;
  }
  if (typeof unixify === 'function') {
    done = unixify;
    unixify = false;
  }
  done = nextback(done || function() {});
  helper.flatToTree(platform.getWatchedPaths(), this.options.cwd, true, unixify, function(err, relative) {
    if (dir) {
      if (unixify) {
        dir = helper.unixifyPathSep(dir);
      }
      // Better guess what to return for backwards compatibility
      return done(null, relative[dir] || relative[dir + (unixify ? '/' : path.sep)] || []);
    }
    return done(null, relative);
  });
  return this;
};
<|endoftext|>


<commit_before>'use strict';

(function () {
    'use strict';

    angular
      .module('inspections')
      .controller('InspectionsController', InspectionsController);

    InspectionsController.$inject = ['$scope', '$state', 'Authentication', '$timeout', 'InspectionService'];

    function InspectionsController($scope, $state, Authentication, $timeout, InspectionService) {
        var vm = this;

        //vm.inspection = inspection;
        vm.authentication = Authentication;
        vm.error = null;
        vm.form = {};
        vm.remove = remove;
        vm.save = save;
        vm.inspection = {};
        vm.inspectionTemplate = {};

        $timeout(function () {
            sbAdminObj.init();
            vm.loadTemplates();
            //morrisData.init();
        });
        // Remove existing Article
        function remove() {
            if (confirm('Are you sure you want to delete?')) {
                vm.article.$remove($state.go('articles.list'));
            }
        }

        function save(isValid) {
            if (!isValid) {
                $scope.$broadcast('show-errors-check-validity', 'vm.form.inspectionForm');
                return false;
            }

            // TODO: move create/update logic to service
            if (vm.inspection._id) {
                vm.inspection.$update(successCallback, errorCallback);
            } else {
                vm.inspection.$save(successCallback, errorCallback);
            }

            function successCallback(res) {
                $state.go('inspection.view', {
                    inspectionId: res._id
                });
            }

            function errorCallback(res) {
                vm.error = res.data.message;
            }
        }

        vm.loadTemplates = function() {
            var promise = InspectionService.listInpsectionTemplate();
            promise.then(function (res) {
                //ambitApp.utils.convertDateStringsToDates(res);
                vm.showTemplates(res);
                vm.hideUi = false;
            }, function (response) {
                //failed
                //screenSvc.showAlert(response, 2, false);
                vm.hideUi = false;
            });
        }
        vm.showTemplates = function (res) {
            vm.templates = res;
            console.log(res);
        }

    }
})();
<commit_msg>started base model<commit_after>'use strict';

(function () {
    'use strict';

    angular
      .module('inspections')
      .controller('InspectionsController', InspectionsController);

    InspectionsController.$inject = ['$scope', '$state', 'Authentication', '$timeout', 'InspectionService'];

    function InspectionsController($scope, $state, Authentication, $timeout, InspectionService) {
        var vm = this;

        //vm.inspection = inspection;
        vm.authentication = Authentication;
        vm.error = null;
        vm.form = {};
        vm.remove = remove;
        vm.save = save;
        vm.inspection = {};

        vm.inspectionTemplate = {
            "title": "HarrisTeq Demo Template TWO",
            "categories": [
                {
                    "categoryName": "Demo Exterior TWO",
                    "categoryItems": [
                      {
                          "categoryItemName": "Siding",
                          "categoryItemOptions": [
                            {
                                "categoryItemOptionName": "Inspected",
                                "isSelected": false
                            },
                            {
                                "categoryItemOptionName": "Not Inspected",
                                "isSelected": false
                            },
                            {
                                "categoryItemOptionName": "Replace\/Repair",
                                "isSelected": false
                            }
                          ]
                      },
                      {
                          "categoryItemName": "Windows",
                          "categoryItemOptions": [
                            {
                                "categoryItemOptionName": "Inspected",
                                "isSelected": false
                            },
                            {
                                "categoryItemOptionName": "Not Inspected",
                                "isSelected": false
                            },
                            {
                                "categoryItemOptionName": "Replace\/Repair",
                                "isSelected": false
                            }
                          ]
                      },
                      {
                          "categoryItemName": "Doors",
                          "categoryItemOptions": [
                            {
                                "categoryItemOptionName": "Inspected",
                                "isSelected": false
                            },
                            {
                                "categoryItemOptionName": "Not Inspected",
                                "isSelected": false
                            },
                            {
                                "categoryItemOptionName": "Replace\/Repair",
                                "isSelected": false
                            }
                          ]
                      },
                      {
                          "categoryItemName": "Steps",
                          "categoryItemOptions": [
                            {
                                "categoryItemOptionName": "Inspected",
                                "isSelected": false
                            },
                            {
                                "categoryItemOptionName": "Not Inspected",
                                "isSelected": false
                            },
                            {
                                "categoryItemOptionName": "Replace\/Repair",
                                "isSelected": false
                            }
                          ]
                      }
                    ]
                }, {
                    "categoryName": "Heating/Cooling",
                    "categoryItems": [
                      {
                          "categoryItemName": "Heating Equipment",
                          "categoryItemOptions": [
                            {
                                "categoryItemOptionName": "Inspected",
                                "isSelected": false
                            },
                            {
                                "categoryItemOptionName": "Not Inspected",
                                "isSelected": false
                            },
                            {
                                "categoryItemOptionName": "Replace\/Repair",
                                "isSelected": false
                            }
                          ]
                      },
                      {
                          "categoryItemName": "Cooling Equipment",
                          "categoryItemOptions": [
                            {
                                "categoryItemOptionName": "Inspected",
                                "isSelected": false
                            },
                            {
                                "categoryItemOptionName": "Not Inspected",
                                "isSelected": false
                            },
                            {
                                "categoryItemOptionName": "Replace\/Repair",
                                "isSelected": false
                            }
                          ]
                      },
                      {
                          "categoryItemName": "Normal Operating Controls",
                          "categoryItemOptions": [
                            {
                                "categoryItemOptionName": "Inspected",
                                "isSelected": false
                            },
                            {
                                "categoryItemOptionName": "Not Inspected",
                                "isSelected": false
                            },
                            {
                                "categoryItemOptionName": "Replace\/Repair",
                                "isSelected": false
                            }
                          ]
                      }
                    ]
                }
            ]
        };

        vm.createItemOption = function (name, isSelected) {
            var rtn = {}
            rtn["categoryItemOptionName"] = name;
            rtn["isSelected"] = isSelected;
            return rtn;
        };

        vm.createInspectedCategoryItemOptions = function() {
            var rtn = [];
            rtn.push (createItemOption("Inspected", false));
            rtn.push (createItemOption("Not Inspected", false));
            rtn.push(createItemOption("Replace\/Repair", false));

            return rtn;
        };

        $timeout(function () {
            sbAdminObj.init();
            vm.loadTemplates();
            //morrisData.init();
        });
        // Remove existing Article
        function remove() {
            if (confirm('Are you sure you want to delete?')) {
                vm.article.$remove($state.go('articles.list'));
            }
        }

        function save(isValid) {
            if (!isValid) {
                $scope.$broadcast('show-errors-check-validity', 'vm.form.inspectionForm');
                return false;
            }

            // TODO: move create/update logic to service
            if (vm.inspection._id) {
                vm.inspection.$update(successCallback, errorCallback);
            } else {
                vm.inspection.$save(successCallback, errorCallback);
            }

            function successCallback(res) {
                $state.go('inspection.view', {
                    inspectionId: res._id
                });
            }

            function errorCallback(res) {
                vm.error = res.data.message;
            }
        }

        vm.loadTemplates = function() {
            var promise = InspectionService.listInpsectionTemplate();
            promise.then(function (res) {
                //ambitApp.utils.convertDateStringsToDates(res);
                vm.showTemplates(res);
                vm.hideUi = false;
            }, function (response) {
                //failed
                //screenSvc.showAlert(response, 2, false);
                vm.hideUi = false;
            });
        }
        vm.showTemplates = function (res) {
            vm.templates = res;
            console.log(res);
        }

    }
})();
<|endoftext|>


<commit_before>export function getSyntaxTokens(path, tokens) {
  return tokens ? tokens.map((t) => {
    return {
      type: 'code-highlight',
      name: _getTokenType(t),
      start: { path, offset: t.start },
      end: { path, offset: t.end },
      on() {},
      off() {}
    }
  }) : []
}

function _getTokenType(t) {
  return t.type
}

/*
  Matchers for transclusions and cell references

  Examples:
  - A1
  - A1:B10
  - Foo!A1
  - doc1!x
  - 'My Sheet'!A1:B10
  - 'My Doc'.x
*/
const ID = "([_A-Za-z][_A-Za-z0-9]*)"
const NAME = "[']([^']+)[']"
const CELL_ID = "([A-Z]+[1-9][0-9]*)"
// These characters will be replaced. Add more if needed.
const INVALID_ID_CHARACTERS = "[':!$@\\s]"

/*
  A reference can point to a variable, a cell, or a range inside the same document
  or another one. To avoid matches inside of other symbols, '\b' (word boundary) is used in the expression.
  `[']` can not be used in combination with '\b'.

  ```
   ( ( \b ID | ['].+['] )[!] | \b)( CELL_ID([:]CELL_ID)? | ID )
  ```
*/
const REF = "(?:(?:(?:(?:\\b"+ID+"|"+NAME+"))[!])|\\b)(?:"+CELL_ID+"(?:[:]"+CELL_ID+")?|"+ID+")"
const REF_RE = new RegExp(REF)
/*
  Transpiles a piece of source code so that it does not contain
  Transclusion expressions anymore, which are usually not valid in common languages.

  @param {string} code
  @param {object} map storage for transpiled symbols so that they can be mapped back later on
  @result
*/
export function transpile(code, map = {}) {
  let re = new RegExp(REF, 'g')
  let m
  while ((m = re.exec(code))) {
    // NOTE: the array indexes used here correspond to the position of the capturing group
    // make sure to update these if you change the structure of the regular expression
    const symbol = m[0]
    // if this is given, the reference is a transclusion
    const docName = m[1] || m[2]
    const focusCell = m[4]
    const varName = m[5]
    // skip variables or single cells referenced within the same doc
    if (!docName) {
      if (varName || !focusCell) continue
    }
    const transpiledSymbol = toIdentifier(symbol)
    map[transpiledSymbol] = symbol
    // TODO: this could be optimized by storing parts and concatenate at the end
    code = code.substring(0, m.index) + transpiledSymbol + code.substring(m.index+transpiledSymbol.length)
  }
  return code
}

/*

  - `type`: `variable | cell | range`
  - `id`: a qualified id such as `doc1!x`, `sheet1!A1`, `sheet1!A1:A10`
  - `mangledStr`: not longer than the orignal which is used for transpiledCode
  - `scope`: e.g `doc1`, `sheet1`, `'My Document'`"
  - `symbol`: local symbol id such as `x`, `A1`, `A1:A10`
*/
export function parseSymbol(str) {
  let m = REF_RE.exec(str)
  if (!m) throw new Error('Unrecognised symbol format.')
  const startPos = m.index
  const endPos = m[0].length + startPos
  const mangledStr = toIdentifier(m[0])
  const scope = m[1] || m[2]
  const anchorCell = m[3]
  const focusCell = m[4]
  const varName = m[5]
  let type, name
  if (anchorCell) {
    if (focusCell && focusCell !== anchorCell) {
      type = 'range'
      name = anchorCell + ':' + focusCell
    } else {
      type = 'cell'
      name = anchorCell
    }
  } else if (varName) {
    type = 'var'
    name = varName
  } else {
    throw new Error('Invalid symbol expression')
  }
  return { type, scope, name, mangledStr, startPos, endPos }
}

/*
  Replaces all characters that are invalid in a variable identifier.

  Note: replacing characters one-by-one retains the original length or the string
  which is desired as this does avoid source-mapping. E.g. when a runtime error
  occurs, the error location can be applied to the original source code without
  any transformation.
*/
export function toIdentifier(str, c = '_') {
  return str.replace(new RegExp(INVALID_ID_CHARACTERS,'g'), c)
}

export function getCellExpressions(source) {
  let re = new RegExp(REF, 'g')
  let m
  let result = []
  while ((m = re.exec(source))) {
    // NOTE: the array indexes used here correspond to the position of the capturing group
    // make sure to update these if you change the structure of the regular expression
    const text = m[0]
    const startPos = m.index
    const endPos = text.length + startPos

    // if this is given, the reference is a transclusion
    const docName = m[1] || m[2]
    const focusCell = m[4]
    const varName = m[5]

    if(!varName) {
      result.push({text, startPos, endPos})
    }
  }
  return result
}
<commit_msg>Remove unused variables.<commit_after>export function getSyntaxTokens(path, tokens) {
  return tokens ? tokens.map((t) => {
    return {
      type: 'code-highlight',
      name: _getTokenType(t),
      start: { path, offset: t.start },
      end: { path, offset: t.end },
      on() {},
      off() {}
    }
  }) : []
}

function _getTokenType(t) {
  return t.type
}

/*
  Matchers for transclusions and cell references

  Examples:
  - A1
  - A1:B10
  - Foo!A1
  - doc1!x
  - 'My Sheet'!A1:B10
  - 'My Doc'.x
*/
const ID = "([_A-Za-z][_A-Za-z0-9]*)"
const NAME = "[']([^']+)[']"
const CELL_ID = "([A-Z]+[1-9][0-9]*)"
// These characters will be replaced. Add more if needed.
const INVALID_ID_CHARACTERS = "[':!$@\\s]"

/*
  A reference can point to a variable, a cell, or a range inside the same document
  or another one. To avoid matches inside of other symbols, '\b' (word boundary) is used in the expression.
  `[']` can not be used in combination with '\b'.

  ```
   ( ( \b ID | ['].+['] )[!] | \b)( CELL_ID([:]CELL_ID)? | ID )
  ```
*/
const REF = "(?:(?:(?:(?:\\b"+ID+"|"+NAME+"))[!])|\\b)(?:"+CELL_ID+"(?:[:]"+CELL_ID+")?|"+ID+")"
const REF_RE = new RegExp(REF)
/*
  Transpiles a piece of source code so that it does not contain
  Transclusion expressions anymore, which are usually not valid in common languages.

  @param {string} code
  @param {object} map storage for transpiled symbols so that they can be mapped back later on
  @result
*/
export function transpile(code, map = {}) {
  let re = new RegExp(REF, 'g')
  let m
  while ((m = re.exec(code))) {
    // NOTE: the array indexes used here correspond to the position of the capturing group
    // make sure to update these if you change the structure of the regular expression
    const symbol = m[0]
    // if this is given, the reference is a transclusion
    const docName = m[1] || m[2]
    const focusCell = m[4]
    const varName = m[5]
    // skip variables or single cells referenced within the same doc
    if (!docName) {
      if (varName || !focusCell) continue
    }
    const transpiledSymbol = toIdentifier(symbol)
    map[transpiledSymbol] = symbol
    // TODO: this could be optimized by storing parts and concatenate at the end
    code = code.substring(0, m.index) + transpiledSymbol + code.substring(m.index+transpiledSymbol.length)
  }
  return code
}

/*

  - `type`: `variable | cell | range`
  - `id`: a qualified id such as `doc1!x`, `sheet1!A1`, `sheet1!A1:A10`
  - `mangledStr`: not longer than the orignal which is used for transpiledCode
  - `scope`: e.g `doc1`, `sheet1`, `'My Document'`"
  - `symbol`: local symbol id such as `x`, `A1`, `A1:A10`
*/
export function parseSymbol(str) {
  let m = REF_RE.exec(str)
  if (!m) throw new Error('Unrecognised symbol format.')
  const startPos = m.index
  const endPos = m[0].length + startPos
  const mangledStr = toIdentifier(m[0])
  const scope = m[1] || m[2]
  const anchorCell = m[3]
  const focusCell = m[4]
  const varName = m[5]
  let type, name
  if (anchorCell) {
    if (focusCell && focusCell !== anchorCell) {
      type = 'range'
      name = anchorCell + ':' + focusCell
    } else {
      type = 'cell'
      name = anchorCell
    }
  } else if (varName) {
    type = 'var'
    name = varName
  } else {
    throw new Error('Invalid symbol expression')
  }
  return { type, scope, name, mangledStr, startPos, endPos }
}

/*
  Replaces all characters that are invalid in a variable identifier.

  Note: replacing characters one-by-one retains the original length or the string
  which is desired as this does avoid source-mapping. E.g. when a runtime error
  occurs, the error location can be applied to the original source code without
  any transformation.
*/
export function toIdentifier(str, c = '_') {
  return str.replace(new RegExp(INVALID_ID_CHARACTERS,'g'), c)
}

export function getCellExpressions(source) {
  let re = new RegExp(REF, 'g')
  let m
  let result = []
  while ((m = re.exec(source))) {
    // NOTE: the array indexes used here correspond to the position of the capturing group
    // make sure to update these if you change the structure of the regular expression
    const text = m[0]
    const startPos = m.index
    const endPos = text.length + startPos
    const varName = m[5]

    if(!varName) {
      result.push({text, startPos, endPos})
    }
  }
  return result
}
<|endoftext|>


<commit_before>"use strict";

import { timeFormat } from "d3-time-format";
// import { map as d3Map } from "d3-collection";

import financeDiscontinuousScale from "./financeDiscontinuousScale";
import { slidingWindow, zipper, identity, isNotDefined } from "../utils";

const yearFormat = "%Y";
const quarterFormat = "%b %Y";
const monthFormat = "%b";
const weekFormat = "%d %b";
const dayFormat = "%a %d";
const hourFormat = "%_I %p";
const minuteFormat = "%I:%M %p";
const secondFormat = "%I:%M:%S %p";
// const milliSecondFormat = "%L";

const levelDefinition = [

	/* eslint-disable no-unused-vars */
	/* 17 */(d, date, i) => d.startOfYear && date.getFullYear() % 2 === 0 && yearFormat,
	/* 16 */(d, date, i) => d.startOfYear && yearFormat,
	/* 15 */(d, date, i) => d.startOfQuarter && quarterFormat,
	/* 14 */(d, date, i) => d.startOfMonth && monthFormat,
	/* 13 */(d, date, i) => d.startOfWeek && weekFormat,
	/* 12 */(d, date, i) => d.startOfDay && i % 2 === 0 && dayFormat,
	/* 11 */(d, date, i) => d.startOfDay && dayFormat,
	/* 10 */(d, date, i) => d.startOfHalfDay && hourFormat, // 12h
	/*  9 */(d, date, i) => d.startOfQuarterDay && hourFormat, // 6h
	/*  8 */(d, date, i) => d.startOfEighthOfADay && hourFormat, // 3h
	/*  7 */(d, date, i) => d.startOfHour && date.getHours() % 2 === 0 && hourFormat, // 2h -- REMOVE THIS
	/*  6 */(d, date, i) => d.startOfHour && hourFormat, // 1h
	/*  5 */(d, date, i) => d.startOf30Minutes && minuteFormat,
	/*  4 */(d, date, i) => d.startOf15Minutes && minuteFormat,
	/*  3 */(d, date, i) => d.startOf5Minutes && minuteFormat,
	/*  2 */(d, date, i) => d.startOfMinute && minuteFormat,
	/*  1 */(d, date, i) => d.startOf30Seconds && secondFormat,
	/*  0 */(d, date, i) => secondFormat,
	/* eslint-enable no-unused-vars */
];

function evaluateLevel(d, date, i) {
	return levelDefinition
		.map((l, idx) => ({ level: levelDefinition.length - idx - 1, format: l(d, date, i) }))
		.find(l => !!l.format);
}

const discontinuousIndexCalculator = slidingWindow()
	.windowSize(2)
	.undefinedValue((d, idx, di) => {
		const i = di;
		const row = {
			date: d.getTime(),
			startOf30Seconds: false,
			startOfMinute: false,
			startOf5Minutes: false,
			startOf15Minutes: false,
			startOf30Minutes: false,
			startOfHour: false,
			startOfEighthOfADay: false,
			startOfQuarterDay: false,
			startOfHalfDay: false,
			startOfDay: true,
			startOfWeek: false,
			startOfMonth: false,
			startOfQuarter: false,
			startOfYear: false,
		};
		const level = evaluateLevel(row, d, i);
		return { ...row, index: i, ...level };
	});

const discontinuousIndexCalculatorLocalTime = discontinuousIndexCalculator
	.accumulator(([prevDate, nowDate], i, idx, di) => {
		const startOf30Seconds = nowDate.getSeconds() % 30 === 0;

		const startOfMinute = nowDate.getMinutes() !== prevDate.getMinutes();
		const startOf5Minutes = startOfMinute && nowDate.getMinutes() % 5 <= prevDate.getMinutes() % 5;
		const startOf15Minutes = startOfMinute && nowDate.getMinutes() % 15 <= prevDate.getMinutes() % 15;
		const startOf30Minutes = startOfMinute && nowDate.getMinutes() % 30 <= prevDate.getMinutes() % 30;

		const startOfHour = nowDate.getHours() !== prevDate.getHours();

		const startOfEighthOfADay = startOfHour && nowDate.getHours() % 3 === 0;
		const startOfQuarterDay = startOfHour && nowDate.getHours() % 6 === 0;
		const startOfHalfDay = startOfHour && nowDate.getHours() % 12 === 0;

		const startOfDay = nowDate.getDay() !== prevDate.getDay();
		// According to ISO calendar
		// Sunday = 0, Monday = 1, ... Saturday = 6
		// day of week of today < day of week of yesterday then today is start of week
		const startOfWeek = nowDate.getDay() < prevDate.getDay();
		// month of today != month of yesterday then today is start of month
		const startOfMonth = nowDate.getMonth() !== prevDate.getMonth();
		// if start of month and month % 3 === 0 then it is start of quarter
		const startOfQuarter = startOfMonth && (nowDate.getMonth() % 3 <= prevDate.getMonth() % 3);
		// year of today != year of yesterday then today is start of year
		const startOfYear = nowDate.getYear() !== prevDate.getYear();

		const row = {
			date: nowDate.getTime(),
			startOf30Seconds,
			startOfMinute,
			startOf5Minutes,
			startOf15Minutes,
			startOf30Minutes,
			startOfHour,
			startOfEighthOfADay,
			startOfQuarterDay,
			startOfHalfDay,
			startOfDay,
			startOfWeek,
			startOfMonth,
			startOfQuarter,
			startOfYear,
		};
		const level = evaluateLevel(row, nowDate, i);
		return { ...row, index: i + di, ...level };
	});

function doStuff(realDateAccessor, inputDateAccessor, initialIndex) {
	return function(data) {
		const dateAccessor = realDateAccessor(inputDateAccessor);
		const calculate = discontinuousIndexCalculatorLocalTime.source(dateAccessor).misc(initialIndex);
		const index = calculate(data);
		/*
		var map = d3Map();
		for (var i = 0; i < data.length - 1; i++) {

			var nextDate = dateAccessor(data[i + 1]);
			var nowDate = dateAccessor(data[i]);
			var diff = nextDate - nowDate;

			if (map.has(diff)) {
				var count = parseInt(map.get(diff), 10) + 1;
				map.set(diff, count);
			} else {
				map.set(diff, 1);
			}
		}

		var entries = map.entries().sort((a, b) => a.value < b.value);

		// For Renko/p&f

		var interval = entries[0].value === 1
			? Math.round((dateAccessor(last(data)) - dateAccessor(head(data))) / data.length)
			: parseInt(entries[0].key, 10); */

		// return { index, interval };
		return { index };
	};
}

export function discontinuousTimeScaleProviderBuilder() {
	let initialIndex = 0, realDateAccessor = identity;
	let inputDateAccessor = d => d.date,
		indexAccessor = d => d.idx,
		indexMutator = (d, idx) => ({ ...d, idx }),
		withIndex, withInterval;

	// eslint-disable-next-line prefer-const
	let discontinuousTimeScaleProvider = function(data) {
		/*
		console.warn("Are you sure you want to use a discontinuousTimeScale?"
			+ " Use this only if you have discontinuous data which"
			+ " needs to be displayed as continuous."
			+ " If you have continuous data use a d3 scale like"
			+ " `d3.scaleTime`"
		);
		*/

		let index = withIndex;
		let interval = withInterval;
		if (isNotDefined(index)) {
			const response = doStuff(realDateAccessor, inputDateAccessor, initialIndex)(data);
			index = response.index;
			interval = response.interval;
		}
		// console.log(interval, entries[0].key);

		const inputIndex = index.map(each => {
			const { format } = each;
			return {
				...each,
				date: new Date(each.date),
				format: timeFormat(format),
			};
		});

		const xScale = financeDiscontinuousScale(inputIndex, interval);

		const mergedData = zipper()
			.combine(indexMutator);

		const finalData = mergedData(data, inputIndex);

		return {
			data: finalData,
			xScale,
			xAccessor: d => d && indexAccessor(d).index,
			displayXAccessor: realDateAccessor(inputDateAccessor),
		};
	};

	discontinuousTimeScaleProvider.initialIndex = function(x) {
		if (!arguments.length) {
			return initialIndex;
		}
		initialIndex = x;
		return discontinuousTimeScaleProvider;
	};
	discontinuousTimeScaleProvider.inputDateAccessor = function(x) {
		if (!arguments.length) {
			return inputDateAccessor;
		}
		inputDateAccessor = x;
		return discontinuousTimeScaleProvider;
	};
	discontinuousTimeScaleProvider.indexAccessor = function(x) {
		if (!arguments.length) {
			return indexAccessor;
		}
		indexAccessor = x;
		return discontinuousTimeScaleProvider;
	};
	discontinuousTimeScaleProvider.indexMutator = function(x) {
		if (!arguments.length) {
			return indexMutator;
		}
		indexMutator = x;
		return discontinuousTimeScaleProvider;
	};
	discontinuousTimeScaleProvider.withIndex = function(x) {
		if (!arguments.length) {
			return withIndex;
		}
		withIndex = x;
		return discontinuousTimeScaleProvider;
	};
	discontinuousTimeScaleProvider.withInterval = function(x) {
		if (!arguments.length) {
			return withInterval;
		}
		withInterval = x;
		return discontinuousTimeScaleProvider;
	};
	discontinuousTimeScaleProvider.utc = function() {
		realDateAccessor = dateAccessor => d => {
			const date = dateAccessor(d);
			// The getTimezoneOffset() method returns the time-zone offset from UTC, in minutes, for the current locale.
			const offsetInMillis = date.getTimezoneOffset() * 60 * 1000;
			return new Date(date.getTime() + offsetInMillis);
		};
		return discontinuousTimeScaleProvider;
	};
	discontinuousTimeScaleProvider.indexCalculator = function() {
		return doStuff(realDateAccessor, inputDateAccessor, initialIndex);
	};

	return discontinuousTimeScaleProvider;
}

/* discontinuousTimeScaleProvider.utc = function(data,
		dateAccessor,
		indexAccessor,
		indexMutator) {
	var utcDateAccessor = d => {
		var date = dateAccessor(d);
		// The getTimezoneOffset() method returns the time-zone offset from UTC, in minutes, for the current locale.
		var offsetInMillis = date.getTimezoneOffset() * 60 * 1000;
		return new Date(date.getTime() + offsetInMillis);
	};
	return discontinuousTimeScaleProvider(data, utcDateAccessor, indexAccessor, indexMutator);
};*/

export default discontinuousTimeScaleProviderBuilder();
<commit_msg>Locale support for discontinuousTimeScaleProvider<commit_after>"use strict";

import { timeFormat, timeFormatDefaultLocale } from "d3-time-format";
// import { map as d3Map } from "d3-collection";

import financeDiscontinuousScale from "./financeDiscontinuousScale";
import { slidingWindow, zipper, identity, isNotDefined } from "../utils";

const defaultFormatters = {
	yearFormat: "%Y",
	quarterFormat: "%b %Y",
	monthFormat: "%b",
	weekFormat: "%d %b",
	dayFormat: "%a %d",
	hourFormat: "%_I %p",
	minuteFormat: "%I:%M %p",
	secondFormat: "%I:%M:%S %p",
	milliSecondFormat: "%L",
};

const levelDefinition = [
	/* eslint-disable no-unused-vars */
	/* 17 */(d, date, i) => d.startOfYear && date.getFullYear() % 2 === 0 && "yearFormat",
	/* 16 */(d, date, i) => d.startOfYear && "yearFormat",
	/* 15 */(d, date, i) => d.startOfQuarter && "quarterFormat",
	/* 14 */(d, date, i) => d.startOfMonth && "monthFormat",
	/* 13 */(d, date, i) => d.startOfWeek && "weekFormat",
	/* 12 */(d, date, i) => d.startOfDay && i % 2 === 0 && "dayFormat",
	/* 11 */(d, date, i) => d.startOfDay && "dayFormat",
	/* 10 */(d, date, i) => d.startOfHalfDay && "hourFormat", // 12h
	/*  9 */(d, date, i) => d.startOfQuarterDay && "hourFormat", // 6h
	/*  8 */(d, date, i) => d.startOfEighthOfADay && "hourFormat", // 3h
	/*  7 */(d, date, i) => d.startOfHour && date.getHours() % 2 === 0 && "hourFormat", // 2h -- REMOVE THIS
	/*  6 */(d, date, i) => d.startOfHour && "hourFormat", // 1h
	/*  5 */(d, date, i) => d.startOf30Minutes && "minuteFormat",
	/*  4 */(d, date, i) => d.startOf15Minutes && "minuteFormat",
	/*  3 */(d, date, i) => d.startOf5Minutes && "minuteFormat",
	/*  2 */(d, date, i) => d.startOfMinute && "minuteFormat",
	/*  1 */(d, date, i) => d.startOf30Seconds && "secondFormat",
	/*  0 */(d, date, i) => "secondFormat",
	/* eslint-enable no-unused-vars */
];

function evaluateLevel(d, date, i, formatters) {
	return levelDefinition
		.map((l, idx) => ({ level: levelDefinition.length - idx - 1, format: formatters[l(d, date, i)] }))
		.find(l => !!l.format);
}

const discontinuousIndexCalculator = slidingWindow()
	.windowSize(2)
	.undefinedValue((d, idx, { initialIndex, formatters }) => {
		const i = initialIndex;
		const row = {
			date: d.getTime(),
			startOf30Seconds: false,
			startOfMinute: false,
			startOf5Minutes: false,
			startOf15Minutes: false,
			startOf30Minutes: false,
			startOfHour: false,
			startOfEighthOfADay: false,
			startOfQuarterDay: false,
			startOfHalfDay: false,
			startOfDay: true,
			startOfWeek: false,
			startOfMonth: false,
			startOfQuarter: false,
			startOfYear: false,
		};
		const level = evaluateLevel(row, d, i, formatters);
		return { ...row, index: i, ...level };
	});

const discontinuousIndexCalculatorLocalTime = discontinuousIndexCalculator
	.accumulator(([prevDate, nowDate], i, idx, { initialIndex, formatters }) => {
		const startOf30Seconds = nowDate.getSeconds() % 30 === 0;

		const startOfMinute = nowDate.getMinutes() !== prevDate.getMinutes();
		const startOf5Minutes = startOfMinute && nowDate.getMinutes() % 5 <= prevDate.getMinutes() % 5;
		const startOf15Minutes = startOfMinute && nowDate.getMinutes() % 15 <= prevDate.getMinutes() % 15;
		const startOf30Minutes = startOfMinute && nowDate.getMinutes() % 30 <= prevDate.getMinutes() % 30;

		const startOfHour = nowDate.getHours() !== prevDate.getHours();

		const startOfEighthOfADay = startOfHour && nowDate.getHours() % 3 === 0;
		const startOfQuarterDay = startOfHour && nowDate.getHours() % 6 === 0;
		const startOfHalfDay = startOfHour && nowDate.getHours() % 12 === 0;

		const startOfDay = nowDate.getDay() !== prevDate.getDay();
		// According to ISO calendar
		// Sunday = 0, Monday = 1, ... Saturday = 6
		// day of week of today < day of week of yesterday then today is start of week
		const startOfWeek = nowDate.getDay() < prevDate.getDay();
		// month of today != month of yesterday then today is start of month
		const startOfMonth = nowDate.getMonth() !== prevDate.getMonth();
		// if start of month and month % 3 === 0 then it is start of quarter
		const startOfQuarter = startOfMonth && (nowDate.getMonth() % 3 <= prevDate.getMonth() % 3);
		// year of today != year of yesterday then today is start of year
		const startOfYear = nowDate.getYear() !== prevDate.getYear();

		const row = {
			date: nowDate.getTime(),
			startOf30Seconds,
			startOfMinute,
			startOf5Minutes,
			startOf15Minutes,
			startOf30Minutes,
			startOfHour,
			startOfEighthOfADay,
			startOfQuarterDay,
			startOfHalfDay,
			startOfDay,
			startOfWeek,
			startOfMonth,
			startOfQuarter,
			startOfYear,
		};
		const level = evaluateLevel(row, nowDate, i, formatters);
		return { ...row, index: i + initialIndex, ...level };
	});

function doStuff(realDateAccessor, inputDateAccessor, initialIndex, formatters) {
	return function(data) {
		const dateAccessor = realDateAccessor(inputDateAccessor);
		const calculate = discontinuousIndexCalculatorLocalTime.source(dateAccessor).misc({ initialIndex, formatters });
		const index = calculate(data);
		/*
		var map = d3Map();
		for (var i = 0; i < data.length - 1; i++) {

			var nextDate = dateAccessor(data[i + 1]);
			var nowDate = dateAccessor(data[i]);
			var diff = nextDate - nowDate;

			if (map.has(diff)) {
				var count = parseInt(map.get(diff), 10) + 1;
				map.set(diff, count);
			} else {
				map.set(diff, 1);
			}
		}

		var entries = map.entries().sort((a, b) => a.value < b.value);

		// For Renko/p&f

		var interval = entries[0].value === 1
			? Math.round((dateAccessor(last(data)) - dateAccessor(head(data))) / data.length)
			: parseInt(entries[0].key, 10); */

		// return { index, interval };
		return { index };
	};
}

export function discontinuousTimeScaleProviderBuilder() {
	let initialIndex = 0, realDateAccessor = identity;
	let inputDateAccessor = d => d.date,
		indexAccessor = d => d.idx,
		indexMutator = (d, idx) => ({ ...d, idx }),
		withIndex, withInterval;

	let currentFormatters = defaultFormatters;

	// eslint-disable-next-line prefer-const
	let discontinuousTimeScaleProvider = function(data) {
		/*
		console.warn("Are you sure you want to use a discontinuousTimeScale?"
			+ " Use this only if you have discontinuous data which"
			+ " needs to be displayed as continuous."
			+ " If you have continuous data use a d3 scale like"
			+ " `d3.scaleTime`"
		);
		*/

		let index = withIndex;
		let interval = withInterval;
		if (isNotDefined(index)) {
			const response = doStuff(realDateAccessor, inputDateAccessor, initialIndex, currentFormatters)(data);
			index = response.index;
			interval = response.interval;
		}
		// console.log(interval, entries[0].key);

		const inputIndex = index.map(each => {
			const { format } = each;
			return {
				...each,
				date: new Date(each.date),
				format: timeFormat(format),
			};
		});

		const xScale = financeDiscontinuousScale(inputIndex, interval);

		const mergedData = zipper()
			.combine(indexMutator);

		const finalData = mergedData(data, inputIndex);

		return {
			data: finalData,
			xScale,
			xAccessor: d => d && indexAccessor(d).index,
			displayXAccessor: realDateAccessor(inputDateAccessor),
		};
	};

	discontinuousTimeScaleProvider.initialIndex = function(x) {
		if (!arguments.length) {
			return initialIndex;
		}
		initialIndex = x;
		return discontinuousTimeScaleProvider;
	};
	discontinuousTimeScaleProvider.inputDateAccessor = function(x) {
		if (!arguments.length) {
			return inputDateAccessor;
		}
		inputDateAccessor = x;
		return discontinuousTimeScaleProvider;
	};
	discontinuousTimeScaleProvider.indexAccessor = function(x) {
		if (!arguments.length) {
			return indexAccessor;
		}
		indexAccessor = x;
		return discontinuousTimeScaleProvider;
	};
	discontinuousTimeScaleProvider.indexMutator = function(x) {
		if (!arguments.length) {
			return indexMutator;
		}
		indexMutator = x;
		return discontinuousTimeScaleProvider;
	};
	discontinuousTimeScaleProvider.withIndex = function(x) {
		if (!arguments.length) {
			return withIndex;
		}
		withIndex = x;
		return discontinuousTimeScaleProvider;
	};
	discontinuousTimeScaleProvider.withInterval = function(x) {
		if (!arguments.length) {
			return withInterval;
		}
		withInterval = x;
		return discontinuousTimeScaleProvider;
	};
	discontinuousTimeScaleProvider.utc = function() {
		realDateAccessor = dateAccessor => d => {
			const date = dateAccessor(d);
			// The getTimezoneOffset() method returns the time-zone offset from UTC, in minutes, for the current locale.
			const offsetInMillis = date.getTimezoneOffset() * 60 * 1000;
			return new Date(date.getTime() + offsetInMillis);
		};
		return discontinuousTimeScaleProvider;
	};
	discontinuousTimeScaleProvider.indexCalculator = function() {
		return doStuff(realDateAccessor, inputDateAccessor, initialIndex, currentFormatters);
	};

	discontinuousTimeScaleProvider.setLocale = function(locale, formatters = null) {
		if (locale) {
			timeFormatDefaultLocale(locale);
		}
		if (formatters) {
			currentFormatters = formatters;
		}
		return discontinuousTimeScaleProvider;
	};

	return discontinuousTimeScaleProvider;
}

/* discontinuousTimeScaleProvider.utc = function(data,
		dateAccessor,
		indexAccessor,
		indexMutator) {
	var utcDateAccessor = d => {
		var date = dateAccessor(d);
		// The getTimezoneOffset() method returns the time-zone offset from UTC, in minutes, for the current locale.
		var offsetInMillis = date.getTimezoneOffset() * 60 * 1000;
		return new Date(date.getTime() + offsetInMillis);
	};
	return discontinuousTimeScaleProvider(data, utcDateAccessor, indexAccessor, indexMutator);
};*/

export default discontinuousTimeScaleProviderBuilder();
<|endoftext|>


<commit_before>/**
 * @class  NewRelic
 * @author  Flavio De Stefano <flavio.destefano@caffeinalab.com>
 * Simply start NewRelic daemon
 */

/**
 * * **token**: The token of this NewRelic app. Default: `null`
 * @type {Object}
 */
var config = _.extend({
	token: null
}, Alloy.CFG.T.newrelic);
exports.config = config;

var TiNewRelic = null;

(function init() {
	if (!OS_IOS) return;

	try {
		TiNewRelic = require('ti.newrelic');
		if (config.token) {
			TiNewRelic.start(config.token);
		}
	} catch (e) {}
})();<commit_msg>Removed newRelic<commit_after><|endoftext|>


<commit_before>'use strict';

var grunt = require('grunt');

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Load all the grunt tasks provided by plugins. Plugins must be defined as devDependency in package.json
 * and installed with 'npm install'.
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/*
 * Grunt requires plugins to be installed relative to Gruntfile.js. (directly under node_modules).
 * But we want to install the plugins as dependencies of fabs instead of the project itself.
 * So we have to tell Grunt the relative path down to the node_modules folder of fabs.
 */
grunt.verbose.writeln('loading npm tasks');

grunt.loadNpmTasks('fabs/node_modules/grunt-contrib-clean');
grunt.loadNpmTasks('fabs/node_modules/grunt-contrib-copy');
grunt.loadNpmTasks('fabs/node_modules/grunt-contrib-htmlmin');
grunt.loadNpmTasks('fabs/node_modules/grunt-contrib-jshint');
grunt.loadNpmTasks('fabs/node_modules/grunt-contrib-compass');
grunt.loadNpmTasks('fabs/node_modules/grunt-contrib-concat');
grunt.loadNpmTasks('fabs/node_modules/grunt-contrib-cssmin');
grunt.loadNpmTasks('fabs/node_modules/grunt-contrib-watch');
grunt.loadNpmTasks('fabs/node_modules/grunt-contrib-uglify');
grunt.loadNpmTasks('fabs/node_modules/grunt-contrib-connect');
grunt.loadNpmTasks('fabs/node_modules/grunt-contrib-compress');
grunt.loadNpmTasks('fabs/node_modules/grunt-contrib-less');
grunt.loadNpmTasks('fabs/node_modules/grunt-preprocess');
grunt.loadNpmTasks('fabs/node_modules/grunt-connect-proxy');
grunt.loadNpmTasks('fabs/node_modules/grunt-karma');
grunt.loadNpmTasks('fabs/node_modules/grunt-ng-annotate');
grunt.loadNpmTasks('fabs/node_modules/grunt-minjson');
grunt.loadNpmTasks('fabs/node_modules/grunt-replace');
grunt.loadNpmTasks('fabs/node_modules/grunt-html2js');
grunt.loadNpmTasks('fabs/node_modules/grunt-shell');
grunt.loadNpmTasks('fabs/node_modules/grunt-bless');
grunt.loadNpmTasks('fabs/node_modules/grunt-bump');
grunt.loadNpmTasks('fabs/node_modules/grunt-conventional-changelog');
grunt.loadNpmTasks('fabs/node_modules/grunt-protractor-runner');

grunt.verbose.writeln('npm tasks loaded');
<commit_msg>fix(grunt): fix loading grunt plugins installed to projects 'node_modules' folder (npm@3)<commit_after>'use strict';

var grunt = require('grunt');
var path = require('path');
var fs = require('fs');

/*
 * Grunt requires plugins to be installed relative to Gruntfile.js. (directly under node_modules).
 * But we want to install the plugins as dependencies of fabs instead of the project itself.
 * So we have to tell Grunt the relative path down to the node_modules folder of fabs.
 */
grunt.verbose.writeln('loading npm tasks');

var plugins = [
  'grunt-contrib-clean',
  'grunt-contrib-copy',
  'grunt-contrib-htmlmin',
  'grunt-contrib-jshint',
  'grunt-contrib-compass',
  'grunt-contrib-concat',
  'grunt-contrib-cssmin',
  'grunt-contrib-watch',
  'grunt-contrib-uglify',
  'grunt-contrib-connect',
  'grunt-contrib-compress',
  'grunt-contrib-less',
  'grunt-preprocess',
  'grunt-connect-proxy',
  'grunt-karma',
  'grunt-ng-annotate',
  'grunt-minjson',
  'grunt-replace',
  'grunt-html2js',
  'grunt-shell',
  'grunt-bless',
  'grunt-bump',
  'grunt-conventional-changelog',
  'grunt-protractor-runner'
];

var pathToFabs = path.resolve(__dirname, '..', '..');
var pathToFabsModules = path.resolve(pathToFabs, 'node_modules');
//var pathToProject = path.resolve(pathToFabs, '..', '..');
//var pathToProjectModules = path.resolve(pathToProject, 'node_modules');

plugins.forEach(function (plugin) {
  var isRelativeToFabs;

  try {
    isRelativeToFabs = fs.statSync(path.normalize(pathToFabsModules + path.sep + plugin)).isDirectory();
  }
  catch(e) {
    isRelativeToFabs = false;
  }

  if (isRelativeToFabs) {
    grunt.loadNpmTasks('fabs/node_modules/' + plugin);
  }
  else {
    grunt.loadNpmTasks(plugin);
  }
});

grunt.verbose.writeln('npm tasks loaded');
<|endoftext|>


<commit_before><commit_msg>Added a few more solutions<commit_after><|endoftext|>


<commit_before>/*
 * Load required modules
 */
var path   = require('path'),
	fs     = require('fs'),
	marked = require('marked'),
	jade = require('jade'),
	exec  = require('child_process').exec;

/*
 * Scope variable to cache pages
 */
var pages = {};

/*
 * Setup module
 */
module.exports = new Glog();

function Glog() {};

/*
 * Function to handle loading of configs
 */
Glog.prototype.load_configs = function(cb) {

	// Set defaults
	var options = {
		blog_title : 'Glog Blog'
		},
		fn = this;

	fs.readFile(path.join('glog_config.json'), 'UTF-8', function(err, data) {
		if(err) {
			fn.handle_error('Could not load configuration file.  This should be named glog_config.json. Err: ' + err);
		}

		var configs = JSON.parse(data);

		// Check mandatory configs
		if(!configs.port) {
			fn.handle_error('port is not defined in glog_config.json.  This should be set to the port number you wish the blog to run on');
			process.exit();
		}

		if(!configs.blog_repository) {
			fn.handle_error('blog_repository is not defined in glog_config.json.  This should point to the git repository of the blog content');
			process.exit();
		}

		if(!configs.author) {
			fn.handle_error('author is not defined in glog_config.json.  This should be the default blog author');
			process.exit();
		}

		for(key in configs) {
			options[key] = configs[key];
		}

	cb(options);
	});

}

/*
 * Load the articles from disc and add them to an array
 */
Glog.prototype.load_articles = function(options, cb) {

	var articles = [],
		article_path = path.join('blog_repo', '/articles'),
		fn = this;

	console.log('Loading articles from ' + article_path);

	fs.readdir(article_path, function(err, files) {
		if(err) {
			fn.handle_error('Could not read articles directory.  Please make sure paths are set up correctly.  Err: ' + err);
		}

		// Remove incorrect extensions
		for(var i=0; i<files.length; i++) {
			if(path.extname(files[i]) !== '.txt') {
				console.log('Skipping file ' + files[i] + '  Incorrect extension');
				files.splice(i,1);
			}
		}

		for(var i=0; i<files.length; i++) {
			console.log('Reading file ' + files[i]);

			fs.readFile(path.join(article_path, files[i]), 'UTF-8', function(err, data) {
				if(err) {
					fn.handle_error('Error reading article.  Err: ' + err);
				}

				// Extract the header
				var parts = data.split('\n\n');
				var header = JSON.parse(parts[0]);
				parts.splice(0,1);
				var body = marked(parts.join('\n\n'));

				console.log('Read articles with headers: ');
				console.log(header);

				// Check mandatory fields
				if(!header.title) {
					fn.handle_error('Articles must have a title');
					cb(false);
					return;
				}

				if(!header.date) {
					fn.handle_error('Articles must have a date');
					cb(false);
					return;
				}

				// Extract date
				var date = new Date(header.date),
					year = date.getFullYear(),
					month = date.getMonth();

				articles.push({
					'title' : header.title,
					'author' : header.author || options.author,
					'date' : date,
					'date_str' : Glog.formatDate(date),
					'year' : year,
					'month' : month,
					'body' : body,
					'url' : [year, month, (header.url || header.title.replace(/\s/g, '-'))].join('/')
				});

				// If that was the last article then trigger the callback
				if(files.length === articles.length) {
					cb(articles);
				}

			});
		}
	});
}

/*
 * Render the entire blog and store pages in cache
 */
Glog.prototype.render_blog = function(options, articles) {

	var fn = this;

	fs.readFile(path.join('blog_repo', 'layout.jade'), 'UTF-8', function(err, data) {
		if(err) {
			fn.handle_error('Error loading layout.  Err: ' + err);
		}

		console.log('Compiling template for home page');
		var fn = jade.compile(data);

		pages['/'] = fn({
			'title': options.blog_title,
			'articles' : articles
		});

		console.log('Compiling template for individual pages');

		// Loop through articles and compile individual pages
		for(var i=0; i< articles.length; i++) {

			pages[articles[i].url] = fn({
				'title': options.blog_title,
				'articles' : [articles[i]]
			});
		}
	});
};

/*
 * Handle a request for the home page
 */
Glog.prototype.req_home = function(req, res, next) {
	console.log('Home page requested');

	// Set headers
	res.setHeader('Content-Type', 'text/html; charset=utf-8');
	res.setHeader('Cache-Control', 'max-age=2592000');
	res.setHeader('Server', 'Glog (NodeJS)');
	res.end(pages['/']);
};

/*
 * Handle a request for an individual article
 */
Glog.prototype.req_article = function(req, res, next) {

	var fn = this,
		url = [req.params.year, req.params.month, req.params.article].join('/');

	console.log('Requesting ' + url);
	if(typeof pages[url] !== 'undefined') {
		// Set headers
		res.setHeader('Content-Type', 'text/html; charset=utf-8');
		res.setHeader('Cache-Control', 'max-age=2592000');
		res.setHeader('Server', 'Glog (NodeJS)');
		res.end(pages[url]);
	} else {
		fn.req_home(req, res, next);
	}
};

/*
 * Generic error handler
 */
Glog.prototype.handle_error = function(err) {
	console.error(err);
}

/*
 * Function to trigger a build of the entire site
 */
Glog.prototype.rebuild = function(cb) {
	var fn = this,
		next;

	fn.load_configs(function(options) {
		fn.update_repo(options, function() {
			fn.load_articles(options, function(articles) {
				articles = articles.sort(function(a,b) {
					return b.date - a.date;
				});
				fn.render_blog(options, articles);

				cb(options);
			});
		});
	});
};

/*
 * Clone a blog git repository
 */
Glog.prototype.get_repo = function(repo, cb) {

	var fn = this;

	// Attempt to clone the git repo
	console.log('Cloning git repository ' + repo);
	exec('git clone ' + repo + ' blog_repo', function(error, stdout, stderr) {
		if(error) {
			fn.handle_error('Could not clone git repository: ' + error);
		}
		console.log('Stdout: ' + stdout);
		console.log('Stderr: ' + stderr);

		cb();
	});
};

/*
 * Update git repository
 */
Glog.prototype.update_repo = function(options, cb) {

	var fn = this;

	// If repo does not exist, clone it
	fs.stat('blog_repo', function(err, stats) {
		if(err) {
			fn.handle_error(err);
		}

		if(err || !stats.isDirectory()) {
			fn.get_repo(options.blog_repository, cb);
		} else {

			console.log('Updating blog git repo');
			exec('cd blog_repo; git pull origin master', function(error, stdout, stderr) {
				if(err) {
					fn.handle_error('Could not update blog repo: ' + error);
				}
				console.log('Stdout: ' + stdout);
				console.log('Stderr: ' + stderr);

				cb();
			});
		}
	});
};

Glog.formatDate = function(date) {
	var days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
		months = ['January' , 'Febuary', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
		str;

	str = [days[date.getDay()], ', ', date.getDate(), ' ', months[date.getMonth()], ', ', date.getFullYear()].join('');

	return str;

};
<commit_msg>Added external js file<commit_after>/*
 * Load required modules
 */
var path   = require('path'),
	fs     = require('fs'),
	marked = require('marked'),
	jade = require('jade'),
	exec  = require('child_process').exec;

/*
 * Scope variable to cache pages
 */
var pages = {};

/*
 * Setup module
 */
module.exports = new Glog();

function Glog() {};

/*
 * Function to handle loading of configs
 */
Glog.prototype.load_configs = function(cb) {

	// Set defaults
	var options = {
		blog_title : 'Glog Blog'
		},
		fn = this;

	fs.readFile(path.join('glog_config.json'), 'UTF-8', function(err, data) {
		if(err) {
			fn.handle_error('Could not load configuration file.  This should be named glog_config.json. Err: ' + err);
		}

		var configs = JSON.parse(data);

		// Check mandatory configs
		if(!configs.port) {
			fn.handle_error('port is not defined in glog_config.json.  This should be set to the port number you wish the blog to run on');
			process.exit();
		}

		if(!configs.blog_repository) {
			fn.handle_error('blog_repository is not defined in glog_config.json.  This should point to the git repository of the blog content');
			process.exit();
		}

		if(!configs.author) {
			fn.handle_error('author is not defined in glog_config.json.  This should be the default blog author');
			process.exit();
		}

		for(key in configs) {
			options[key] = configs[key];
		}

	cb(options);
	});

}

/*
 * Load the articles from disc and add them to an array
 */
Glog.prototype.load_articles = function(options, cb) {

	var articles = [],
		article_path = path.join('blog_repo', '/articles'),
		fn = this;

	console.log('Loading articles from ' + article_path);

	fs.readdir(article_path, function(err, files) {
		if(err) {
			fn.handle_error('Could not read articles directory.  Please make sure paths are set up correctly.  Err: ' + err);
		}

		// Remove incorrect extensions
		for(var i=0; i<files.length; i++) {
			if(path.extname(files[i]) !== '.txt') {
				console.log('Skipping file ' + files[i] + '  Incorrect extension');
				files.splice(i,1);
			}
		}

		for(var i=0; i<files.length; i++) {
			console.log('Reading file ' + files[i]);

			fs.readFile(path.join(article_path, files[i]), 'UTF-8', function(err, data) {
				if(err) {
					fn.handle_error('Error reading article.  Err: ' + err);
				}

				// Extract the header
				var parts = data.split('\n\n');
				var header = JSON.parse(parts[0]);
				parts.splice(0,1);
				var body = marked(parts.join('\n\n'));

				console.log('Read articles with headers: ');
				console.log(header);

				// Check mandatory fields
				if(!header.title) {
					fn.handle_error('Articles must have a title');
					cb(false);
					return;
				}

				if(!header.date) {
					fn.handle_error('Articles must have a date');
					cb(false);
					return;
				}

				// Extract date
				var date = new Date(header.date),
					year = date.getFullYear(),
					month = date.getMonth();

				// If month < 10 prepend a 0
				if(month < 10) {
					month = ['0', month].join('');
				}

				articles.push({
					'title' : header.title,
					'author' : header.author || options.author,
					'date' : date,
					'date_str' : Glog.formatDate(date),
					'year' : year,
					'month' : month,
					'body' : body,
					'url' : [year, month, (header.url || header.title.replace(/\s/g, '-'))].join('/')
				});

				// If that was the last article then trigger the callback
				if(files.length === articles.length) {
					cb(articles);
				}

			});
		}
	});
}

/*
 * Render the entire blog and store pages in cache
 */
Glog.prototype.render_blog = function(options, articles) {

	var fn = this;

	fs.readFile(path.join('blog_repo', 'layout.jade'), 'UTF-8', function(err, data) {
		if(err) {
			fn.handle_error('Error loading layout.  Err: ' + err);
		}

		console.log('Compiling template for home page');
		var fn = jade.compile(data);

		pages['/'] = fn({
			'title': options.blog_title,
			'articles' : articles
		});

		console.log('Compiling template for individual pages');

		// Loop through articles and compile individual pages
		for(var i=0; i< articles.length; i++) {

			pages[articles[i].url] = fn({
				'title': options.blog_title,
				'articles' : [articles[i]]
			});
		}
	});
};

/*
 * Handle a request for the home page
 */
Glog.prototype.req_home = function(req, res, next) {
	console.log('Home page requested');

	// Set headers
	res.setHeader('Content-Type', 'text/html; charset=utf-8');
	res.setHeader('Cache-Control', 'max-age=2592000');
	res.setHeader('Server', 'Glog (NodeJS)');
	res.end(pages['/']);
};

/*
 * Handle a request for an individual article
 */
Glog.prototype.req_article = function(req, res, next) {

	var fn = this,
		url = [req.params.year, req.params.month, req.params.article].join('/');

	console.log('Requesting ' + url);
	if(typeof pages[url] !== 'undefined') {
		// Set headers
		res.setHeader('Content-Type', 'text/html; charset=utf-8');
		res.setHeader('Cache-Control', 'max-age=2592000');
		res.setHeader('Server', 'Glog (NodeJS)');
		res.end(pages[url]);
	} else {
		fn.req_home(req, res, next);
	}
};

/*
 * Generic error handler
 */
Glog.prototype.handle_error = function(err) {
	console.error(err);
}

/*
 * Function to trigger a build of the entire site
 */
Glog.prototype.rebuild = function(cb) {
	var fn = this,
		next;

	fn.load_configs(function(options) {
		fn.update_repo(options, function() {
			fn.load_articles(options, function(articles) {
				articles = articles.sort(function(a,b) {
					return b.date - a.date;
				});
				fn.render_blog(options, articles);

				cb(options);
			});
		});
	});
};

/*
 * Clone a blog git repository
 */
Glog.prototype.get_repo = function(repo, cb) {

	var fn = this;

	// Attempt to clone the git repo
	console.log('Cloning git repository ' + repo);
	exec('git clone ' + repo + ' blog_repo', function(error, stdout, stderr) {
		if(error) {
			fn.handle_error('Could not clone git repository: ' + error);
		}
		console.log('Stdout: ' + stdout);
		console.log('Stderr: ' + stderr);

		cb();
	});
};

/*
 * Update git repository
 */
Glog.prototype.update_repo = function(options, cb) {

	var fn = this;

	// If repo does not exist, clone it
	fs.stat('blog_repo', function(err, stats) {
		if(err) {
			fn.handle_error(err);
		}

		if(err || !stats.isDirectory()) {
			fn.get_repo(options.blog_repository, cb);
		} else {

			console.log('Updating blog git repo');
			exec('cd blog_repo; git pull origin master', function(error, stdout, stderr) {
				if(err) {
					fn.handle_error('Could not update blog repo: ' + error);
				}
				console.log('Stdout: ' + stdout);
				console.log('Stderr: ' + stderr);

				cb();
			});
		}
	});
};

Glog.formatDate = function(date) {
	var days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
		months = ['January' , 'Febuary', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
		str;

	str = [days[date.getDay()], ', ', date.getDate(), ' ', months[date.getMonth()], ', ', date.getFullYear()].join('');

	return str;

};
<|endoftext|>