<commit_before>function uniqueId() {
  return Date.now() + 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    var r = Math.random()*16|0, v = c === 'x' ? r : (r&0x3|0x8);
    return v.toString(16);
  });
}

var listener = null;
var setupMessageListener = function(siteName, buildEnv) {
  var ref = window.ENV.firebase.root().child('management/sites/' + siteName + '/messages');
  if(listener) {
    ref.off('child_added', listener);
    listener = null;
  }

  var initialIds = {};
  ref.once('value', function(totalData) {
    var val = totalData.val();

    for(var key in val) {
      initialIds[key] = true;
    }

    listener = ref.on('child_added', function(snap) {
      var now = Date.now();
      var message = snap.val();
      var id = snap.name();

      if(!initialIds[id]) {
        if(message.code === 'BUILD') {
          if(message.status === 0) {
            window.ENV.notify('success', 'Site build complete', { icon: 'refresh' });
          } else {
            window.ENV.notify('danger', 'Site build failed', { icon: 'remove' });
          }
          buildEnv.set('building', false);
        }
      }
    });
  });
};

export default Ember.Route.extend({
  notifications: [],

  getBuildEnvironment: function () {

    var route = this;

    if (Ember.isEmpty(route.get('buildEnvironment.isInitialized'))) {
      Ember.Logger.log('ApplicationRoute::getBuildEnvironment');
    } else {
      Ember.Logger.log('ApplicationRoute::getBuildEnvironment::skip');
      return Ember.RSVP.Promise.resolve();
    }

    var buildEnv = route.get('buildEnvironment');

    buildEnv.set('isInitialized', true);
    buildEnv.set('keepReload', Ember.$('meta[name="keepReload"]').attr('content'));

    var siteName = Ember.$('meta[name="siteName"]').attr('content');

    buildEnv.set('siteDisplayName', window.ENV.selfHosted ? siteName.replace('/,1/g', '.') : siteName);
    buildEnv.set('selfHosted', window.ENV.selfHosted);

    if (!window.ENV.selfHosted) {
      window.ENV.siteDNS = siteName + '.webhook.org';
    }
    window.ENV.firebaseRoot.child('/management/sites/' + siteName + '/dns').on('value', function (snap) {
      if (snap.val()) {
        window.ENV.siteDNS = snap.val();
      }
    });

    if (window.ENV.uploadUrl.indexOf('http://') !== 0) {
      window.ENV.uploadUrl = 'http://' + window.ENV.uploadUrl;
    }
    if (window.ENV.uploadUrl.substr(-1) !== '/') {
      window.ENV.uploadUrl = window.ENV.uploadUrl + '/';
    }

    var req = new XMLHttpRequest();
    req.open('GET', document.location, false);
    req.send(null);
    var headers = req.getAllResponseHeaders().toLowerCase();

    return new Ember.RSVP.Promise(function (resolve, reject) {

      if (headers.indexOf('x-webhook-local') !== -1) {
        buildEnv.set('local', true);
        var localSocket = Ember.Object.create({
          socket: new window.WebSocket('ws://' + document.location.hostname + ':6557')
        });

        buildEnv.set('localSocket', localSocket);

        localSocket.reopen({
          connected: function () {
            return this.get('socket.readyState') === 1;
          }.property('socket.readyState')
        });

        localSocket.socket.onmessage = function (event) {
          var storedCallback;
          if (event.data === 'done') {
            storedCallback = localSocket.get('doneCallback');
            localSocket.set('doneCallback', null);

            if (storedCallback) {
              storedCallback();
            }
          } else if (event.data.indexOf('done:') === 0) {
            var data = JSON.parse(event.data.replace('done:', ''));

            storedCallback = localSocket.get('doneCallback');
            localSocket.set('doneCallback', null);

            if (storedCallback) {
              storedCallback(data);
            }
          } else if (event.data.indexOf('message:') === 0) {
            var message = JSON.parse(event.data.replace('message:', ''));
            localSocket.set('message', message);
          }
        };

        localSocket.socket.onopen = function () {
          localSocket.set('connected', true);
          resolve();
        };

        localSocket.socket.onerror = function () {
          resolve();
        };

        if (!$('meta[name=suppressAlert]').attr('content')) {
          localSocket.socket.onclose = function () {
            localSocket.set('lostConnection', true);
          };
        }

        // Shut down LiveReload
        if (window.LiveReload && !buildEnv.get('keepReload')) {
          var shutDown = new CustomEvent('LiveReloadShutDown');
          document.addEventListener("LiveReloadConnect", function () {
            document.dispatchEvent(shutDown);
          }, false);
        }

      } else {
        resolve();
      }
    });
  },

  getMessageSuport: function () {

    var route = this;

    if (Ember.isEmpty(route.get('session.supportedMessages'))) {
      Ember.Logger.log('ApplicationRoute::getMessageSupport');
    } else {
      Ember.Logger.log('ApplicationRoute::getMessageSupport::skip');
      return Ember.RSVP.Promise.resolve();
    }

    route.set('session.supportedMessages', Ember.Object.create());

    return new Ember.RSVP.Promise(function (resolve, reject) {

      var localSocket = route.get('buildEnvironment.localSocket');
      if (!localSocket || !localSocket.connected) {

        Ember.$.ajax({
          dataType: 'jsonp',
          jsonpCallback: 'supportedJSONPCallback',
          url: '/.wh/_supported/',
          success: resolve,
          error: reject
        });

      } else {

        route.gruntCommand('supported_messages', resolve);

      }

    }).then(function (messages) {
      messages.forEach(function (message) {
        route.get('session.supportedMessages').set(message, true);
      });
      Ember.Logger.info('Server Messages Supported:', messages.join(', '));
    }, function (error) {
      Ember.Logger.warn('Failed to retrieve supported grunt messages.');
    });
  },

  // Confirm that user has completed validation steps
  validateUser: function (user) {

    Ember.Logger.log('ApplicationRoute::validateUser');

    var session = this.get('session');
    var siteName = session.get('site.name');

    var managementSiteRef = window.ENV.firebaseRoot.child('management/sites/' + siteName);

    return new Ember.RSVP.Promise(function (resolve, reject) {

      var getToken = function (snapshot) {
        var token = snapshot.val();
        session.set('site.token', token);

        window.ENV.firebase = window.ENV.firebaseRoot.child('buckets/' + siteName + '/' + token + '/dev');

        // if you just logged in, we have to set the firebase property
        DS.FirebaseAdapter.reopen({
          firebase: window.ENV.firebase
        });

        Ember.Logger.log('ApplicationRoute::validateUser::✓');

        resolve(user);
      };

      managementSiteRef.child('key').once('value', getToken, function (error) {

        if (error.code === 'PERMISSION_DENIED') {
          var escapedEmail = user.email.replace(/\./g, ',1');
          // Try to add to user list, if this is allowed they were a potential user
          managementSiteRef.child('users').child(escapedEmail).set(user.email, function () {
            managementSiteRef.root().child('management/users').child(escapedEmail).child('sites/user').child(siteName).set(true, function (error) {
              // Try to delete self from potential user list
              managementSiteRef.child('potential_users').child(escapedEmail).remove(function () {
                // Redo original authorization call
                managementSiteRef.child('key').once('value', getToken, reject);
              }, reject);
            });
          }, reject);
        } else {
          reject(error);
        }

      });

    });

  },

  initializeUser: function (user) {

    Ember.Logger.log('ApplicationRoute::initializeUser');

    var route = this;
    var session = route.get('session');
    var siteName = session.get('site.name');

    var managementSiteRef = window.ENV.firebaseRoot.child('management/sites/' + siteName);

    if (route.get('buildEnvironment.local') === false) {
      setupMessageListener(siteName, route.get('buildEnvironment'));
    }

    Ember.Logger.info('Logged in as ' + user.email);

    var escapedEmail = user.email.replace(/\./g, ',1');

    var ownerCheck = new Ember.RSVP.Promise(function (resolve, reject) {
      session.set('isOwner', false);
      managementSiteRef.once('value', function (snapshot) {
        var siteData = snapshot.val();

        if (siteData.owners[escapedEmail]) {
          Ember.Logger.info('Logged in user is a site owner.');
          session.set('isOwner', true);
        } else if (siteData.users[escapedEmail]) {
          Ember.Logger.info('Logged in user is a site user.');
        } else {
          Ember.Logger.error('Logged in user is neither a site owner or site user??');
        }

        Ember.run(null, resolve);

      });
    });

    // Default billing values
    var billing = Ember.Object.create({
      active: true,
      status: 'paid',
      url: 'http://billing.webhook.com/site/' + siteName + '/',
    });
    billing.reopen({
      isPaid: function () {
        return this.get('status') === 'paid';
      }.property('status'),
      isTrial: function () {
        return this.get('status') === 'trialing';
      }.property('status')
    });
    session.set('billing', billing);

    // Grab actual billing values
    var billingRef = window.ENV.firebaseRoot.child('billing/sites/' + siteName);

    var activeCheck = new Ember.RSVP.Promise(function (resolve, reject) {
      billingRef.child('active').once('value', function (snapshot) {
        session.set('billing.active', snapshot.val());
        Ember.run(null, resolve);
      });
    });

    var statusCheck = new Ember.RSVP.Promise(function (resolve, reject) {
      billingRef.child('status').once('value', function (snapshot) {
        session.set('billing.status', snapshot.val());
        Ember.run(null, resolve);
      });
    });

    var endTrialCheck = new Ember.RSVP.Promise(function (resolve, reject) {
      billingRef.child('endTrial').once('value', function (snapshot) {
        var endTrial = snapshot.val();
        if (endTrial) {
          var endTrialDays = Math.ceil(moment(snapshot.val()).diff(moment(), 'days', true));
          session.set('billing.endTrial', endTrial);
          session.set('billing.endTrialDays', endTrialDays);
          session.set('billing.endTrialIsLastDay', endTrialDays === 1);
        }
        Ember.run(null, resolve);
      });
    });

    return Ember.RSVP.Promise.all([ownerCheck, activeCheck, statusCheck, endTrialCheck]).then(function () {
      session.set('user', user);
    });

  },

  getSession: function () {

    var route = this;
    var session = route.get('session');

    if (Ember.isEmpty(session.get('auth'))) {
      Ember.Logger.log('ApplicationRoute::getSession');
    } else {
      Ember.Logger.log('ApplicationRoute::getSession::skip');
      return Ember.RSVP.Promise.resolve();
    }

    var siteName = session.get('site.name');

    var managementSiteRef = window.ENV.firebaseRoot.child('management/sites/' + siteName);

    return new Ember.RSVP.Promise(function (resolve, reject) {

      var firebaseAuth = new FirebaseSimpleLogin(window.ENV.firebaseRoot, function (error, user) {

        if (route.get('isDestroyed')) {
          return;
        }

        if (user) {
          // Logged in
          route.validateUser(user).then(route.initializeUser.bind(route)).then(resolve);
        } else if (error) {
          // an error occurred while attempting login
          reject(error);
        } else {
          // user is logged out
          session.set('user', null);
          session.set('site.token', null);
          resolve();
        }

      });

      session.set('auth', firebaseAuth);

    });
  },

  beforeModel: function () {
    Ember.Logger.log('ApplicationRoute::beforeModel');

    var route = this;

    return this.getBuildEnvironment().then(function () {
      return Ember.RSVP.Promise.all([
        route.getSession(),
        route.getMessageSuport()
      ]);
    });
  },

  setupController: function (controller) {
    controller.set('notifications', this.get('notifications'));
    this._super.apply(this, arguments);
  },

  gruntCommand: function (command, callback) {
    Ember.Logger.log('%cgruntCommand -> ' + command, 'color: purple; font-weight: bold');

    var localSocket = this.get('buildEnvironment.localSocket');
    if (localSocket && localSocket.connected) {
      localSocket.socket.send(command);
      if (callback) {
        localSocket.doneCallback = callback;
      }
    }
  },

  actions: {
    logoutUser: function () {

      window.ENV.firebase.child('presence/online').child(this.get('session.user.uid')).remove();

      this.get('session.auth').logout();
      this.set('session.user', null);
      this.transitionTo('login');
    },

    notify: function (type, message, options) {

      options = options || {};

      var notifications = this.get('notifications'),
          notification = Ember.Object.create({
            className: 'wy-tray-item' + (type ? '-' + type : ''),
            message: message
          });

      if (options.icon) {
        notification.set('iconClass', 'icon icon-' + options.icon);
      }

      if (options.className) {
        notification.set('extraClassName', options.className);
      }

      notifications.pushObject(notification);

      Ember.run.later(this, function () {
        notification.set('state', 'on');
      }, 10);

      Ember.run.later(this, function () {
        notification.set('state', null);
      }, 4500);

      Ember.run.later(this, function () {
        notifications.removeObject(notification);
      }, 5000);

    },

    chooseLanguage: function (language) {
      Ember.Logger.log('Changing language to %@'.fmt(language));
      window.localStorage.setItem('webhook-cms-language', language);

      Ember.Logger.log('Resetting app.');
      window.App.reset();
    },

    buildSignal: function (publishDate) {
      Ember.Logger.info('Sending build signal:%@'.fmt(publishDate || 'No publish date.'));

      var route = this;

      var user = route.get('session.user.email');

      if (!route.get('buildEnvironment.local')) {

        var data = {
          userid: user,
          sitename: route.get('session.site.name'),
          id: uniqueId()
        };

        if (publishDate) {
          data.build_time = publishDate;
        }

        window.ENV.firebase.root().child('management/commands/build/' + route.get('session.site.name')).set(data);
        route.set('buildEnvironment.building', true);

      } else {

        route.send('gruntCommand', 'build', function () {
          route.send('notify', 'success', 'Local build complete', { icon: 'refresh' });
        });

      }
    },

    gruntCommand: function (command, callback) {
      this.gruntCommand.apply(this, arguments);
    }
  }
});
<commit_msg>let there be login errors again<commit_after>function uniqueId() {
  return Date.now() + 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    var r = Math.random()*16|0, v = c === 'x' ? r : (r&0x3|0x8);
    return v.toString(16);
  });
}

var listener = null;
var setupMessageListener = function(siteName, buildEnv) {
  var ref = window.ENV.firebase.root().child('management/sites/' + siteName + '/messages');
  if(listener) {
    ref.off('child_added', listener);
    listener = null;
  }

  var initialIds = {};
  ref.once('value', function(totalData) {
    var val = totalData.val();

    for(var key in val) {
      initialIds[key] = true;
    }

    listener = ref.on('child_added', function(snap) {
      var now = Date.now();
      var message = snap.val();
      var id = snap.name();

      if(!initialIds[id]) {
        if(message.code === 'BUILD') {
          if(message.status === 0) {
            window.ENV.notify('success', 'Site build complete', { icon: 'refresh' });
          } else {
            window.ENV.notify('danger', 'Site build failed', { icon: 'remove' });
          }
          buildEnv.set('building', false);
        }
      }
    });
  });
};

export default Ember.Route.extend({
  notifications: [],

  getBuildEnvironment: function () {

    var route = this;

    if (Ember.isEmpty(route.get('buildEnvironment.isInitialized'))) {
      Ember.Logger.log('ApplicationRoute::getBuildEnvironment');
    } else {
      Ember.Logger.log('ApplicationRoute::getBuildEnvironment::skip');
      return Ember.RSVP.Promise.resolve();
    }

    var buildEnv = route.get('buildEnvironment');

    buildEnv.set('isInitialized', true);
    buildEnv.set('keepReload', Ember.$('meta[name="keepReload"]').attr('content'));

    var siteName = Ember.$('meta[name="siteName"]').attr('content');

    buildEnv.set('siteDisplayName', window.ENV.selfHosted ? siteName.replace('/,1/g', '.') : siteName);
    buildEnv.set('selfHosted', window.ENV.selfHosted);

    if (!window.ENV.selfHosted) {
      window.ENV.siteDNS = siteName + '.webhook.org';
    }
    window.ENV.firebaseRoot.child('/management/sites/' + siteName + '/dns').on('value', function (snap) {
      if (snap.val()) {
        window.ENV.siteDNS = snap.val();
      }
    });

    if (window.ENV.uploadUrl.indexOf('http://') !== 0) {
      window.ENV.uploadUrl = 'http://' + window.ENV.uploadUrl;
    }
    if (window.ENV.uploadUrl.substr(-1) !== '/') {
      window.ENV.uploadUrl = window.ENV.uploadUrl + '/';
    }

    var req = new XMLHttpRequest();
    req.open('GET', document.location, false);
    req.send(null);
    var headers = req.getAllResponseHeaders().toLowerCase();

    return new Ember.RSVP.Promise(function (resolve, reject) {

      if (headers.indexOf('x-webhook-local') !== -1) {
        buildEnv.set('local', true);
        var localSocket = Ember.Object.create({
          socket: new window.WebSocket('ws://' + document.location.hostname + ':6557')
        });

        buildEnv.set('localSocket', localSocket);

        localSocket.reopen({
          connected: function () {
            return this.get('socket.readyState') === 1;
          }.property('socket.readyState')
        });

        localSocket.socket.onmessage = function (event) {
          var storedCallback;
          if (event.data === 'done') {
            storedCallback = localSocket.get('doneCallback');
            localSocket.set('doneCallback', null);

            if (storedCallback) {
              storedCallback();
            }
          } else if (event.data.indexOf('done:') === 0) {
            var data = JSON.parse(event.data.replace('done:', ''));

            storedCallback = localSocket.get('doneCallback');
            localSocket.set('doneCallback', null);

            if (storedCallback) {
              storedCallback(data);
            }
          } else if (event.data.indexOf('message:') === 0) {
            var message = JSON.parse(event.data.replace('message:', ''));
            localSocket.set('message', message);
          }
        };

        localSocket.socket.onopen = function () {
          localSocket.set('connected', true);
          resolve();
        };

        localSocket.socket.onerror = function () {
          resolve();
        };

        if (!$('meta[name=suppressAlert]').attr('content')) {
          localSocket.socket.onclose = function () {
            localSocket.set('lostConnection', true);
          };
        }

        // Shut down LiveReload
        if (window.LiveReload && !buildEnv.get('keepReload')) {
          var shutDown = new CustomEvent('LiveReloadShutDown');
          document.addEventListener("LiveReloadConnect", function () {
            document.dispatchEvent(shutDown);
          }, false);
        }

      } else {
        resolve();
      }
    });
  },

  getMessageSuport: function () {

    var route = this;

    if (Ember.isEmpty(route.get('session.supportedMessages'))) {
      Ember.Logger.log('ApplicationRoute::getMessageSupport');
    } else {
      Ember.Logger.log('ApplicationRoute::getMessageSupport::skip');
      return Ember.RSVP.Promise.resolve();
    }

    route.set('session.supportedMessages', Ember.Object.create());

    return new Ember.RSVP.Promise(function (resolve, reject) {

      var localSocket = route.get('buildEnvironment.localSocket');
      if (!localSocket || !localSocket.connected) {

        Ember.$.ajax({
          dataType: 'jsonp',
          jsonpCallback: 'supportedJSONPCallback',
          url: '/.wh/_supported/',
          success: resolve,
          error: reject
        });

      } else {

        route.gruntCommand('supported_messages', resolve);

      }

    }).then(function (messages) {
      messages.forEach(function (message) {
        route.get('session.supportedMessages').set(message, true);
      });
      Ember.Logger.info('Server Messages Supported:', messages.join(', '));
    }, function (error) {
      Ember.Logger.warn('Failed to retrieve supported grunt messages.');
    });
  },

  // Confirm that user has completed validation steps
  validateUser: function (user) {

    Ember.Logger.log('ApplicationRoute::validateUser');

    var session = this.get('session');
    var siteName = session.get('site.name');

    var managementSiteRef = window.ENV.firebaseRoot.child('management/sites/' + siteName);

    return new Ember.RSVP.Promise(function (resolve, reject) {

      var getToken = function (snapshot) {
        var token = snapshot.val();
        session.set('site.token', token);

        window.ENV.firebase = window.ENV.firebaseRoot.child('buckets/' + siteName + '/' + token + '/dev');

        // if you just logged in, we have to set the firebase property
        DS.FirebaseAdapter.reopen({
          firebase: window.ENV.firebase
        });

        Ember.Logger.log('ApplicationRoute::validateUser::✓');

        resolve(user);
      };

      managementSiteRef.child('key').once('value', getToken, function (error) {

        if (error.code === 'PERMISSION_DENIED') {
          var escapedEmail = user.email.replace(/\./g, ',1');
          // Try to add to user list, if this is allowed they were a potential user
          managementSiteRef.child('users').child(escapedEmail).set(user.email, function () {
            managementSiteRef.root().child('management/users').child(escapedEmail).child('sites/user').child(siteName).set(true, function (error) {
              // Try to delete self from potential user list
              managementSiteRef.child('potential_users').child(escapedEmail).remove(function () {
                // Redo original authorization call
                managementSiteRef.child('key').once('value', getToken, reject);
              }, reject);
            });
          }, reject);
        } else {
          reject(error);
        }

      });

    });

  },

  initializeUser: function (user) {

    Ember.Logger.log('ApplicationRoute::initializeUser');

    var route = this;
    var session = route.get('session');
    var siteName = session.get('site.name');

    var managementSiteRef = window.ENV.firebaseRoot.child('management/sites/' + siteName);

    if (route.get('buildEnvironment.local') === false) {
      setupMessageListener(siteName, route.get('buildEnvironment'));
    }

    Ember.Logger.info('Logged in as ' + user.email);

    var escapedEmail = user.email.replace(/\./g, ',1');

    var ownerCheck = new Ember.RSVP.Promise(function (resolve, reject) {
      session.set('isOwner', false);
      managementSiteRef.once('value', function (snapshot) {
        var siteData = snapshot.val();

        if (siteData.owners[escapedEmail]) {
          Ember.Logger.info('Logged in user is a site owner.');
          session.set('isOwner', true);
        } else if (siteData.users[escapedEmail]) {
          Ember.Logger.info('Logged in user is a site user.');
        } else {
          Ember.Logger.error('Logged in user is neither a site owner or site user??');
        }

        Ember.run(null, resolve);

      });
    });

    // Default billing values
    var billing = Ember.Object.create({
      active: true,
      status: 'paid',
      url: 'http://billing.webhook.com/site/' + siteName + '/',
    });
    billing.reopen({
      isPaid: function () {
        return this.get('status') === 'paid';
      }.property('status'),
      isTrial: function () {
        return this.get('status') === 'trialing';
      }.property('status')
    });
    session.set('billing', billing);

    // Grab actual billing values
    var billingRef = window.ENV.firebaseRoot.child('billing/sites/' + siteName);

    var activeCheck = new Ember.RSVP.Promise(function (resolve, reject) {
      billingRef.child('active').once('value', function (snapshot) {
        session.set('billing.active', snapshot.val());
        Ember.run(null, resolve);
      });
    });

    var statusCheck = new Ember.RSVP.Promise(function (resolve, reject) {
      billingRef.child('status').once('value', function (snapshot) {
        session.set('billing.status', snapshot.val());
        Ember.run(null, resolve);
      });
    });

    var endTrialCheck = new Ember.RSVP.Promise(function (resolve, reject) {
      billingRef.child('endTrial').once('value', function (snapshot) {
        var endTrial = snapshot.val();
        if (endTrial) {
          var endTrialDays = Math.ceil(moment(snapshot.val()).diff(moment(), 'days', true));
          session.set('billing.endTrial', endTrial);
          session.set('billing.endTrialDays', endTrialDays);
          session.set('billing.endTrialIsLastDay', endTrialDays === 1);
        }
        Ember.run(null, resolve);
      });
    });

    return Ember.RSVP.Promise.all([ownerCheck, activeCheck, statusCheck, endTrialCheck]).then(function () {
      session.set('user', user);
    });

  },

  getSession: function () {

    var route = this;
    var session = route.get('session');

    if (Ember.isEmpty(session.get('auth'))) {
      Ember.Logger.log('ApplicationRoute::getSession');
    } else {
      Ember.Logger.log('ApplicationRoute::getSession::skip');
      return Ember.RSVP.Promise.resolve();
    }

    var siteName = session.get('site.name');

    var managementSiteRef = window.ENV.firebaseRoot.child('management/sites/' + siteName);

    return new Ember.RSVP.Promise(function (resolve, reject) {

      var firebaseAuth = new FirebaseSimpleLogin(window.ENV.firebaseRoot, function (error, user) {

        if (route.get('isDestroyed')) {
          return;
        }

        if (user) {
          // Logged in
          route.validateUser(user).then(route.initializeUser.bind(route)).then(resolve, function (error) {
            session.set('user', null);
            session.set('site.token', null);
            session.set('error', error);
          });
        } else if (error) {
          // an error occurred while attempting login
          session.set('user', null);
          session.set('site.token', null);
          session.set('error', error);
          reject(error);
        } else {
          // user is logged out
          session.set('user', null);
          session.set('site.token', null);
          resolve();
        }

      });

      session.set('auth', firebaseAuth);

    });
  },

  beforeModel: function () {
    Ember.Logger.log('ApplicationRoute::beforeModel');

    var route = this;

    return this.getBuildEnvironment().then(function () {
      return Ember.RSVP.Promise.all([
        route.getSession(),
        route.getMessageSuport()
      ]);
    });
  },

  setupController: function (controller) {
    controller.set('notifications', this.get('notifications'));
    this._super.apply(this, arguments);
  },

  gruntCommand: function (command, callback) {
    Ember.Logger.log('%cgruntCommand -> ' + command, 'color: purple; font-weight: bold');

    var localSocket = this.get('buildEnvironment.localSocket');
    if (localSocket && localSocket.connected) {
      localSocket.socket.send(command);
      if (callback) {
        localSocket.doneCallback = callback;
      }
    }
  },

  actions: {
    logoutUser: function () {

      window.ENV.firebase.child('presence/online').child(this.get('session.user.uid')).remove();

      this.get('session.auth').logout();
      this.set('session.user', null);
      this.transitionTo('login');
    },

    notify: function (type, message, options) {

      options = options || {};

      var notifications = this.get('notifications'),
          notification = Ember.Object.create({
            className: 'wy-tray-item' + (type ? '-' + type : ''),
            message: message
          });

      if (options.icon) {
        notification.set('iconClass', 'icon icon-' + options.icon);
      }

      if (options.className) {
        notification.set('extraClassName', options.className);
      }

      notifications.pushObject(notification);

      Ember.run.later(this, function () {
        notification.set('state', 'on');
      }, 10);

      Ember.run.later(this, function () {
        notification.set('state', null);
      }, 4500);

      Ember.run.later(this, function () {
        notifications.removeObject(notification);
      }, 5000);

    },

    chooseLanguage: function (language) {
      Ember.Logger.log('Changing language to %@'.fmt(language));
      window.localStorage.setItem('webhook-cms-language', language);

      Ember.Logger.log('Resetting app.');
      window.App.reset();
    },

    buildSignal: function (publishDate) {
      Ember.Logger.info('Sending build signal:%@'.fmt(publishDate || 'No publish date.'));

      var route = this;

      var user = route.get('session.user.email');

      if (!route.get('buildEnvironment.local')) {

        var data = {
          userid: user,
          sitename: route.get('session.site.name'),
          id: uniqueId()
        };

        if (publishDate) {
          data.build_time = publishDate;
        }

        window.ENV.firebase.root().child('management/commands/build/' + route.get('session.site.name')).set(data);
        route.set('buildEnvironment.building', true);

      } else {

        route.send('gruntCommand', 'build', function () {
          route.send('notify', 'success', 'Local build complete', { icon: 'refresh' });
        });

      }
    },

    gruntCommand: function (command, callback) {
      this.gruntCommand.apply(this, arguments);
    }
  }
});
<|endoftext|>


<commit_before>var Promise = require('q'),
      https = require('https'),
      zlib  = require('zlib');
      url  = require('url'),
      extend  = require('extend');

var API_ROOT = 'external.api.yle.fi';
var API_VERSION = 'v1';

var YleAPI = function(config) {
  ['APP_ID', 'APP_KEY'].forEach(function(key) {
    if(key in config) {}
    else {
      throw new Error("YleAPI missing config key: ", key);
    }
  });

  this.config = config;
  this.config.api_root = API_ROOT;
};

YleAPI.prototype = {
  get: function (path, params) {
    var fullPath = url.format({
      pathname: "/" + API_VERSION + "/" + path + ".json",
      query: extend({}, params, {
        app_id: this.config.APP_ID,
        app_key: this.config.APP_KEY
      })
    });
    return this.request('GET', fullPath, params);
  },

  request: function(method, path, params) {
    var deferred = Promise.defer();
    var options = {
      hostname: 'external.api.yle.fi',
      port: 443,
      path: path,
      method: method,
      headers: {
        'Accept-Encoding': 'gzip'
      }
    };

    https.request(options, function(response) {
      var responseBody = "";
      var output;

      if(response.headers['content-encoding'] == 'gzip' ) {
        var gzip = zlib.createGunzip();
        response.pipe(gzip);
        output = gzip;
      } else {
        output = response;
      }

      response.on('error', function(error) {
        deferred.reject({
          statusCode: "UNKNOWN ERROR",
          responseBody: error.message
        });
      });

      output.on('data', function (data) {
        data = data.toString('utf-8');
        responseBody += data;
      });

      output.on('end', function() {
        if(response.statusCode > 201) {
          deferred.reject({
            statusCode: response.statusCode,
            responseBody: responseBody
          });
        } else {
          // TODO: what should happen when response is empty?
          deferred.resolve(JSON.parse(responseBody));
        }
      });

    }).end();

    return deferred.promise;
  }
};

module.exports = YleAPI;
<commit_msg>clean stuff<commit_after>var Promise = require('q'),
      https = require('https'),
      zlib  = require('zlib');
      url  = require('url'),
      extend  = require('extend');

var API_ROOT = 'external.api.yle.fi';
var API_VERSION = 'v1';

var YleAPI = function(config) {
  ['APP_ID', 'APP_KEY'].forEach(function(key) {
    if(key in config) {}
    else {
      throw new Error("YleAPI missing config key: ", key);
    }
  });

  this.config = config;
  this.config.api_root = API_ROOT;
};

YleAPI.prototype = {
  get: function (path, params) {
    var fullPath = url.format({
      pathname: "/" + API_VERSION + "/" + path + ".json",
      query: extend({}, params, {
        app_id: this.config.APP_ID,
        app_key: this.config.APP_KEY
      })
    });
    return this.request('GET', fullPath);
  },

  request: function(method, path) {
    var deferred = Promise.defer();
    var options = {
      hostname: API_ROOT,
      port: 443,
      path: path,
      method: method,
      headers: {
        'Accept-Encoding': 'gzip'
      }
    };

    https.request(options, function(response) {
      var responseBody = "";
      var output;

      if(response.headers['content-encoding'] == 'gzip' ) {
        var gzip = zlib.createGunzip();
        response.pipe(gzip);
        output = gzip;
      } else {
        output = response;
      }

      response.on('error', function(error) {
        deferred.reject({
          statusCode: "UNKNOWN ERROR",
          responseBody: error.message
        });
      });

      output.on('data', function (data) {
        data = data.toString('utf-8');
        responseBody += data;
      });

      output.on('end', function() {
        if(response.statusCode > 201) {
          deferred.reject({
            statusCode: response.statusCode,
            responseBody: responseBody
          });
        } else {
          // TODO: what should happen when response is empty?
          deferred.resolve(JSON.parse(responseBody));
        }
      });

    }).end();

    return deferred.promise;
  }
};

module.exports = YleAPI;
<|endoftext|>


<commit_before>(function(window) {
  var defaults  = { protocol : 'https'
                  , domain   : 'mite.yo.lk'
                  , account  : ''
                  , api_key  : ''
                  , async    : true
                  , timeout  : 60 // 1 minute
                  , error  : function(xhr, msg) {alert('Error: mite.gyver could not connect with your mite.account!');}
                  };

  window.miteQuery = (function() {

    ////
    //  Private
    var get_url_for, json_parse,
        _request, _get, _post, _put, _destroy,
        _buildQuery, _parse, _extend,
        account, myself, Base, ActiveArchivedBase, OnlyReadable, TimeEntry, Tracker, Bookmark, Customer, Project, Service, User,
        config = {}, nada = function() {};

    // build URL for API request
    get_url_for = function(path) {
      return config.protocol + '://' + 'corsapi.' + config.domain + '/' + path + '.json';
    };

    // parse string to JSON
    json_parse = function(string) {
      return ( /^\s*$/.test(string) ) ? {} : JSON.parse(string);
    };

    // build a query out of an associative array
    _buildQuery = function(json) {
      if (!json) { return ""; }

      var params = [];
      for(key in json) {
        params.push([encodeURIComponent(key),encodeURIComponent(json[key])].join('='));
      }
      return params.join('&');
    };

    _parse = function(options) {
      if(typeof options == 'function') { options = {success: options}; }
      return options || {};
    };

    _extend = function(obj) {
      for(var i = 1, len = arguments.length; i < len; i++ ) {
        for (var prop in arguments[i]) { obj[prop] = arguments[i][prop]; }
      }
    	return obj;
    };

    // ajax call wrapper
    _request = function(method, path, options) {
      var xhr         = new XMLHttpRequest(),
          data        = options.data      || null,
          async       = (typeof options.async == 'boolean') ? options.async : config.async,
          timeout     = options.timeout   || config.timeout,
          success     = options.success   || nada,
          error       = options.error     || config.error,
          complete    = options.complete  || nada,
          timeout_handler, user_input;

      xhr.onreadystatechange = function(){
        if (xhr.readyState == 4) {
          if (/2\d\d/.test(xhr.status)) {
            if(xhr.responseText) {
              success( json_parse(xhr.responseText) );
            } else {
              error(xhr, 'error');
            }
          } else {
            error(xhr, xhr.responseText || 'error');
          }
          complete(xhr);
          clearTimeout(timeout_handler);
        }
      };

      if (options.error) {
        timeout_handler = setTimeout(function() {
          error(xhr, 'timeout');
        }, timeout * 1000);
      }

      xhr.open(method,path,async);
      if (data instanceof Object) {
        data = JSON.stringify(data);
        xhr.setRequestHeader('Content-Type','application/json');
      }

      xhr.setRequestHeader('X-Requested-With','XMLHttpRequest');
      xhr.setRequestHeader("X-MiteApiKey",  config.api_key);
      xhr.setRequestHeader("X-MiteAccount", config.account);
      xhr.send(data);

      if (!config.async) {
        return json_parse(xhr.responseText);
      }
    };

    // GET request
    _get = function(path, params, options) {
      var parsed_options,
          separator = /\?/.test(path) ? '&' : '?';

      if (typeof options == 'undefined') {
        parsed_options = _parse(params);
      } else {
        parsed_options = _parse(options);
        parsed_options.data = params;
      }

      path = get_url_for(path);
      if (parsed_options.data) {
        path += separator + _buildQuery(parsed_options.data);
        delete(parsed_options.data);
      }

      return _request('GET', path, parsed_options);
    };

    // POST request
    _post = function(path, params, options) {
      var parsed_options  = _parse(options);
      parsed_options.data = params;
      return _request('POST', get_url_for(path), parsed_options);
    };

    // PUT request
    _put = function(path, params, options) {
      var parsed_options  = _parse(options);
      parsed_options.data = params;
      return _request('PUT', get_url_for(path), parsed_options);
    };

    // destroy request
    _destroy = function(path, options) {
      return _request('DELETE', get_url_for(path), _parse(options));
    };

    // http://mite.yo.lk/en/api/account.html
    account             = function(options)              { return    _get('account',                            options); };
    myself              = function(options)              { return    _get('myself',                             options); };

    Base = {
      _name             : function()                     { return this._url.replace(/s$/, "").replace(/ie$/, "y"); },
      _wrapParams       : function()                     { params[this._name()] = params; return params; },
      all               : function(params, options)      { return    _get(this._url,                    params, options); },
      find              : function(id, options)          { return    _get(this._url + "/" + id,                 options); },
      create            : function(params, options)      { return    _post(this._url, this._wrapParams(params), options); },
      update            : function(id, params, options)  { return    _put(this._url + id,               params, options); },
      destroy           : function(id, options)          { return    _destroy(this._url + "/" + id,           options); }
    };

    ActiveArchivedBase = _extend({
      all               : undefined,
      active            : Base.all,
      archived          : function(params, options)      { return    _get(this._url + "/archived",      params, options); }
    }, Base);

    OnlyReadable = {
      create            : undefined,
      update            : undefined,
      destroy           : undefined
    };

    // http://mite.yo.lk/en/api/time-entries.html
    // see also: http://mite.yo.lk/en/api/grouped-time-entries.html
    TimeEntry = _extend({
      _url      : 'time_entries'
    }, Base);

    // http://mite.yo.lk/en/api/tracker.html
    Tracker = {
      find              : function(options)              { return    _get('tracker',                                options); },
      start             : function(id, options)          { return    _put('tracker/'+id,                        {}, options); },
      stop              : function(id, options)          { return    _destroy('tracker/'+id,                        options); }
    };

    // http://mite.yo.lk/en/api/bookmarks.html
    Bookmark = _extend({
      _url              : 'time_entries/bookmarks',
      // TODO fix me (I guess it relates to the redirect)
      time_entries_for  : function(id, options)          { return    _get(this._url + '/' + id + '/follow',   options); }
    }, Base, OnlyReadable);

    // http://mite.yo.lk/en/api/customers.html
    Customer = _extend({
      _url              : 'customers',
      projects_for      : function(ids, options)         { return    _get('projects?customer_id='+ids,              options); },
      time_entries_for  : function(ids, options)         { return    _get('time_entries?customer_id='+ids,          options); }
    }, ActiveArchivedBase);

    // http://mite.yo.lk/en/api/projects.html
    Project = _extend({
      _url              : 'projects',
      time_entries_for  : function(ids, options)         { return    _get('time_entries?project_id='+ids,           options); }
    }, ActiveArchivedBase);

    // http://mite.yo.lk/en/api/services.html
    Service = _extend({
      _url              : 'services',
      time_entries_for  : function(ids, options)         { return    _get('time_entries?service_id='+ids,           options); }
    }, ActiveArchivedBase);

    // http://mite.yo.lk/en/api/users.html
    User = _extend({
      _url              : 'users',
      time_entries_for  : function(ids, options)         { return    _get('time_entries?user_id='+ids,              options); }
    }, ActiveArchivedBase, OnlyReadable);

    ////
    //  Public
    var Interface = function(options) {
      if (!options || !options.account || !options.api_key) {
        throw "account & api_key need to be set";
      }

      config.protocol = options.protocol || defaults.protocol;
      config.domain   = options.domain   || defaults.domain;
      config.account  = options.account  || defaults.account;
      config.api_key  = options.api_key  || defaults.api_key;
      config.async    = options.async    || defaults.async;
      config.timeout  = options.timeout  || defaults.timeout;
      config.error    = options.error    || defaults.error;

      this.config     = config;
    };

    Interface.prototype = {
      // resources
      account   : account,
      myself    : myself,
      TimeEntry : TimeEntry,
      Tracker   : Tracker,
      Bookmark  : Bookmark,
      Customer  : Customer,
      Project   : Project,
      Service   : Service,
      User      : User
    };
    return Interface;
  }());
}(window));<commit_msg>Minor internal naming<commit_after>(function(window) {
  var defaults  = { protocol : 'https'
                  , domain   : 'mite.yo.lk'
                  , account  : ''
                  , api_key  : ''
                  , async    : true
                  , timeout  : 60 // 1 minute
                  , error  : function(xhr, msg) {alert('Error: mite.gyver could not connect with your mite.account!');}
                  };

  window.miteQuery = (function() {

    ////
    //  Private
    var _buildUrl, _parseJson,
        _request, _get, _post, _put, _destroy,
        _buildQuery, _parseOptions, _extend,
        account, myself, Base, ActiveArchivedBase, OnlyReadable,
        TimeEntry, Tracker, Bookmark, Customer, Project, Service, User,
        config = {}, nada = function() {};

    // build URL for API request
    _buildUrl = function(path) {
      return config.protocol + '://' + 'corsapi.' + config.domain + '/' + path + '.json';
    };

    // parse string to JSON
    _parseJson = function(string) {
      return ( /^\s*$/.test(string) ) ? {} : JSON.parse(string);
    };

    // build a query out of an associative array
    _buildQuery = function(json) {
      if (!json) { return ""; }

      var params = [];
      for(key in json) {
        params.push([encodeURIComponent(key),encodeURIComponent(json[key])].join('='));
      }
      return params.join('&');
    };

    _parseOptions = function(options) {
      if(typeof options == 'function') { options = {success: options}; }
      return options || {};
    };

    _extend = function(obj) {
      for(var i = 1, len = arguments.length; i < len; i++ ) {
        for (var prop in arguments[i]) { obj[prop] = arguments[i][prop]; }
      }
    	return obj;
    };

    // ajax call wrapper
    _request = function(method, path, options) {
      var xhr         = new XMLHttpRequest(),
          data        = options.data      || null,
          async       = (typeof options.async == 'boolean') ? options.async : config.async,
          timeout     = options.timeout   || config.timeout,
          success     = options.success   || nada,
          error       = options.error     || config.error,
          complete    = options.complete  || nada,
          timeout_handler, user_input;

      xhr.onreadystatechange = function(){
        if (xhr.readyState == 4) {
          if (/2\d\d/.test(xhr.status)) {
            if(xhr.responseText) {
              success( _parseJson(xhr.responseText) );
            } else {
              error(xhr, 'error');
            }
          } else {
            error(xhr, xhr.responseText || 'error');
          }
          complete(xhr);
          clearTimeout(timeout_handler);
        }
      };

      if (options.error) {
        timeout_handler = setTimeout(function() {
          error(xhr, 'timeout');
        }, timeout * 1000);
      }

      xhr.open(method,path,async);
      if (data instanceof Object) {
        data = JSON.stringify(data);
        xhr.setRequestHeader('Content-Type','application/json');
      }

      xhr.setRequestHeader('X-Requested-With','XMLHttpRequest');
      xhr.setRequestHeader("X-MiteApiKey",  config.api_key);
      xhr.setRequestHeader("X-MiteAccount", config.account);
      xhr.send(data);

      if (!config.async) {
        return _parseJson(xhr.responseText);
      }
    };

    // GET request
    _get = function(path, params, options) {
      var parsed_options,
          separator = /\?/.test(path) ? '&' : '?';

      if (typeof options == 'undefined') {
        parsed_options = _parseOptions(params);
      } else {
        parsed_options = _parseOptions(options);
        parsed_options.data = params;
      }

      path = _buildUrl(path);
      if (parsed_options.data) {
        path += separator + _buildQuery(parsed_options.data);
        delete(parsed_options.data);
      }

      return _request('GET', path, parsed_options);
    };

    // POST request
    _post = function(path, params, options) {
      var parsed_options  = _parseOptions(options);
      parsed_options.data = params;
      return _request('POST', _buildUrl(path), parsed_options);
    };

    // PUT request
    _put = function(path, params, options) {
      var parsed_options  = _parseOptions(options);
      parsed_options.data = params;
      return _request('PUT', _buildUrl(path), parsed_options);
    };

    // destroy request
    _destroy = function(path, options) {
      return _request('DELETE', _buildUrl(path), _parseOptions(options));
    };

    // http://mite.yo.lk/en/api/account.html
    account             = function(options)              { return    _get('account',                            options); };
    myself              = function(options)              { return    _get('myself',                             options); };

    Base = {
      _name             : function()                     { return this._url.replace(/s$/, "").replace(/ie$/, "y"); },
      _wrapParams       : function()                     { params[this._name()] = params; return params; },
      all               : function(params, options)      { return    _get(this._url,                    params, options); },
      find              : function(id, options)          { return    _get(this._url + "/" + id,                 options); },
      create            : function(params, options)      { return    _post(this._url, this._wrapParams(params), options); },
      update            : function(id, params, options)  { return    _put(this._url + id,               params, options); },
      destroy           : function(id, options)          { return    _destroy(this._url + "/" + id,           options); }
    };

    ActiveArchivedBase = _extend({
      all               : undefined,
      active            : Base.all,
      archived          : function(params, options)      { return    _get(this._url + "/archived",      params, options); }
    }, Base);

    OnlyReadable = {
      create            : undefined,
      update            : undefined,
      destroy           : undefined
    };

    // http://mite.yo.lk/en/api/time-entries.html
    // see also: http://mite.yo.lk/en/api/grouped-time-entries.html
    TimeEntry = _extend({
      _url      : 'time_entries'
    }, Base);

    // http://mite.yo.lk/en/api/tracker.html
    Tracker = {
      find              : function(options)              { return    _get('tracker',                                options); },
      start             : function(id, options)          { return    _put('tracker/'+id,                        {}, options); },
      stop              : function(id, options)          { return    _destroy('tracker/'+id,                        options); }
    };

    // http://mite.yo.lk/en/api/bookmarks.html
    Bookmark = _extend({
      _url              : 'time_entries/bookmarks',
      // TODO fix me (I guess it relates to the redirect)
      time_entries_for  : function(id, options)          { return    _get(this._url + '/' + id + '/follow',   options); }
    }, Base, OnlyReadable);

    // http://mite.yo.lk/en/api/customers.html
    Customer = _extend({
      _url              : 'customers',
      projects_for      : function(ids, options)         { return    _get('projects?customer_id='+ids,              options); },
      time_entries_for  : function(ids, options)         { return    _get('time_entries?customer_id='+ids,          options); }
    }, ActiveArchivedBase);

    // http://mite.yo.lk/en/api/projects.html
    Project = _extend({
      _url              : 'projects',
      time_entries_for  : function(ids, options)         { return    _get('time_entries?project_id='+ids,           options); }
    }, ActiveArchivedBase);

    // http://mite.yo.lk/en/api/services.html
    Service = _extend({
      _url              : 'services',
      time_entries_for  : function(ids, options)         { return    _get('time_entries?service_id='+ids,           options); }
    }, ActiveArchivedBase);

    // http://mite.yo.lk/en/api/users.html
    User = _extend({
      _url              : 'users',
      time_entries_for  : function(ids, options)         { return    _get('time_entries?user_id='+ids,              options); }
    }, ActiveArchivedBase, OnlyReadable);

    ////
    //  Public
    var Interface = function(options) {
      if (!options || !options.account || !options.api_key) {
        throw "account & api_key need to be set";
      }

      config.protocol = options.protocol || defaults.protocol;
      config.domain   = options.domain   || defaults.domain;
      config.account  = options.account  || defaults.account;
      config.api_key  = options.api_key  || defaults.api_key;
      config.async    = options.async    || defaults.async;
      config.timeout  = options.timeout  || defaults.timeout;
      config.error    = options.error    || defaults.error;

      this.config     = config;
    };

    Interface.prototype = {
      // resources
      account   : account,
      myself    : myself,
      TimeEntry : TimeEntry,
      Tracker   : Tracker,
      Bookmark  : Bookmark,
      Customer  : Customer,
      Project   : Project,
      Service   : Service,
      User      : User
    };
    return Interface;
  }());
}(window));<|endoftext|>


<commit_before>/*
Copyright (c) 2011, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://yuilibrary.com/license/
*/
var fs = require("fs"),
    rimraf = require('rimraf'),
    path = require("path");

/**
This is the __module__ description for the `YUIDoc` module.

    var options = {
        paths: [ './lib' ],
        outdir: './out'
    };

    var Y = require('yuidocjs');
    var json = (new Y.YUIDoc(options)).run();

@class YUIDoc
@main yuidoc
*/

YUI.add('yuidoc', function(Y) {

    /**
     * The default list of configuration options
     * @property OPTIONS
     * @type Object
     * @final
     * @for YUIDoc
     */

    var OPTIONS = {
        quiet: false,
        writeJSON: true,
        outdir: path.join(process.cwd(),  'out'),
        extension: '.js',
        exclude: '.DS_Store,.svn,CVS,.git,build_rollup_tmp,build_tmp,node_modules',
        norecurse: false,
        version: '0.1.0',
        paths: [],
        themedir: path.join(__dirname,  'themes', 'default'),
        syntaxtype: 'js'
    };

    /**
     * YUIDoc main class

        var options = {
            paths: [ './lib' ],
            outdir: './out'
        };

        var Y = require('yuidoc');
        var json = (new Y.YUIDoc(options)).run();

     * @class YUIDoc
     * @module yuidoc
     * @constructor
     * @param config The config object
     */
    Y.YUIDoc = function(config) {
        /**
         * Holds the number of files that we are processing.
         * @property filecount
         * @type Boolean
         * @private
         */
        this.filecount = 0;
        /**
         * Hash map of dirnames to selleck config options.
         * @property selleck
         * @type Object
         * @private
         */
        this.selleck = {};
        /**
         * Holder for the list of files we are processing.
         * @property filemap
         * @type Object
         * @private
         */
        this.filemap = {};
        /**
         * Holder for the list of directories we are processing.
         * @property dirmap
         * @type Object
         * @private
         */
        this.dirmap = {};

        /**
         * Internal holder for configuration options.
         * @property options
         * @type Object
         * @private
         */
        this.options = Y.merge(OPTIONS, config);

        if (this.options.quiet) {
            Y.applyConfig({
                debug: false
            });
        }

    };

    Y.YUIDoc.prototype = {
        /**
         * Always exclude these directories
         * @method _setDefaultExcludes
         * @private
         */
        _setDefaultExcludes: function() {
            //These should always be excluded
            var excludes = '.DS_Store,.svn,CVS,.git,build_rollup_tmp,build_tmp,node_modules'.split(','),
                self = this;

            excludes.forEach(function(item) {
                self.options.excludes[item] = true;
            });
        },
        /**
         * Does post process on self.options.
         * @method _processConfig
         * @private
         */
        _processConfig: function() {
            this.options.extensions = Y.Array.hash(this.options.extension.split(','));
            this.options.excludes = Y.Array.hash(this.options.exclude.split(','));
            this._setDefaultExcludes();
        },
        /**
         * Walks the paths and parses the directory contents
         * @method walk
         * @private
         */
        walk: function() {
            Y.each(this.options.paths, function(dir) {
                this.parsedir(dir);
            }, this);
        },
        /**
         * Walks the passed directory and grabs all the files recursively.
         * @method parsedir
         * @param {String} dir The directory to parse the contents of.
         * @private
         */
        parsedir: function(dir) {
            if (!Y.Files.isDirectory(dir)) {
                throw('Can not find directory: ' + dir);
            }
            var allfiles = fs.readdirSync(dir), stats,
                files = [], fullpath, self = this;

            if (dir in self.options.excludes) {
                return;
            }
            allfiles = allfiles.sort();

            Y.each(allfiles, function(filename) {
                if (!(filename in self.options.excludes)) {
                    fullpath = path.join(dir, filename);

                    stats = fs.statSync(fullpath);

                    if (stats.isDirectory() && !self.options.norecurse) {
                        self.parsedir(fullpath);
                    } else {
                        files.push(filename);
                    }
                }
            });
            if (!(dir in self.options.excludes)) {
                this.parsefiles(dir, files);
            }
        },
        /**
         * Gathers all the file data and populates the filemap and dirmap hashes.
         * @method parsefiles
         * @param {String} dir The directory to start from.
         * @param {Array} files List of files to parse.
         * @private
         */
        parsefiles: function(dir, files) {
            var self = this;
	    files = files.sort();
            Y.each(files, function(filename) {
                var ext = path.extname(filename), text, fullpath;

                if (ext) {
                    if (ext in self.options.extensions) {
                        fullpath = path.join(dir, filename);

                        if (Y.Files.exists(fullpath)) {
                            self.filecount++;
                            text = fs.readFileSync(fullpath, Y.charset);

                            self.filemap[fullpath] = text;
                            self.dirmap[fullpath] = dir;
                            self.getSelleck(fullpath);

                        } else {
                            Y.log('File skipped: ' + fullpath, 'warn', 'yuidoc');
                        }
                    }
                }
            });
        },
        getSelleck: function(fullpath) {
            var self = this,
                base, comp, json;

            if (self.options.selleck) {
                base = path.dirname(fullpath);
                comp = path.join(base, '../', 'docs', 'component.json');
                //Y.log('Checking for Selleck data: ' + comp, 'info', 'yuidoc');
                if (Y.Files.exists(comp)) {
                    try {
                        var json = JSON.parse(fs.readFileSync(comp, 'utf8'));
                        delete json.examples; //Remove the selleck example data, we only want the comp info
                        self.selleck[fullpath] = json;
                    } catch (e) {
                        Y.log('JSON parse failed on Selleck component.json file: ' + comp, 'error', 'yuidoc');
                    }
                }
            }
        },
        /**
         * Writes the parser JSON data to disk.
         * @method writeJSON
         * @param {Object} parser The DocParser instance to use
         * @private
         * @return {Object} The JSON data returned from the DocParser
         */
        writeJSON: function(parser) {
            var self = this,
            data;

            data = parser.data;

            data.warnings = parser.warnings;

            if (self.selleck && self.options.selleck && data.files && data.modules) {
                Object.keys(self.selleck).forEach(function(file) {
                    Object.keys(data.files).forEach(function(f) {
                        if (file === f) {
                            var mods = data.files[f].modules;
                            if (mods) {
                                Object.keys(mods).forEach(function(mod) {
                                    if (data.modules[mod]) {
                                        if (!data.modules[mod].extra) {
                                            data.modules[mod].extra = {};
                                        }
                                        data.modules[mod].extra.selleck = self.selleck[file];
                                    }
                                });
                            }
                        }
                    });
                });
            }

            if (self.options.project) {
                parser.data.project = self.options.project;
            }

            if (self.options.writeJSON) {
                // Y.log(Y.JSON.stringify(parser.data, null, 4));
                var file = path.join(self.options.outdir, 'data.json'), out;
                if (Y.Files.exists(self.options.outdir) && !self.options.nodeleteout) {
                    Y.log('Found out dir, deleting: ' + self.options.outdir, 'warn', 'yuidoc');
                    rimraf.sync(self.options.outdir);
                }
                if (!Y.Files.exists(self.options.outdir)) {
                    Y.log('Making out dir: ' + self.options.outdir, 'info', 'yuidoc');
                    try {
                        fs.mkdirSync(self.options.outdir, 0777);
                    } catch (e) {
                        Y.log('Outdir creation failed', 'warn', 'yuidoc');
                    }
                }

                out = fs.createWriteStream(file, {
                        flags: "w", encoding: Y.charset, mode: 0644
                });
                out.write(JSON.stringify(data, null, 4));
                out.end();
            }

            return data;
        },
        lint: function(warnings) {
            var code = 0,
                count = 0;

            if (warnings && warnings.length) {
                code = 1;
                console.log('YUIDoc found', warnings.length, 'lint errors in your docs');
                warnings.forEach(function(item) {
                    count++;
                    console.log('#' + count, item.message, item.line + '\n');
                });
            }
            process.exit(code);
        },
        /**
         * Process the config, walk the file tree and write out the JSON data.
         * @method run
         * @return {Object} The JSON data returned from the DocParser
         */
        run: function() {
            /**
             * Timestamp holder so we know when YUIDoc started the parse process.
             * @property starttime
             * @type Timestamp
             */
            Y.log('YUIDoc Starting from: ' + this.options.paths.join(','), 'info', 'yuidoc');
            this.starttime = new Date().getTime();

            var self = this;

            this._processConfig();
            this.walk();

            var json = this.writeJSON(new Y.DocParser({
                syntaxtype: self.options.syntaxtype,
                filemap: self.filemap,
                dirmap: self.dirmap
            }).parse());

            if (this.options.lint) {
                this.lint(json.warnings);
            }

            /**
             * Timestamp holder so we know when YUIDoc has finished the parse process.
             * @property endtime
             * @type Timestamp
             */
            this.endtime = new Date().getTime();
            Y.log('Parsed ' + this.filecount + ' files in ' + ((this.endtime - this.starttime) / 1000) + ' seconds', 'info', 'yuidoc');

            return json;
        }
    };

});
<commit_msg>Change lint so that process only exits on failure.<commit_after>/*
Copyright (c) 2011, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://yuilibrary.com/license/
*/
var fs = require("fs"),
    rimraf = require('rimraf'),
    path = require("path");

/**
This is the __module__ description for the `YUIDoc` module.

    var options = {
        paths: [ './lib' ],
        outdir: './out'
    };

    var Y = require('yuidocjs');
    var json = (new Y.YUIDoc(options)).run();

@class YUIDoc
@main yuidoc
*/

YUI.add('yuidoc', function(Y) {

    /**
     * The default list of configuration options
     * @property OPTIONS
     * @type Object
     * @final
     * @for YUIDoc
     */

    var OPTIONS = {
        quiet: false,
        writeJSON: true,
        outdir: path.join(process.cwd(),  'out'),
        extension: '.js',
        exclude: '.DS_Store,.svn,CVS,.git,build_rollup_tmp,build_tmp,node_modules',
        norecurse: false,
        version: '0.1.0',
        paths: [],
        themedir: path.join(__dirname,  'themes', 'default'),
        syntaxtype: 'js'
    };

    /**
     * YUIDoc main class

        var options = {
            paths: [ './lib' ],
            outdir: './out'
        };

        var Y = require('yuidoc');
        var json = (new Y.YUIDoc(options)).run();

     * @class YUIDoc
     * @module yuidoc
     * @constructor
     * @param config The config object
     */
    Y.YUIDoc = function(config) {
        /**
         * Holds the number of files that we are processing.
         * @property filecount
         * @type Boolean
         * @private
         */
        this.filecount = 0;
        /**
         * Hash map of dirnames to selleck config options.
         * @property selleck
         * @type Object
         * @private
         */
        this.selleck = {};
        /**
         * Holder for the list of files we are processing.
         * @property filemap
         * @type Object
         * @private
         */
        this.filemap = {};
        /**
         * Holder for the list of directories we are processing.
         * @property dirmap
         * @type Object
         * @private
         */
        this.dirmap = {};

        /**
         * Internal holder for configuration options.
         * @property options
         * @type Object
         * @private
         */
        this.options = Y.merge(OPTIONS, config);

        if (this.options.quiet) {
            Y.applyConfig({
                debug: false
            });
        }

    };

    Y.YUIDoc.prototype = {
        /**
         * Always exclude these directories
         * @method _setDefaultExcludes
         * @private
         */
        _setDefaultExcludes: function() {
            //These should always be excluded
            var excludes = '.DS_Store,.svn,CVS,.git,build_rollup_tmp,build_tmp,node_modules'.split(','),
                self = this;

            excludes.forEach(function(item) {
                self.options.excludes[item] = true;
            });
        },
        /**
         * Does post process on self.options.
         * @method _processConfig
         * @private
         */
        _processConfig: function() {
            this.options.extensions = Y.Array.hash(this.options.extension.split(','));
            this.options.excludes = Y.Array.hash(this.options.exclude.split(','));
            this._setDefaultExcludes();
        },
        /**
         * Walks the paths and parses the directory contents
         * @method walk
         * @private
         */
        walk: function() {
            Y.each(this.options.paths, function(dir) {
                this.parsedir(dir);
            }, this);
        },
        /**
         * Walks the passed directory and grabs all the files recursively.
         * @method parsedir
         * @param {String} dir The directory to parse the contents of.
         * @private
         */
        parsedir: function(dir) {
            if (!Y.Files.isDirectory(dir)) {
                throw('Can not find directory: ' + dir);
            }
            var allfiles = fs.readdirSync(dir), stats,
                files = [], fullpath, self = this;

            if (dir in self.options.excludes) {
                return;
            }
            allfiles = allfiles.sort();

            Y.each(allfiles, function(filename) {
                if (!(filename in self.options.excludes)) {
                    fullpath = path.join(dir, filename);

                    stats = fs.statSync(fullpath);

                    if (stats.isDirectory() && !self.options.norecurse) {
                        self.parsedir(fullpath);
                    } else {
                        files.push(filename);
                    }
                }
            });
            if (!(dir in self.options.excludes)) {
                this.parsefiles(dir, files);
            }
        },
        /**
         * Gathers all the file data and populates the filemap and dirmap hashes.
         * @method parsefiles
         * @param {String} dir The directory to start from.
         * @param {Array} files List of files to parse.
         * @private
         */
        parsefiles: function(dir, files) {
            var self = this;
	    files = files.sort();
            Y.each(files, function(filename) {
                var ext = path.extname(filename), text, fullpath;

                if (ext) {
                    if (ext in self.options.extensions) {
                        fullpath = path.join(dir, filename);

                        if (Y.Files.exists(fullpath)) {
                            self.filecount++;
                            text = fs.readFileSync(fullpath, Y.charset);

                            self.filemap[fullpath] = text;
                            self.dirmap[fullpath] = dir;
                            self.getSelleck(fullpath);

                        } else {
                            Y.log('File skipped: ' + fullpath, 'warn', 'yuidoc');
                        }
                    }
                }
            });
        },
        getSelleck: function(fullpath) {
            var self = this,
                base, comp, json;

            if (self.options.selleck) {
                base = path.dirname(fullpath);
                comp = path.join(base, '../', 'docs', 'component.json');
                //Y.log('Checking for Selleck data: ' + comp, 'info', 'yuidoc');
                if (Y.Files.exists(comp)) {
                    try {
                        var json = JSON.parse(fs.readFileSync(comp, 'utf8'));
                        delete json.examples; //Remove the selleck example data, we only want the comp info
                        self.selleck[fullpath] = json;
                    } catch (e) {
                        Y.log('JSON parse failed on Selleck component.json file: ' + comp, 'error', 'yuidoc');
                    }
                }
            }
        },
        /**
         * Writes the parser JSON data to disk.
         * @method writeJSON
         * @param {Object} parser The DocParser instance to use
         * @private
         * @return {Object} The JSON data returned from the DocParser
         */
        writeJSON: function(parser) {
            var self = this,
            data;

            data = parser.data;

            data.warnings = parser.warnings;

            if (self.selleck && self.options.selleck && data.files && data.modules) {
                Object.keys(self.selleck).forEach(function(file) {
                    Object.keys(data.files).forEach(function(f) {
                        if (file === f) {
                            var mods = data.files[f].modules;
                            if (mods) {
                                Object.keys(mods).forEach(function(mod) {
                                    if (data.modules[mod]) {
                                        if (!data.modules[mod].extra) {
                                            data.modules[mod].extra = {};
                                        }
                                        data.modules[mod].extra.selleck = self.selleck[file];
                                    }
                                });
                            }
                        }
                    });
                });
            }

            if (self.options.project) {
                parser.data.project = self.options.project;
            }

            if (self.options.writeJSON) {
                // Y.log(Y.JSON.stringify(parser.data, null, 4));
                var file = path.join(self.options.outdir, 'data.json'), out;
                if (Y.Files.exists(self.options.outdir) && !self.options.nodeleteout) {
                    Y.log('Found out dir, deleting: ' + self.options.outdir, 'warn', 'yuidoc');
                    rimraf.sync(self.options.outdir);
                }
                if (!Y.Files.exists(self.options.outdir)) {
                    Y.log('Making out dir: ' + self.options.outdir, 'info', 'yuidoc');
                    try {
                        fs.mkdirSync(self.options.outdir, 0777);
                    } catch (e) {
                        Y.log('Outdir creation failed', 'warn', 'yuidoc');
                    }
                }

                out = fs.createWriteStream(file, {
                        flags: "w", encoding: Y.charset, mode: 0644
                });
                out.write(JSON.stringify(data, null, 4));
                out.end();
            }

            return data;
        },
        lint: function(warnings) {
            var code = 0,
                count = 0;

            if (warnings && warnings.length) {
                code = 1;
                console.log('YUIDoc found', warnings.length, 'lint errors in your docs');
                warnings.forEach(function(item) {
                    count++;
                    console.log('#' + count, item.message, item.line + '\n');
                });
                process.exit(code);
            }
        },
        /**
         * Process the config, walk the file tree and write out the JSON data.
         * @method run
         * @return {Object} The JSON data returned from the DocParser
         */
        run: function() {
            /**
             * Timestamp holder so we know when YUIDoc started the parse process.
             * @property starttime
             * @type Timestamp
             */
            Y.log('YUIDoc Starting from: ' + this.options.paths.join(','), 'info', 'yuidoc');
            this.starttime = new Date().getTime();

            var self = this;

            this._processConfig();
            this.walk();

            var json = this.writeJSON(new Y.DocParser({
                syntaxtype: self.options.syntaxtype,
                filemap: self.filemap,
                dirmap: self.dirmap
            }).parse());

            if (this.options.lint) {
                this.lint(json.warnings);
            }

            /**
             * Timestamp holder so we know when YUIDoc has finished the parse process.
             * @property endtime
             * @type Timestamp
             */
            this.endtime = new Date().getTime();
            Y.log('Parsed ' + this.filecount + ' files in ' + ((this.endtime - this.starttime) / 1000) + ' seconds', 'info', 'yuidoc');

            return json;
        }
    };

});
<|endoftext|>