<commit_before>import React, { Component, PropTypes } from 'react';
import fecha from 'fecha';

import Article from 'grommet/components/Article';
import Box from 'grommet/components/Box';
import Button from 'grommet/components/Button';
import Header from 'grommet/components/Header';
import Footer from 'grommet/components/Footer';
import Heading from 'grommet/components/Heading';
import Label from 'grommet/components/Label';
import Section from 'grommet/components/Section';
import Tile from 'grommet/components/Tile';
import Tiles from 'grommet/components/Tiles';
import Paragraph from 'grommet/components/Paragraph';

import EditIcon from 'grommet/components/icons/base/Edit';
import CloseIcon from 'grommet/components/icons/base/Close';
import DeleteIcon from 'grommet/components/icons/base/Trash';
import StatusIcon from 'grommet/components/icons/Status';
import SpinningIcon from 'grommet/components/icons/Spinning';

import ManageHeader from './Header';
import ManageDeletePost from './ManageDeletePost';
import ManageCancelChangePost from './ManageCancelChangePost';

import Error from '../Error';
import Loading from '../Loading';
import BlogFooter from '../Footer';
import store from '../../store';
import history from '../../RouteHistory';

import { setDocumentTitle } from '../../utils/blog';

export default class Manage extends Component {

  /**
  * used by the server to achieve isomorphic with async data.
  * This function must return a promise!
  * See /server/blog.js.
  */
  static fetchData (location, params, appContext) {
    store.addContext(appContext);
    return store.getArchive('/manage');
  }

  constructor () {
    super();

    this._onArchiveReceived = this._onArchiveReceived.bind(this);
    this._onArchiveFailed = this._onArchiveFailed.bind(this);
    this._renderArchive = this._renderArchive.bind(this);
    this._onRequestToDeletePost = this._onRequestToDeletePost.bind(this);
    this._onDeletePost = this._onDeletePost.bind(this);
    this._onDeletePostCancel = this._onDeletePostCancel.bind(this);
    this._onCancelChangeCancel = this._onCancelChangeCancel.bind(this);
    this._onDeleteSucceed = this._onDeleteSucceed.bind(this);
    this._onCancelChangeSucceed = this._onCancelChangeSucceed.bind(this);
    this._onDeleteFailed = this._onDeleteFailed.bind(this);
    this._onCancelChangeFailed = this._onCancelChangeFailed.bind(this);
    this._onCancelChange = this._onCancelChange.bind(this);
    this._onRequestToCancelChange = this._onRequestToCancelChange.bind(this);

    this.state = {
      archive: undefined,
      loading: true,
      delete: false,
      deleting: false,
      post: undefined
    };
  }

  componentDidMount () {
    setDocumentTitle('Manage');
    store.getArchive('/manage').then(
      this._onArchiveReceived, this._onArchiveFailed
    );
  }

  componentWillReceiveProps () {
    store.getArchive('/manage').then(
      this._onArchiveReceived, this._onArchiveFailed
    );
  }

  _onArchiveReceived (archive) {
    if (archive && Object.keys(archive).length === 0) {
      archive = undefined;
    }
    this.setState({
      archive: archive,
      loading: false,
      deleting: false,
      canceling: false,
      post: undefined,
      error: undefined
    });
  }

  _onArchiveFailed () {
    this.setState({
      archive: undefined,
      loading: false,
      error: 'Could not load posts. Make sure you have internet connection and try again.'
    });
  }

  _onEditPost (postId, event) {
    event.preventDefault();
    history.push(`/manage/post/edit/${postId}`);
  }

  _onDeletePost () {
    this.setState({deleting: true, delete: false});
    store.deletePost(this.state.post).then(
      this._onDeleteSucceed, this._onDeleteFailed
    );
  }

  _onRequestToDeletePost (post, event) {
    event.preventDefault();
    this.setState({delete: true, post: post});
  }

  _onRequestToCancelChange (post, event) {
    event.preventDefault();
    this.setState({cancelChange: true, post: post});
  }

  _onDeletePostCancel () {
    this.setState({delete: false, post: undefined});
  }

  _onCancelChangeCancel () {
    this.setState({cancelChange: false, post: undefined});
  }

  _onDeleteSucceed () {
    store.getArchive('/manage').then(
      this._onArchiveReceived, this._onArchiveFailed
    );
  }

  _onDeleteFailed () {
    this.setState({
      loading: false,
      deleting: false,
      error: 'Could not delete post. Make sure you have internet connection and try again.'
    });
  }

  _onCancelChange () {
    this.setState({canceling: true, cancelChange: false});
    store.cancelChange(this.state.post).then(
      this._onCancelChangeSucceed, this._onCancelChangeFailed
    );
  }

  _onCancelChangeSucceed () {
    //giving some time for the github api to reflect the changes.
    setTimeout(() => {
      store.getArchive('/manage').then(
        this._onArchiveReceived, this._onArchiveFailed
      );
    }, 2000);
  }

  _onCancelChangeFailed () {
    this.setState({
      loading: false,
      canceling: false,
      error: 'Could not cancel change. Make sure you have internet connection and try again.'
    });
  }

  _renderArchive () {
    let monthKeys = Object.keys(this.archive);
    return monthKeys.map((monthLabel, index) => {
      const postsByMonth = this.archive[monthLabel];
      let posts = postsByMonth.map((post, index) => {
        let formattedDate = fecha.format(
          new Date(post.createdAt), 'MMMM D, YYYY'
        );

        const editIcon = <EditIcon a11yTitle={`Edit ${post.title} post`} />;

        let footerNode;
        if (this.state.deleting && this.state.post.id === post.id) {
          footerNode = (
            <Box direction="row" responsive={false}>
              <Box justify="center">
                <SpinningIcon />
              </Box>
              <Box pad={{ horizontal: 'small' }}>
                Deleting...
              </Box>
            </Box>
          );
        } else {
          const deleteIcon = <DeleteIcon a11yTitle={`Delete ${post.title} post`} />;
          footerNode = (
            <Box direction="row" responsive={false}>
              <Button href={`/manage/post/edit/${post.id}`} icon={editIcon}
                onClick={this._onEditPost.bind(this, post.id)} />
              <Button href="#" icon={deleteIcon}
                onClick={this._onRequestToDeletePost.bind(this, post)} />
            </Box>
          );
        }

        let colorIndexProp = 'neutral-1';

        let editButton;
        if (post.action !== 'Delete') {
          editButton = (
            <Button href={`/manage/post/edit/${post.id}`} icon={editIcon}
              onClick={this._onEditPost.bind(this, post.id)} />
          );
        }

        let postChangeActions = (
          <Box direction="row" responsive={false} justify='end'>
            {editButton}
            <Button plain={true} icon={<CloseIcon />}
              onClick={this._onRequestToCancelChange.bind(this, post)}
              a11yTitle={`Cancel ${post.action} ${post.title} post`} />
          </Box>
        );
        if (this.state.canceling && this.state.post.id === post.id) {
          postChangeActions = (
            <Box direction="row" responsive={false} justify='end'>
              <Box justify="center">
                <SpinningIcon />
              </Box>
              <Box pad={{ horizontal: 'small' }}>
                Canceling...
              </Box>
            </Box>
          );
        }

        if (post.pending) {
          colorIndexProp = 'grey-2';
          footerNode = (
            <Box justify='between' full='horizontal'>
              <Box direction="row" responsive={false}>
                <Box justify='center'>
                  <StatusIcon value='warning' />
                </Box>
                <Box justify='center'>
                  {post.action} post is pending approval
                </Box>
              </Box>
              {postChangeActions}
            </Box>
          );
        }

        return (
          <Tile key={`post_${index}`} align='start' pad='small'
            colorIndex={colorIndexProp}>

              <Heading tag='h4' strong={true}>
                {post.title}
              </Heading>

            <Box pad={{horizontal: 'small'}} className='flex'>
              <Paragraph>
                Posted {formattedDate} by {post.author}
              </Paragraph>
            </Box>

              {footerNode}

          </Tile>
        );
      }, this);

      return (
        <Box key={`month_group_${index}`} separator='top'>
          {monthLabel}
          <Tiles size='large' flush={false}>
            {posts}
          </Tiles>
        </Box>
      );
    });
  }

  render () {

    this.archive = this.state.archive;
    this.loading = this.state.loading;
    if (store.useContext() && this.context.asyncData) {
      this.loading = false;
      this.archive = this.context.asyncData;
    }

    let archiveNode;
    let footerNode;
    if (this.archive) {
      footerNode = (
        <BlogFooter />
      );
      archiveNode = this._renderArchive();
    } else if (!this.loading) {
      archiveNode = (

No posts have been found.

      );
    } else {
      footerNode = undefined;
      archiveNode = (
        <Loading />
      );
    }

    let errorNode;
    if (this.state.error) {
      errorNode = (
        <Error message={this.state.error} />
      );
    }

    let deleteLayer;
    if (this.state.delete) {
      deleteLayer = (
        <ManageDeletePost post={this.state.post}
          onCancel={this._onDeletePostCancel} onDelete={this._onDeletePost} />
      );
    }

    let cancelChangeLayer;
    if (this.state.cancelChange) {
      cancelChangeLayer = (
        <ManageCancelChangePost post={this.state.post}
          onCancel={this._onCancelChangeCancel} onConfirm={this._onCancelChange} />
      );
    }

    return (

        <ManageHeader />

          <Heading tag="h2" strong={true}>Manage</Heading>
          {errorNode}
          {archiveNode}

        {footerNode}
        {deleteLayer}
        {cancelChangeLayer}

    );
  }
}

Manage.propTypes = {
  params: PropTypes.object
};

Manage.contextTypes = {
  asyncData: PropTypes.any
};
<commit_msg>Added link for post in manage page.<commit_after>import React, { Component, PropTypes } from 'react';
import fecha from 'fecha';

import Anchor from 'grommet/components/Anchor';
import Article from 'grommet/components/Article';
import Box from 'grommet/components/Box';
import Button from 'grommet/components/Button';
import Header from 'grommet/components/Header';
import Footer from 'grommet/components/Footer';
import Heading from 'grommet/components/Heading';
import Label from 'grommet/components/Label';
import Section from 'grommet/components/Section';
import Tile from 'grommet/components/Tile';
import Tiles from 'grommet/components/Tiles';
import Paragraph from 'grommet/components/Paragraph';

import EditIcon from 'grommet/components/icons/base/Edit';
import CloseIcon from 'grommet/components/icons/base/Close';
import DeleteIcon from 'grommet/components/icons/base/Trash';
import StatusIcon from 'grommet/components/icons/Status';
import SpinningIcon from 'grommet/components/icons/Spinning';

import ManageHeader from './Header';
import ManageDeletePost from './ManageDeletePost';
import ManageCancelChangePost from './ManageCancelChangePost';

import Error from '../Error';
import Loading from '../Loading';
import BlogFooter from '../Footer';
import store from '../../store';
import history from '../../RouteHistory';

import { setDocumentTitle } from '../../utils/blog';

export default class Manage extends Component {

  /**
  * used by the server to achieve isomorphic with async data.
  * This function must return a promise!
  * See /server/blog.js.
  */
  static fetchData (location, params, appContext) {
    store.addContext(appContext);
    return store.getArchive('/manage');
  }

  constructor () {
    super();

    this._onArchiveReceived = this._onArchiveReceived.bind(this);
    this._onArchiveFailed = this._onArchiveFailed.bind(this);
    this._renderArchive = this._renderArchive.bind(this);
    this._onRequestToDeletePost = this._onRequestToDeletePost.bind(this);
    this._onDeletePost = this._onDeletePost.bind(this);
    this._onDeletePostCancel = this._onDeletePostCancel.bind(this);
    this._onCancelChangeCancel = this._onCancelChangeCancel.bind(this);
    this._onDeleteSucceed = this._onDeleteSucceed.bind(this);
    this._onCancelChangeSucceed = this._onCancelChangeSucceed.bind(this);
    this._onDeleteFailed = this._onDeleteFailed.bind(this);
    this._onCancelChangeFailed = this._onCancelChangeFailed.bind(this);
    this._onCancelChange = this._onCancelChange.bind(this);
    this._onRequestToCancelChange = this._onRequestToCancelChange.bind(this);
    this._onRequestForPost = this._onRequestForPost.bind(this);

    this.state = {
      archive: undefined,
      loading: true,
      delete: false,
      deleting: false,
      post: undefined
    };
  }

  componentDidMount () {
    setDocumentTitle('Manage');
    store.getArchive('/manage').then(
      this._onArchiveReceived, this._onArchiveFailed
    );
  }

  componentWillReceiveProps () {
    store.getArchive('/manage').then(
      this._onArchiveReceived, this._onArchiveFailed
    );
  }

  _onArchiveReceived (archive) {
    if (archive && Object.keys(archive).length === 0) {
      archive = undefined;
    }
    this.setState({
      archive: archive,
      loading: false,
      deleting: false,
      canceling: false,
      post: undefined,
      error: undefined
    });
  }

  _onArchiveFailed () {
    this.setState({
      archive: undefined,
      loading: false,
      error: 'Could not load posts. Make sure you have internet connection and try again.'
    });
  }

  _onRequestForPost (event) {
    event.preventDefault();
    history.push(event.currentTarget.getAttribute('href'));
  }

  _onEditPost (postId, event) {
    event.preventDefault();
    history.push(`/manage/post/edit/${postId}`);
  }

  _onDeletePost () {
    this.setState({deleting: true, delete: false});
    store.deletePost(this.state.post).then(
      this._onDeleteSucceed, this._onDeleteFailed
    );
  }

  _onRequestToDeletePost (post, event) {
    event.preventDefault();
    this.setState({delete: true, post: post});
  }

  _onRequestToCancelChange (post, event) {
    event.preventDefault();
    this.setState({cancelChange: true, post: post});
  }

  _onDeletePostCancel () {
    this.setState({delete: false, post: undefined});
  }

  _onCancelChangeCancel () {
    this.setState({cancelChange: false, post: undefined});
  }

  _onDeleteSucceed () {
    store.getArchive('/manage').then(
      this._onArchiveReceived, this._onArchiveFailed
    );
  }

  _onDeleteFailed () {
    this.setState({
      loading: false,
      deleting: false,
      error: 'Could not delete post. Make sure you have internet connection and try again.'
    });
  }

  _onCancelChange () {
    this.setState({canceling: true, cancelChange: false});
    store.cancelChange(this.state.post).then(
      this._onCancelChangeSucceed, this._onCancelChangeFailed
    );
  }

  _onCancelChangeSucceed () {
    //giving some time for the github api to reflect the changes.
    setTimeout(() => {
      store.getArchive('/manage').then(
        this._onArchiveReceived, this._onArchiveFailed
      );
    }, 2000);
  }

  _onCancelChangeFailed () {
    this.setState({
      loading: false,
      canceling: false,
      error: 'Could not cancel change. Make sure you have internet connection and try again.'
    });
  }

  _renderArchive () {
    let monthKeys = Object.keys(this.archive);
    return monthKeys.map((monthLabel, index) => {
      const postsByMonth = this.archive[monthLabel];
      let posts = postsByMonth.map((post, index) => {
        let formattedDate = fecha.format(
          new Date(post.createdAt), 'MMMM D, YYYY'
        );

        const editIcon = <EditIcon a11yTitle={`Edit ${post.title} post`} />;

        let footerNode;
        if (this.state.deleting && this.state.post.id === post.id) {
          footerNode = (
            <Box direction="row" responsive={false}>
              <Box justify="center">
                <SpinningIcon />
              </Box>
              <Box pad={{ horizontal: 'small' }}>
                Deleting...
              </Box>
            </Box>
          );
        } else {
          const deleteIcon = <DeleteIcon a11yTitle={`Delete ${post.title} post`} />;
          footerNode = (
            <Box direction="row" responsive={false}>
              <Button href={`/manage/post/edit/${post.id}`} icon={editIcon}
                onClick={this._onEditPost.bind(this, post.id)} />
              <Button href="#" icon={deleteIcon}
                onClick={this._onRequestToDeletePost.bind(this, post)} />
            </Box>
          );
        }

        let colorIndexProp = 'neutral-1';

        let editButton;
        if (post.action !== 'Delete') {
          editButton = (
            <Button href={`/manage/post/edit/${post.id}`} icon={editIcon}
              onClick={this._onEditPost.bind(this, post.id)} />
          );
        }

        let postChangeActions = (
          <Box direction="row" responsive={false} justify='end'>
            {editButton}
            <Button plain={true} icon={<CloseIcon />}
              onClick={this._onRequestToCancelChange.bind(this, post)}
              a11yTitle={`Cancel ${post.action} ${post.title} post`} />
          </Box>
        );
        if (this.state.canceling && this.state.post.id === post.id) {
          postChangeActions = (
            <Box direction="row" responsive={false} justify='end'>
              <Box justify="center">
                <SpinningIcon />
              </Box>
              <Box pad={{ horizontal: 'small' }}>
                Canceling...
              </Box>
            </Box>
          );
        }

        let headerNode = (
          <Heading tag='h4' strong={true}>
            {post.title}
          </Heading>
        );
        if (post.pending) {
          colorIndexProp = 'grey-2';
          footerNode = (
            <Box justify='between' full='horizontal'>
              <Box direction="row" responsive={false}>
                <Box justify='center'>
                  <StatusIcon value='warning' />
                </Box>
                <Box justify='center'>
                  {post.action} post is pending approval
                </Box>
              </Box>
              {postChangeActions}
            </Box>
          );
        } else {
          headerNode = (
            <Anchor href={`/post/${post.id}`} onClick={this._onRequestForPost}>
              {headerNode}
            </Anchor>
          );
        }

        return (
          <Tile key={`post_${index}`} align='start' pad='small'
            colorIndex={colorIndexProp}>

              {headerNode}

            <Box pad={{horizontal: 'small'}} className='flex'>
              <Paragraph>
                Posted {formattedDate} by {post.author}
              </Paragraph>
            </Box>

              {footerNode}

          </Tile>
        );
      }, this);

      return (
        <Box key={`month_group_${index}`} separator='top'>
          {monthLabel}
          <Tiles size='large' flush={false}>
            {posts}
          </Tiles>
        </Box>
      );
    });
  }

  render () {

    this.archive = this.state.archive;
    this.loading = this.state.loading;
    if (store.useContext() && this.context.asyncData) {
      this.loading = false;
      this.archive = this.context.asyncData;
    }

    let archiveNode;
    let footerNode;
    if (this.archive) {
      footerNode = (
        <BlogFooter />
      );
      archiveNode = this._renderArchive();
    } else if (!this.loading) {
      archiveNode = (

No posts have been found.

      );
    } else {
      footerNode = undefined;
      archiveNode = (
        <Loading />
      );
    }

    let errorNode;
    if (this.state.error) {
      errorNode = (
        <Error message={this.state.error} />
      );
    }

    let deleteLayer;
    if (this.state.delete) {
      deleteLayer = (
        <ManageDeletePost post={this.state.post}
          onCancel={this._onDeletePostCancel} onDelete={this._onDeletePost} />
      );
    }

    let cancelChangeLayer;
    if (this.state.cancelChange) {
      cancelChangeLayer = (
        <ManageCancelChangePost post={this.state.post}
          onCancel={this._onCancelChangeCancel} onConfirm={this._onCancelChange} />
      );
    }

    return (

        <ManageHeader />

          <Heading tag="h2" strong={true}>Manage</Heading>
          {errorNode}
          {archiveNode}

        {footerNode}
        {deleteLayer}
        {cancelChangeLayer}

    );
  }
}

Manage.propTypes = {
  params: PropTypes.object
};

Manage.contextTypes = {
  asyncData: PropTypes.any
};
<|endoftext|>


<commit_before>"use strict"

// Module dependencies
var consolidate = require("consolidate");
var mustache = require("mustache");
var express = require("express");
var session = require("express-session");
var passport = require("passport");
var cookieParser = require("cookie-parser");
var bodyParser = require("body-parser");
var winston = require("winston");
var path = require("path");
var async = require("async");
var openVeoAPI = require("openveo-api");
var applicationStorage = openVeoAPI.applicationStorage;

// Set module root directory and define a custom require function
process.root = __dirname;
process.require = function(filePath){
  return require(path.normalize(process.root + "/" + filePath));
};

// Module files
var pluginLoader = process.require("app/server/loaders/pluginLoader.js");
var routeLoader = process.require("app/server/loaders/routeLoader");
var DefaultController = process.require("app/server/controllers/DefaultController.js");

// Configuration files
var serverConf = process.require("config/serverConf.json");
var databaseConf = process.require("config/databaseConf.json");
var conf = process.require("conf.json");

var server;

// Initialize logger
process.require("app/server/logger.js");

// Retrieve initialized logger
var logger = winston.loggers.get("openveo");

// Retrieve back office menu and views folders from configuration
var menu = conf["backOffice"]["menu"];
var viewsFolders = conf["viewsFolders"];

// Create express application and main routers
// One router for the font end "/"
// One router for the back end "/admin"
var app = express();
var router = express.Router();
var adminRouter = express.Router();

// Remove x-powered-by http header
app.set("x-powered-by", false);

// Set mustache as the template engine
app.engine("html", consolidate.mustache);
app.set("view engine", "html");

// Common options for all static servers
// delivering static files
var staticServerOptions = {
  extensions: ["htm", "html"],
  maxAge: "1d",
  setHeaders: function(response, path, stat){
    response.set("x-timestamp", Date.now());
  }
};

// Load all middlewares which need to operate
// on each request
// The cookieParser and session middlewares are required
// by passport
app.use(cookieParser());
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.use(session({ secret: serverConf["sessionSecret"], saveUninitialized: true, resave: true }));
app.use(passport.initialize());
app.use(passport.session());

// Log each request method, path and headers
app.use(function(request, response, next){
  logger.info({method : request.method, path : request.url, headers : request.headers});
  next();
});

// Load and apply main routes from configuration to
// public and back end routers
applyRoutes(routeLoader.decodeRoutes(__dirname, conf["routes"]["public"]), router);
applyRoutes(routeLoader.decodeRoutes(__dirname, conf["routes"]["admin"]), adminRouter);

// Mount public and back end routers
app.use("/admin", adminRouter);
app.use("/", router);

async.series([

  // Establish a connection to the database
  function(callback){

    // Get a Database instance
    var db = openVeoAPI.Database.getDatabase(databaseConf);

    // Establish connection to the database
    db.connect(function(error){
      if(error)
        process.exit(0);

      applicationStorage.setDatabase(db);

      // Initialize passport (authentication manager)
      process.require("app/server/passport.js");

      callback();
    });
  },

  // Load openveo sub plugins under node_modules directory
  function(callback){

    pluginLoader.loadPlugins(path.join(process.cwd() ,"node_modules"), function(error, plugins){

      // An error occurred when loading plugins
      // The server must not be launched, exit process
      if(error){
        logger.error(error && error.message);
        process.exit(0);
      }
      else{
        var publicDirectories = [];
        applicationStorage.setPlugins(plugins);

        plugins.forEach(function(loadedPlugin){

          // If plugin has a public directory, load it as a
          // static server
          if(loadedPlugin.publicDirectory)
            publicDirectories.push(loadedPlugin.publicDirectory);

          // Mount plugin public router to the plugin front end mount path
          if(loadedPlugin.router && loadedPlugin.mountPath){

            // Found routes for the plugin
            // Apply routes to the public router
            if(loadedPlugin.routes)
              applyRoutes(loadedPlugin.routes, loadedPlugin.router);

            // Mount public router to the express application
            app.use(loadedPlugin.mountPath, loadedPlugin.router);
          }

          // Mount the admin router to the plugin back end mount path
          if(loadedPlugin.adminRouter && loadedPlugin.mountPath){

            // Found admin routes for the plugin
            // Apply routes to the admin router
            if(loadedPlugin.adminRoutes)
              applyRoutes(loadedPlugin.adminRoutes, loadedPlugin.adminRouter);

            // Mount admin router to the express application
            app.use("/admin" + loadedPlugin.mountPath, loadedPlugin.adminRouter);
          }

          // Found back end menu configuration for the plugin
          if(loadedPlugin.menu)
            menu = menu.concat(loadedPlugin.menu);

          // Found a list of folders containing views for the plugin
          if(loadedPlugin.viewsFolders)
            viewsFolders = viewsFolders.concat(loadedPlugin.viewsFolders);

          logger.info("Plugin " + loadedPlugin.name + " successfully loaded");

        });

        // Set main public directory to be served first as the static server
        app.use(express.static("public", staticServerOptions));

        // Set plugins public directories as additionnal static servers
        publicDirectories.forEach(function(publicDirectory){
          app.use(express.static(publicDirectory, staticServerOptions));
        });

        // Set views folders for template engine
        app.set("views", viewsFolders);

        applicationStorage.setMenu(menu);

      }

      callback();
    });

  },

  // Handle default actions and errors
  function(callback){

    // Handle default action
    app.all("/admin/*", DefaultController.defaultAction);

    // Handle not found files
    app.all("*", DefaultController.notFoundAction);

    // Handle server errors
    app.use(function(error, request, response, next){
      logger.error(error && error.message);
      response.status(500).send();
    });

    // Start server
    server = app.listen(serverConf.port, function(){
      logger.info("Server listening at http://%s:%s", server.address().address, server.address().port);
    });

    callback();
  }
]);

/**
 * Applies a list of routes to a router.
 * @param Array routes The list of routes to apply
 * @param Object router An express router to attach the routes to
 */
function applyRoutes(routes, router){
  if(routes && routes.length && router){
    routes.forEach(function(route){
      logger.debug("Route loaded", {"route" : route.method + " " + route.path});
      router[route.method](route.path, route.action);
    });
  }
}<commit_msg>Correct bug on logger<commit_after>"use strict"

// Module dependencies
var consolidate = require("consolidate");
var mustache = require("mustache");
var express = require("express");
var session = require("express-session");
var passport = require("passport");
var cookieParser = require("cookie-parser");
var bodyParser = require("body-parser");
var winston = require("winston");
var path = require("path");
var async = require("async");
var openVeoAPI = require("openveo-api");
var applicationStorage = openVeoAPI.applicationStorage;

// Set module root directory and define a custom require function
process.root = __dirname;
process.require = function(filePath){
  return require(path.normalize(process.root + "/" + filePath));
};

// Initialize logger
process.require("app/server/logger.js");

// Module files
var pluginLoader = process.require("app/server/loaders/pluginLoader.js");
var routeLoader = process.require("app/server/loaders/routeLoader");
var DefaultController = process.require("app/server/controllers/DefaultController.js");

// Configuration files
var serverConf = process.require("config/serverConf.json");
var databaseConf = process.require("config/databaseConf.json");
var conf = process.require("conf.json");

var server;

// Retrieve initialized logger
var logger = winston.loggers.get("openveo");

// Retrieve back office menu and views folders from configuration
var menu = conf["backOffice"]["menu"];
var viewsFolders = conf["viewsFolders"];

// Create express application and main routers
// One router for the font end "/"
// One router for the back end "/admin"
var app = express();
var router = express.Router();
var adminRouter = express.Router();

// Remove x-powered-by http header
app.set("x-powered-by", false);

// Set mustache as the template engine
app.engine("html", consolidate.mustache);
app.set("view engine", "html");

// Common options for all static servers
// delivering static files
var staticServerOptions = {
  extensions: ["htm", "html"],
  maxAge: "1d",
  setHeaders: function(response, path, stat){
    response.set("x-timestamp", Date.now());
  }
};

// Load all middlewares which need to operate
// on each request
// The cookieParser and session middlewares are required
// by passport
app.use(cookieParser());
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.use(session({ secret: serverConf["sessionSecret"], saveUninitialized: true, resave: true }));
app.use(passport.initialize());
app.use(passport.session());

// Log each request method, path and headers
app.use(function(request, response, next){
  logger.info({method : request.method, path : request.url, headers : request.headers});
  next();
});

// Load and apply main routes from configuration to
// public and back end routers
applyRoutes(routeLoader.decodeRoutes(__dirname, conf["routes"]["public"]), router);
applyRoutes(routeLoader.decodeRoutes(__dirname, conf["routes"]["admin"]), adminRouter);

// Mount public and back end routers
app.use("/admin", adminRouter);
app.use("/", router);

async.series([

  // Establish a connection to the database
  function(callback){

    // Get a Database instance
    var db = openVeoAPI.Database.getDatabase(databaseConf);

    // Establish connection to the database
    db.connect(function(error){
      if(error)
        process.exit(0);

      applicationStorage.setDatabase(db);

      // Initialize passport (authentication manager)
      process.require("app/server/passport.js");

      callback();
    });
  },

  // Load openveo sub plugins under node_modules directory
  function(callback){

    pluginLoader.loadPlugins(path.join(process.cwd() ,"node_modules"), function(error, plugins){

      // An error occurred when loading plugins
      // The server must not be launched, exit process
      if(error){
        logger.error(error && error.message);
        process.exit(0);
      }
      else{
        var publicDirectories = [];
        applicationStorage.setPlugins(plugins);

        plugins.forEach(function(loadedPlugin){

          // If plugin has a public directory, load it as a
          // static server
          if(loadedPlugin.publicDirectory)
            publicDirectories.push(loadedPlugin.publicDirectory);

          // Mount plugin public router to the plugin front end mount path
          if(loadedPlugin.router && loadedPlugin.mountPath){

            // Found routes for the plugin
            // Apply routes to the public router
            if(loadedPlugin.routes)
              applyRoutes(loadedPlugin.routes, loadedPlugin.router);

            // Mount public router to the express application
            app.use(loadedPlugin.mountPath, loadedPlugin.router);
          }

          // Mount the admin router to the plugin back end mount path
          if(loadedPlugin.adminRouter && loadedPlugin.mountPath){

            // Found admin routes for the plugin
            // Apply routes to the admin router
            if(loadedPlugin.adminRoutes)
              applyRoutes(loadedPlugin.adminRoutes, loadedPlugin.adminRouter);

            // Mount admin router to the express application
            app.use("/admin" + loadedPlugin.mountPath, loadedPlugin.adminRouter);
          }

          // Found back end menu configuration for the plugin
          if(loadedPlugin.menu)
            menu = menu.concat(loadedPlugin.menu);

          // Found a list of folders containing views for the plugin
          if(loadedPlugin.viewsFolders)
            viewsFolders = viewsFolders.concat(loadedPlugin.viewsFolders);

          logger.info("Plugin " + loadedPlugin.name + " successfully loaded");

        });

        // Set main public directory to be served first as the static server
        app.use(express.static("public", staticServerOptions));

        // Set plugins public directories as additionnal static servers
        publicDirectories.forEach(function(publicDirectory){
          app.use(express.static(publicDirectory, staticServerOptions));
        });

        // Set views folders for template engine
        app.set("views", viewsFolders);

        applicationStorage.setMenu(menu);

      }

      callback();
    });

  },

  // Handle default actions and errors
  function(callback){

    // Handle default action
    app.all("/admin/*", DefaultController.defaultAction);

    // Handle not found files
    app.all("*", DefaultController.notFoundAction);

    // Handle server errors
    app.use(function(error, request, response, next){
      logger.error(error && error.message);
      response.status(500).send();
    });

    // Start server
    server = app.listen(serverConf.port, function(){
      logger.info("Server listening at http://%s:%s", server.address().address, server.address().port);
    });

    callback();
  }
]);

/**
 * Applies a list of routes to a router.
 * @param Array routes The list of routes to apply
 * @param Object router An express router to attach the routes to
 */
function applyRoutes(routes, router){
  if(routes && routes.length && router){
    routes.forEach(function(route){
      logger.debug("Route loaded", {"route" : route.method + " " + route.path});
      router[route.method](route.path, route.action);
    });
  }
}<|endoftext|>


<commit_before>// Represents a BAM index.
// Code is based heavily on bam.js, part of the Dalliance Genome Explorer,  (c) Thomas Down 2006-2001.

import BinaryParser from "../binary.js";
import igvxhr from "../igvxhr.js";
import Zlib from "../vendor/zlib_and_gzip.js";
import {buildOptions} from "../util/igvUtils.js";

const BAI_MAGIC = 21578050;
const TABIX_MAGIC = 21578324;
const MAX_HEADER_SIZE = 100000000;   // IF the header is larger than this we can't read it !
const MAX_GZIP_BLOCK_SIZE = (1 << 16);

/**
 * @param indexURL
 * @param config
 * @param tabix
 *
 * @returns a Promised for the bam or tabix index.  The fulfill function takes the index as an argument.
 */
async function loadBamIndex(indexURL, config, tabix, genome) {

    let arrayBuffer = await igvxhr.loadArrayBuffer(indexURL, buildOptions(config))

    var indices = [],
        magic, nbin, nintv, nref, parser,
        blockMin = Number.MAX_VALUE,
        blockMax = 0,
        binIndex, linearIndex, binNumber, cs, ce, b, i, ref, sequenceIndexMap;

    if (!arrayBuffer) {
        fullfill(null);
        return;
    }

    if (tabix) {
        var inflate = new Zlib.Gunzip(new Uint8Array(arrayBuffer));
        arrayBuffer = inflate.decompress().buffer;
    }

    parser = new BinaryParser(new DataView(arrayBuffer));

    magic = parser.getInt();

    if (magic === BAI_MAGIC || (tabix && magic === TABIX_MAGIC)) {

        nref = parser.getInt();

        if (tabix) {
            // Tabix header parameters aren't used, but they must be read to advance the pointer
            var format = parser.getInt();
            var col_seq = parser.getInt();
            var col_beg = parser.getInt();
            var col_end = parser.getInt();
            var meta = parser.getInt();
            var skip = parser.getInt();
            var l_nm = parser.getInt();

            sequenceIndexMap = {};
            for (i = 0; i < nref; i++) {
                var seq_name = parser.getString();

                // Translate to "official" chr name.
                if (genome) {
                    seq_name = genome.getChromosomeName(seq_name);
                }

                sequenceIndexMap[seq_name] = i;
            }
        }

        for (ref = 0; ref < nref; ref++) {

            binIndex = {};
            linearIndex = [];

            nbin = parser.getInt();

            for (b = 0; b < nbin; b++) {

                binNumber = parser.getInt();

                if (binNumber === 37450) {
                    // This is a psuedo bin, not used but we have to consume the bytes
                    nchnk = parser.getInt(); // # of chunks for this bin
                    cs = parser.getVPointer();   // unmapped beg
                    ce = parser.getVPointer();   // unmapped end
                    var n_maped = parser.getLong();
                    var nUnmapped = parser.getLong();

                } else {

                    binIndex[binNumber] = [];
                    var nchnk = parser.getInt(); // # of chunks for this bin

                    for (i = 0; i < nchnk; i++) {
                        cs = parser.getVPointer();    //chunk_beg
                        ce = parser.getVPointer();    //chunk_end
                        if (cs && ce) {
                            if (cs.block < blockMin) {
                                blockMin = cs.block;    // Block containing first alignment
                            }
                            if (ce.block > blockMax) {
                                blockMax = ce.block;
                            }
                            binIndex[binNumber].push([cs, ce]);
                        }
                    }
                }
            }

            nintv = parser.getInt();
            for (i = 0; i < nintv; i++) {
                cs = parser.getVPointer();
                linearIndex.push(cs);   // Might be null
            }

            if (nbin > 0) {
                indices[ref] = {
                    binIndex: binIndex,
                    linearIndex: linearIndex
                }
            }
        }

    } else {
        throw new Error(indexURL + " is not a " + (tabix ? "tabix" : "bai") + " file");
    }

    return new BamIndex(indices, blockMin, blockMax, sequenceIndexMap, tabix);

}

const BamIndex = function (indices, blockMin, blockMax, sequenceIndexMap, tabix) {
    this.firstAlignmentBlock = blockMin;
    this.lastAlignmentBlock = blockMax;
    this.indices = indices;
    this.sequenceIndexMap = sequenceIndexMap;
    this.tabix = tabix;

};

/**
 * Fetch blocks for a particular genomic range.  This method is public so it can be unit-tested.
 *
 * @param refId  the sequence dictionary index of the chromosome
 * @param min  genomic start position
 * @param max  genomic end position
 * @param return an array of {minv: {filePointer, offset}, {maxv: {filePointer, offset}}
 */
BamIndex.prototype.blocksForRange = function (refId, min, max) {

    var bam = this,
        ba = bam.indices[refId],
        overlappingBins,
        chunks,
        nintv,
        lowest,
        minLin,
        maxLin,
        vp,
        i;

    if (!ba) {
        return [];
    } else {

        overlappingBins = reg2bins(min, max);        // List of bin #s that overlap min, max
        chunks = [];

        // Find chunks in overlapping bins.  Leaf bins (< 4681) are not pruned
        overlappingBins.forEach(function (bin) {
            if (ba.binIndex[bin]) {
                var binChunks = ba.binIndex[bin],
                    nchnk = binChunks.length;
                for (var c = 0; c < nchnk; ++c) {
                    var cs = binChunks[c][0];
                    var ce = binChunks[c][1];
                    chunks.push({minv: cs, maxv: ce, bin: bin});
                }
            }
        });

        // Use the linear index to find minimum file position of chunks that could contain alignments in the region
        nintv = ba.linearIndex.length;
        lowest = null;
        minLin = Math.min(min >> 14, nintv - 1);
        maxLin = Math.min(max >> 14, nintv - 1);
        for (i = minLin; i <= maxLin; ++i) {
            vp = ba.linearIndex[i];
            if (vp) {
                // todo -- I think, but am not sure, that the values in the linear index have to be in increasing order.  So the first non-null should be minimum
                if (!lowest || vp.isLessThan(lowest)) {
                    lowest = vp;
                }
            }
        }

        return optimizeChunks(chunks, lowest);
    }

};

function optimizeChunks(chunks, lowest) {

    var mergedChunks = [],
        lastChunk = null;

    if (chunks.length === 0) return chunks;

    chunks.sort(function (c0, c1) {
        var dif = c0.minv.block - c1.minv.block;
        if (dif != 0) {
            return dif;
        } else {
            return c0.minv.offset - c1.minv.offset;
        }
    });

    chunks.forEach(function (chunk) {

        if (!lowest || chunk.maxv.isGreaterThan(lowest)) {
            if (lastChunk === null) {
                mergedChunks.push(chunk);
                lastChunk = chunk;
            } else {
                if ((chunk.minv.block - lastChunk.maxv.block) < 65000) { // Merge chunks that are withing 65k of each other
                    if (chunk.maxv.isGreaterThan(lastChunk.maxv)) {
                        lastChunk.maxv = chunk.maxv;
                    }
                } else {
                    mergedChunks.push(chunk);
                    lastChunk = chunk;
                }
            }
        }
    });

    return mergedChunks;
}

/**
 * Calculate the list of bins that overlap with region [beg, end]
 *
 */
function reg2bins(beg, end) {
    var i = 0, k, list = [];
    if (end >= 1 << 29) end = 1 << 29;
    --end;
    list.push(0);
    for (k = 1 + (beg >> 26); k <= 1 + (end >> 26); ++k) list.push(k);
    for (k = 9 + (beg >> 23); k <= 9 + (end >> 23); ++k) list.push(k);
    for (k = 73 + (beg >> 20); k <= 73 + (end >> 20); ++k) list.push(k);
    for (k = 585 + (beg >> 17); k <= 585 + (end >> 17); ++k) list.push(k);
    for (k = 4681 + (beg >> 14); k <= 4681 + (end >> 14); ++k) list.push(k);
    return list;
}

export default loadBamIndex;<commit_msg>modernization<commit_after>// Represents a BAM index.
// Code is based heavily on bam.js, part of the Dalliance Genome Explorer,  (c) Thomas Down 2006-2001.

import BinaryParser from "../binary.js";
import igvxhr from "../igvxhr.js";
import Zlib from "../vendor/zlib_and_gzip.js";
import {buildOptions} from "../util/igvUtils.js";

const BAI_MAGIC = 21578050;
const TABIX_MAGIC = 21578324;
const MAX_HEADER_SIZE = 100000000;   // IF the header is larger than this we can't read it !
const MAX_GZIP_BLOCK_SIZE = (1 << 16);

/**
 * @param indexURL
 * @param config
 * @param tabix
 *
 */
async function loadBamIndex(indexURL, config, tabix, genome) {

    let arrayBuffer = await igvxhr.loadArrayBuffer(indexURL, buildOptions(config))

    const indices = []
    let blockMin = Number.MAX_VALUE,
        blockMax = 0

    if (!arrayBuffer) {
        return;
    }

    if (tabix) {
        const inflate = new Zlib.Gunzip(new Uint8Array(arrayBuffer))
        arrayBuffer = inflate.decompress().buffer;
    }

    const parser = new BinaryParser(new DataView(arrayBuffer));

    const magic = parser.getInt();
    const sequenceIndexMap = {};
    if (magic === BAI_MAGIC || (tabix && magic === TABIX_MAGIC)) {

        const nref = parser.getInt();
        if (tabix) {
            // Tabix header parameters aren't used, but they must be read to advance the pointer
            const format = parser.getInt()
            const col_seq = parser.getInt()
            const col_beg = parser.getInt()
            const col_end = parser.getInt()
            const meta = parser.getInt()
            const skip = parser.getInt()
            const l_nm = parser.getInt()

            for (let i = 0; i < nref; i++) {
                let seq_name = parser.getString();
                // Translate to "official" chr name.
                if (genome) {
                    seq_name = genome.getChromosomeName(seq_name);
                }
                sequenceIndexMap[seq_name] = i;
            }
        }

        for (let ref = 0; ref < nref; ref++) {

            const binIndex = {};
            const linearIndex = [];
            const nbin = parser.getInt();
            for (let b = 0; b < nbin; b++) {

                const binNumber = parser.getInt();

                if (binNumber === 37450) {
                    // This is a psuedo bin, not used but we have to consume the bytes
                    const nchnk = parser.getInt(); // # of chunks for this bin
                    const cs = parser.getVPointer();   // unmapped beg
                    const ce = parser.getVPointer();   // unmapped end
                    const n_maped = parser.getLong()
                    const nUnmapped = parser.getLong()

                } else {

                    binIndex[binNumber] = [];
                    const nchnk = parser.getInt(); // # of chunks for this bin

                    for (let i = 0; i < nchnk; i++) {
                        const cs = parser.getVPointer();    //chunk_beg
                        const ce = parser.getVPointer();    //chunk_end
                        if (cs && ce) {
                            if (cs.block < blockMin) {
                                blockMin = cs.block;    // Block containing first alignment
                            }
                            if (ce.block > blockMax) {
                                blockMax = ce.block;
                            }
                            binIndex[binNumber].push([cs, ce]);
                        }
                    }
                }
            }

            const nintv = parser.getInt();
            for (let i = 0; i < nintv; i++) {
                const cs = parser.getVPointer();
                linearIndex.push(cs);   // Might be null
            }

            if (nbin > 0) {
                indices[ref] = {
                    binIndex: binIndex,
                    linearIndex: linearIndex
                }
            }
        }

    } else {
        throw new Error(indexURL + " is not a " + (tabix ? "tabix" : "bai") + " file");
    }

    return new BamIndex(indices, blockMin, blockMax, sequenceIndexMap, tabix);

}

const BamIndex = function (indices, blockMin, blockMax, sequenceIndexMap, tabix) {
    this.firstAlignmentBlock = blockMin;
    this.lastAlignmentBlock = blockMax;
    this.indices = indices;
    this.sequenceIndexMap = sequenceIndexMap;
    this.tabix = tabix;

};

/**
 * Fetch blocks for a particular genomic range.  This method is public so it can be unit-tested.
 *
 * @param refId  the sequence dictionary index of the chromosome
 * @param min  genomic start position
 * @param max  genomic end position
 * @param return an array of {minv: {filePointer, offset}, {maxv: {filePointer, offset}}
 */
BamIndex.prototype.blocksForRange = function (refId, min, max) {

    const bam = this;
    const ba = bam.indices[refId];

    if (!ba) {
        return [];
    } else {
        const overlappingBins = reg2bins(min, max);        // List of bin #s that overlap min, max
        const chunks = [];

        // Find chunks in overlapping bins.  Leaf bins (< 4681) are not pruned
        overlappingBins.forEach(function (bin) {
            if (ba.binIndex[bin]) {
                const binChunks = ba.binIndex[bin],
                    nchnk = binChunks.length
                for (let c = 0; c < nchnk; ++c) {
                    const cs = binChunks[c][0]
                    const ce = binChunks[c][1]
                    chunks.push({minv: cs, maxv: ce, bin: bin});
                }
            }
        });

        // Use the linear index to find minimum file position of chunks that could contain alignments in the region
        const nintv = ba.linearIndex.length;
        let lowest = null;
        const minLin = Math.min(min >> 14, nintv - 1);
        const maxLin = Math.min(max >> 14, nintv - 1);
        for (let i = minLin; i <= maxLin; ++i) {
            const vp = ba.linearIndex[i];
            if (vp) {
                // todo -- I think, but am not sure, that the values in the linear index have to be in increasing order.  So the first non-null should be minimum
                if (!lowest || vp.isLessThan(lowest)) {
                    lowest = vp;
                }
            }
        }

        return optimizeChunks(chunks, lowest);
    }

};

function optimizeChunks(chunks, lowest) {

    const mergedChunks = []
    let lastChunk = null

    if (chunks.length === 0) return chunks;

    chunks.sort(function (c0, c1) {
        const dif = c0.minv.block - c1.minv.block
        if (dif !== 0) {
            return dif;
        } else {
            return c0.minv.offset - c1.minv.offset;
        }
    });

    chunks.forEach(function (chunk) {

        if (!lowest || chunk.maxv.isGreaterThan(lowest)) {
            if (lastChunk === null) {
                mergedChunks.push(chunk);
                lastChunk = chunk;
            } else {
                if ((chunk.minv.block - lastChunk.maxv.block) < 65000) { // Merge chunks that are withing 65k of each other
                    if (chunk.maxv.isGreaterThan(lastChunk.maxv)) {
                        lastChunk.maxv = chunk.maxv;
                    }
                } else {
                    mergedChunks.push(chunk);
                    lastChunk = chunk;
                }
            }
        }
    });

    return mergedChunks;
}

/**
 * Calculate the list of bins that overlap with region [beg, end]
 *
 */
function reg2bins(beg, end) {
    const i = 0
    let k
    const list = []
    if (end >= 1 << 29) end = 1 << 29;
    --end;
    list.push(0);
    for (k = 1 + (beg >> 26); k <= 1 + (end >> 26); ++k) list.push(k);
    for (k = 9 + (beg >> 23); k <= 9 + (end >> 23); ++k) list.push(k);
    for (k = 73 + (beg >> 20); k <= 73 + (end >> 20); ++k) list.push(k);
    for (k = 585 + (beg >> 17); k <= 585 + (end >> 17); ++k) list.push(k);
    for (k = 4681 + (beg >> 14); k <= 4681 + (end >> 14); ++k) list.push(k);
    return list;
}

export default loadBamIndex;<|endoftext|>


<commit_before>angular
  .module('material.components.expansionPanels')
  .directive('mdExpansionPanel', expansionPanelDirective);

var ANIMATION_TIME = 180; //ms

/**
 * @ngdoc directive
 * @name mdExpansionPanel
 * @module material.components.expansionPanels
 *
 * @restrict E
 *
 * @description
 * `mdExpansionPanel` is the main container for panels
 *
 * @param {string=} md-component-id - add an id if you want to acces the panel via the `$mdExpansionPanel` service
 **/
function expansionPanelDirective() {
  var directive = {
    restrict: 'E',
    require: ['mdExpansionPanel', '?^^mdExpansionPanelGroup'],
    scope: true,
    compile: compile,
    controller: ['$scope', '$element', '$attrs', '$window', '$$rAF', '$mdConstant', '$mdUtil', '$mdComponentRegistry', '$timeout', '$q', '$animate', controller]
  };
  return directive;

  function compile(tElement, tAttrs) {
    var INVALID_PREFIX = 'Invalid HTML for md-expansion-panel: ';

    tElement.attr('tabindex', tAttrs.tabindex || '0');

    if (tElement[0].querySelector('md-expansion-panel-collapsed') === null) {
      throw Error(INVALID_PREFIX + 'Expected a child element of `md-epxansion-panel-collapsed`');
    }
    if (tElement[0].querySelector('md-expansion-panel-expanded') === null) {
      throw Error(INVALID_PREFIX + 'Expected a child element of `md-epxansion-panel-expanded`');
    }

    return function postLink(scope, element, attrs, ctrls) {
      var epxansionPanelCtrl = ctrls[0];
      var epxansionPanelGroupCtrl = ctrls[1];

      if (epxansionPanelGroupCtrl) {
        epxansionPanelCtrl.epxansionPanelGroupCtrl = epxansionPanelGroupCtrl;
        epxansionPanelGroupCtrl.addPanel(epxansionPanelCtrl.componentId, {
          expand: epxansionPanelCtrl.expand,
          collapse: epxansionPanelCtrl.collapse,
          remove: epxansionPanelCtrl.remove,
          onRemove: epxansionPanelCtrl.onRemove,
          destroy: epxansionPanelCtrl.destroy,
        });
      }
    };
  }

  function controller($scope, $element, $attrs, $window, $$rAF, $mdConstant, $mdUtil, $mdComponentRegistry, $timeout, $q, $animate) {
    /* jshint validthis: true */
    var vm = this;

    var collapsedCtrl;
    var expandedCtrl;
    var headerCtrl;
    var footerCtrl;
    var deregister;
    var scrollContainer;
    var stickyContainer;
    var topKiller;
    var resizeKiller;
    var onRemoveCallback;
    var transformParent;
    var backdrop;
    var isOpen = false;
    var isDisabled = false;
    var debouncedUpdateScroll = $$rAF.throttle(updateScroll);
    var debouncedUpdateResize = $$rAF.throttle(updateResize);

    vm.registerCollapsed = function (ctrl) { collapsedCtrl = ctrl; };
    vm.registerExpanded = function (ctrl) { expandedCtrl = ctrl; };
    vm.registerHeader = function (ctrl) { headerCtrl = ctrl; };
    vm.registerFooter = function (ctrl) { footerCtrl = ctrl; };

    vm.$element = $element;
    vm.componentId = $attrs.mdComponentId;
    vm.expand = expand;
    vm.collapse = collapse;
    vm.remove = remove;
    vm.destroy = destroy;
    vm.onRemove = onRemove;

    $attrs.$observe('disabled', function(disabled) {
      isDisabled = (typeof disabled === 'string' && disabled !== 'false') ? true : false;

      if (isDisabled === true) {
        $element.attr('tabindex', '-1');
      } else {
        $element.attr('tabindex', '0');
      }
    });

    $element
      .on('focus', function (ev) {
        $element.on('keydown', handleKeypress);
      })
      .on('blur', function (ev) {
        $element.off('keydown', handleKeypress);
      });

    function handleKeypress(ev) {
      var keyCodes = $mdConstant.KEY_CODE;
      switch (ev.keyCode) {
        case keyCodes.ENTER:
          expand();
          break;
        case keyCodes.ESCAPE:
          collapse();
          break;
      }
    }

    $scope.$panel = {
      collapse: collapse,
      expand: expand,
      remove: remove
    };

    $scope.$on('$destroy', function () {
      removeClickCatcher();

      // remove component from registry
      if (typeof deregister === 'function') {
        deregister();
        deregister = undefined;
      }
      killEvents();
    });

    if ($attrs.mdComponentId) {
      deregister = $mdComponentRegistry.register({
        expand: expand,
        collapse: collapse,
        remove: remove,
        onRemove: onRemove,
        addClickCatcher: addClickCatcher,
        removeClickCatcher: removeClickCatcher,
        componentId: $attrs.mdComponentId
      }, $attrs.mdComponentId);
    }

    function expand() {
      if (isOpen === true || isDisabled === true) { return; }
      isOpen = true;

      var deferred = $q.defer();

      if (vm.epxansionPanelGroupCtrl) {
        vm.epxansionPanelGroupCtrl.expandPanel(vm.componentId);
      }

      $element.removeClass('md-close');
      $element.addClass('md-open');

      initEvents();
      collapsedCtrl.hide();
      expandedCtrl.show();

      if (headerCtrl) { headerCtrl.show(); }
      if (footerCtrl) { footerCtrl.show(); }

      $timeout(function () {
        deferred.resolve();
      }, ANIMATION_TIME);
      return deferred.promise;
    }

    function collapse() {
      if (isOpen === false) { return; }
      isOpen = false;

      var deferred = $q.defer();

      $element.addClass('md-close');
      $element.removeClass('md-open');

      killEvents();
      collapsedCtrl.show();
      expandedCtrl.hide();

      if (headerCtrl) { headerCtrl.hide(); }
      if (footerCtrl) { footerCtrl.hide(); }

      $timeout(function () {
        deferred.resolve();
      }, ANIMATION_TIME);
      return deferred.promise;
    }

    function remove(noAnimation) {
      var deferred = $q.defer();

      if (vm.epxansionPanelGroupCtrl) {
        vm.epxansionPanelGroupCtrl.removePanel(vm.componentId);
      }

      if (typeof deregister === 'function') {
        deregister();
        deregister = undefined;
      }

      if (noAnimation === true || isOpen === false) {
        $scope.$destroy();
        $element.remove();
        deferred.resolve();
        callbackRemove();
      } else {
        collapse();
        $timeout(function () {
          $scope.$destroy();
          $element.remove();
          deferred.resolve();
          callbackRemove();
        }, ANIMATION_TIME);
      }

      return deferred.promise;
    }

    function onRemove(callback) {
      onRemoveCallback = callback;
    }

    function callbackRemove() {
      if (typeof onRemoveCallback === 'function') {
        onRemoveCallback();
        onRemoveCallback = undefined;
      }
    }

    function destroy() {
      $scope.$destroy();
    }

    function initEvents() {
      if ((!footerCtrl || footerCtrl.noSticky === true) && (!headerCtrl || headerCtrl.noSticky === true)) {
        return;
      }

      // watch for panel position changes
      topKiller = $scope.$watch(function () { return $element[0].offsetTop; }, debouncedUpdateScroll, true);

      // watch for panel position changes
      resizeKiller = $scope.$watch(function () { return $element[0].offsetWidth; }, debouncedUpdateResize, true);

      // listen to md-content scroll events id we are nested in one
      scrollContainer = $mdUtil.getNearestContentElement($element);
      if (scrollContainer.nodeName === 'MD-CONTENT') {
        transformParent = getTransformParent(scrollContainer);
        angular.element(scrollContainer).on('scroll', debouncedUpdateScroll);
      } else {
        transformParent = undefined;
      }

      // listen to expanded content scroll if height is set
      if (expandedCtrl.setHeight === true) {
        expandedCtrl.$element.on('scroll', debouncedUpdateScroll);
      }

      // listen to window scroll events
      angular.element($window)
        .on('scroll', debouncedUpdateScroll)
        .on('resize', debouncedUpdateScroll)
        .on('resize', debouncedUpdateResize);
    }

    function killEvents() {
      if (typeof topKiller === 'function') {
        topKiller();
        topKiller = undefined;
      }

      if (typeof resizeKiller === 'function') {
        resizeKiller();
        resizeKiller = undefined;
      }

      if (scrollContainer && scrollContainer.nodeName === 'MD-CONTENT') {
        angular.element(scrollContainer).off('scroll', debouncedUpdateScroll);
      }

      if (expandedCtrl.setHeight === true) {
        expandedCtrl.$element.off('scroll', debouncedUpdateScroll);
      }

      angular.element($window)
        .off('scroll', debouncedUpdateScroll)
        .off('resize', debouncedUpdateScroll)
        .off('resize', debouncedUpdateResize);
    }

    function getTransformParent(el) {
      var parent = el.parentNode;

      while (parent) {
        if ($mdUtil.hasComputedStyle(angular.element(parent), 'transform')) {
          return parent;
        }
        parent = parent.parentNode;
      }

      return undefined;
    }

    function updateScroll(e) {
      var top;
      var bottom;
      var bounds;
      if (expandedCtrl.setHeight === true) {
        bounds = expandedCtrl.$element[0].getBoundingClientRect();
      } else {
        bounds = scrollContainer.getBoundingClientRect();
      }
      var transformTop = transformParent ? transformParent.getBoundingClientRect().top : 0;

      // we never want the header going post the top of the page. to prevent this don't allow top to go below 0
      top = Math.max(bounds.top, 0);
      bottom = top + bounds.height;

      if (footerCtrl && footerCtrl.noSticky === false) { footerCtrl.onScroll(top, bottom, transformTop); }
      if (headerCtrl && headerCtrl.noSticky === false) { headerCtrl.onScroll(top, bottom, transformTop); }
    }

    function updateResize() {
      var value = $element[0].offsetWidth;
      if (footerCtrl && footerCtrl.noSticky === false) { footerCtrl.onResize(value); }
      if (headerCtrl && headerCtrl.noSticky === false) { headerCtrl.onResize(value); }
    }

    function addClickCatcher(clickCallback) {
      backdrop = $mdUtil.createBackdrop($scope);
      backdrop[0].tabIndex = -1;

      if (typeof clickCallback === 'function') {
        backdrop.on('click', clickCallback);
      }

      $animate.enter(backdrop, $element.parent(), null, {duration: 0});
      $element.css('z-index', 60);
    }

    function removeClickCatcher() {
      if (backdrop) {
        backdrop.remove();
        backdrop.off('click');
        backdrop = undefined;
        $element.css('z-index', '');
      }
    }
  }
}
<commit_msg>add component id if one is not provided. This will allow for interaction with group and injectable $panel<commit_after>angular
  .module('material.components.expansionPanels')
  .directive('mdExpansionPanel', expansionPanelDirective);

var ANIMATION_TIME = 180; //ms

/**
 * @ngdoc directive
 * @name mdExpansionPanel
 * @module material.components.expansionPanels
 *
 * @restrict E
 *
 * @description
 * `mdExpansionPanel` is the main container for panels
 *
 * @param {string=} md-component-id - add an id if you want to acces the panel via the `$mdExpansionPanel` service
 **/
function expansionPanelDirective() {
  var directive = {
    restrict: 'E',
    require: ['mdExpansionPanel', '?^^mdExpansionPanelGroup'],
    scope: true,
    compile: compile,
    controller: ['$scope', '$element', '$attrs', '$window', '$$rAF', '$mdConstant', '$mdUtil', '$mdComponentRegistry', '$timeout', '$q', '$animate', controller]
  };
  return directive;

  function compile(tElement, tAttrs) {
    var INVALID_PREFIX = 'Invalid HTML for md-expansion-panel: ';

    tElement.attr('tabindex', tAttrs.tabindex || '0');

    if (tElement[0].querySelector('md-expansion-panel-collapsed') === null) {
      throw Error(INVALID_PREFIX + 'Expected a child element of `md-epxansion-panel-collapsed`');
    }
    if (tElement[0].querySelector('md-expansion-panel-expanded') === null) {
      throw Error(INVALID_PREFIX + 'Expected a child element of `md-epxansion-panel-expanded`');
    }

    return function postLink(scope, element, attrs, ctrls) {
      var epxansionPanelCtrl = ctrls[0];
      var epxansionPanelGroupCtrl = ctrls[1];

      if (epxansionPanelGroupCtrl) {
        epxansionPanelCtrl.epxansionPanelGroupCtrl = epxansionPanelGroupCtrl;
        epxansionPanelGroupCtrl.addPanel(epxansionPanelCtrl.componentId, {
          expand: epxansionPanelCtrl.expand,
          collapse: epxansionPanelCtrl.collapse,
          remove: epxansionPanelCtrl.remove,
          onRemove: epxansionPanelCtrl.onRemove,
          destroy: epxansionPanelCtrl.destroy,
        });
      }
    };
  }

  function controller($scope, $element, $attrs, $window, $$rAF, $mdConstant, $mdUtil, $mdComponentRegistry, $timeout, $q, $animate) {
    /* jshint validthis: true */
    var vm = this;

    var collapsedCtrl;
    var expandedCtrl;
    var headerCtrl;
    var footerCtrl;
    var deregister;
    var scrollContainer;
    var stickyContainer;
    var topKiller;
    var resizeKiller;
    var onRemoveCallback;
    var transformParent;
    var backdrop;
    var isOpen = false;
    var isDisabled = false;
    var debouncedUpdateScroll = $$rAF.throttle(updateScroll);
    var debouncedUpdateResize = $$rAF.throttle(updateResize);

    vm.registerCollapsed = function (ctrl) { collapsedCtrl = ctrl; };
    vm.registerExpanded = function (ctrl) { expandedCtrl = ctrl; };
    vm.registerHeader = function (ctrl) { headerCtrl = ctrl; };
    vm.registerFooter = function (ctrl) { footerCtrl = ctrl; };

    if ($attrs.mdComponentId === undefined) {
      $attrs.$set('mdComponentId', '_expansion_panel_id_' + $mdUtil.nextUid());
    }

    vm.$element = $element;
    vm.componentId = $attrs.mdComponentId;
    vm.expand = expand;
    vm.collapse = collapse;
    vm.remove = remove;
    vm.destroy = destroy;
    vm.onRemove = onRemove;

    $attrs.$observe('disabled', function(disabled) {
      isDisabled = (typeof disabled === 'string' && disabled !== 'false') ? true : false;

      if (isDisabled === true) {
        $element.attr('tabindex', '-1');
      } else {
        $element.attr('tabindex', '0');
      }
    });

    $element
      .on('focus', function (ev) {
        $element.on('keydown', handleKeypress);
      })
      .on('blur', function (ev) {
        $element.off('keydown', handleKeypress);
      });

    function handleKeypress(ev) {
      var keyCodes = $mdConstant.KEY_CODE;
      switch (ev.keyCode) {
        case keyCodes.ENTER:
          expand();
          break;
        case keyCodes.ESCAPE:
          collapse();
          break;
      }
    }

    $scope.$panel = {
      collapse: collapse,
      expand: expand,
      remove: remove
    };

    $scope.$on('$destroy', function () {
      removeClickCatcher();

      // remove component from registry
      if (typeof deregister === 'function') {
        deregister();
        deregister = undefined;
      }
      killEvents();
    });

    if ($attrs.mdComponentId) {
      deregister = $mdComponentRegistry.register({
        expand: expand,
        collapse: collapse,
        remove: remove,
        onRemove: onRemove,
        addClickCatcher: addClickCatcher,
        removeClickCatcher: removeClickCatcher,
        componentId: $attrs.mdComponentId
      }, $attrs.mdComponentId);
    }

    function expand() {
      if (isOpen === true || isDisabled === true) { return; }
      isOpen = true;

      var deferred = $q.defer();

      if (vm.epxansionPanelGroupCtrl) {
        vm.epxansionPanelGroupCtrl.expandPanel(vm.componentId);
      }

      $element.removeClass('md-close');
      $element.addClass('md-open');

      initEvents();
      collapsedCtrl.hide();
      expandedCtrl.show();

      if (headerCtrl) { headerCtrl.show(); }
      if (footerCtrl) { footerCtrl.show(); }

      $timeout(function () {
        deferred.resolve();
      }, ANIMATION_TIME);
      return deferred.promise;
    }

    function collapse() {
      if (isOpen === false) { return; }
      isOpen = false;

      var deferred = $q.defer();

      $element.addClass('md-close');
      $element.removeClass('md-open');

      killEvents();
      collapsedCtrl.show();
      expandedCtrl.hide();

      if (headerCtrl) { headerCtrl.hide(); }
      if (footerCtrl) { footerCtrl.hide(); }

      $timeout(function () {
        deferred.resolve();
      }, ANIMATION_TIME);
      return deferred.promise;
    }

    function remove(noAnimation) {
      var deferred = $q.defer();

      if (vm.epxansionPanelGroupCtrl) {
        vm.epxansionPanelGroupCtrl.removePanel(vm.componentId);
      }

      if (typeof deregister === 'function') {
        deregister();
        deregister = undefined;
      }

      if (noAnimation === true || isOpen === false) {
        $scope.$destroy();
        $element.remove();
        deferred.resolve();
        callbackRemove();
      } else {
        collapse();
        $timeout(function () {
          $scope.$destroy();
          $element.remove();
          deferred.resolve();
          callbackRemove();
        }, ANIMATION_TIME);
      }

      return deferred.promise;
    }

    function onRemove(callback) {
      onRemoveCallback = callback;
    }

    function callbackRemove() {
      if (typeof onRemoveCallback === 'function') {
        onRemoveCallback();
        onRemoveCallback = undefined;
      }
    }

    function destroy() {
      $scope.$destroy();
    }

    function initEvents() {
      if ((!footerCtrl || footerCtrl.noSticky === true) && (!headerCtrl || headerCtrl.noSticky === true)) {
        return;
      }

      // watch for panel position changes
      topKiller = $scope.$watch(function () { return $element[0].offsetTop; }, debouncedUpdateScroll, true);

      // watch for panel position changes
      resizeKiller = $scope.$watch(function () { return $element[0].offsetWidth; }, debouncedUpdateResize, true);

      // listen to md-content scroll events id we are nested in one
      scrollContainer = $mdUtil.getNearestContentElement($element);
      if (scrollContainer.nodeName === 'MD-CONTENT') {
        transformParent = getTransformParent(scrollContainer);
        angular.element(scrollContainer).on('scroll', debouncedUpdateScroll);
      } else {
        transformParent = undefined;
      }

      // listen to expanded content scroll if height is set
      if (expandedCtrl.setHeight === true) {
        expandedCtrl.$element.on('scroll', debouncedUpdateScroll);
      }

      // listen to window scroll events
      angular.element($window)
        .on('scroll', debouncedUpdateScroll)
        .on('resize', debouncedUpdateScroll)
        .on('resize', debouncedUpdateResize);
    }

    function killEvents() {
      if (typeof topKiller === 'function') {
        topKiller();
        topKiller = undefined;
      }

      if (typeof resizeKiller === 'function') {
        resizeKiller();
        resizeKiller = undefined;
      }

      if (scrollContainer && scrollContainer.nodeName === 'MD-CONTENT') {
        angular.element(scrollContainer).off('scroll', debouncedUpdateScroll);
      }

      if (expandedCtrl.setHeight === true) {
        expandedCtrl.$element.off('scroll', debouncedUpdateScroll);
      }

      angular.element($window)
        .off('scroll', debouncedUpdateScroll)
        .off('resize', debouncedUpdateScroll)
        .off('resize', debouncedUpdateResize);
    }

    function getTransformParent(el) {
      var parent = el.parentNode;

      while (parent) {
        if ($mdUtil.hasComputedStyle(angular.element(parent), 'transform')) {
          return parent;
        }
        parent = parent.parentNode;
      }

      return undefined;
    }

    function updateScroll(e) {
      var top;
      var bottom;
      var bounds;
      if (expandedCtrl.setHeight === true) {
        bounds = expandedCtrl.$element[0].getBoundingClientRect();
      } else {
        bounds = scrollContainer.getBoundingClientRect();
      }
      var transformTop = transformParent ? transformParent.getBoundingClientRect().top : 0;

      // we never want the header going post the top of the page. to prevent this don't allow top to go below 0
      top = Math.max(bounds.top, 0);
      bottom = top + bounds.height;

      if (footerCtrl && footerCtrl.noSticky === false) { footerCtrl.onScroll(top, bottom, transformTop); }
      if (headerCtrl && headerCtrl.noSticky === false) { headerCtrl.onScroll(top, bottom, transformTop); }
    }

    function updateResize() {
      var value = $element[0].offsetWidth;
      if (footerCtrl && footerCtrl.noSticky === false) { footerCtrl.onResize(value); }
      if (headerCtrl && headerCtrl.noSticky === false) { headerCtrl.onResize(value); }
    }

    function addClickCatcher(clickCallback) {
      backdrop = $mdUtil.createBackdrop($scope);
      backdrop[0].tabIndex = -1;

      if (typeof clickCallback === 'function') {
        backdrop.on('click', clickCallback);
      }

      $animate.enter(backdrop, $element.parent(), null, {duration: 0});
      $element.css('z-index', 60);
    }

    function removeClickCatcher() {
      if (backdrop) {
        backdrop.remove();
        backdrop.off('click');
        backdrop = undefined;
        $element.css('z-index', '');
      }
    }
  }
}
<|endoftext|>


<commit_before>'use strict';

var invalid = [];
var test;

test = {
	'code': [
		'// VARIABLES //',
		'',
		'var arr = new Int32Array( [1,2,3] );'
	].join( '\n' ),
	'errors': [
		{
			'message': 'typed array constructor is invoked without requiring it',
			'type': 'NewExpression'
		}
	]
};
invalid.push( test );

test = {
	'code': [
		'// MAIN //',
		'',
		'function dice() {',
		'  return new Int32Array( [1,2,3,4,5,6] );',
		'}'
	].join( '\n' ),
	'errors': [
		{
			'message': 'typed array constructor is invoked without requiring it',
			'type': 'NewExpression'
		}
	]
};
invalid.push( test );

test = {
	'code': [
		'var push = require( \'@stdlib/utils/push\' )',
		'',
		'var arr = [ 1.0, 2.0, 3.0, 4.0, 5.0 ];',
		'',
		'arr = push( arr, 6.0, 7.0 );',
		'// returns [ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0 ]',
		'',
		'arr = new Float64Array( [ 1.0, 2.0, 3.0, 4.0, 5.0 ] );',
		'// returns <Float64Array>[ 1.0, 2.0, 3.0, 4.0, 5.0 ]'
	].join( '\n' ),
	'errors': [
		{
			'message': 'typed array constructor is invoked without requiring it',
			'type': 'NewExpression'
		}
	]
};
invalid.push( test );

test = {
	'code': [
		'/**',
		'* Multiply matrices x and y.',
		'*',
		'* @private',
		'* @param {Float64Array} x - first input matrix',
		'* @param {Float64Array} y - second input matrix',
		'* @returns {Float64Array} matrix product',
		'*/',
		'function mmult( x, y ) {',
		'	var i;',
		'	var j;',
		'	var k;',
		'	var s;',
		'	var z;',
		'',
		'	z = new Float64Array( m * m );',
		'	for ( i = 0; i < m; i++) {',
		'		for ( j = 0; j < m; j++ ) {',
		'			s = 0;',
		'			for ( k = 0; k < m; k++ ) {',
		'				s += x[ (i*m) + k ] * y[ (k*m) + j ];',
		'				z[ (i*m) + j ] = s;',
		'			}',
		'		}',
		'	}',
		'	return z;',
		'} // end FUNCTION mmult()'
	].join( '\n' ),
	'errors': [
		{
			'message': 'typed array constructor is invoked without requiring it',
			'type': 'NewExpression'
		}
	]
};
invalid.push( test );

// EXPORTS //

module.exports = invalid;
<commit_msg>Fix test fixtures<commit_after>'use strict';

var invalid = [];
var test;

test = {
	'code': [
		'// VARIABLES //',
		'',
		'var arr = new Int32Array( [1,2,3] );'
	].join( '\n' ),
	'errors': [
		{
			'message': 'typed array constructor is invoked without loading it beforehand via require()',
			'type': 'NewExpression'
		}
	]
};
invalid.push( test );

test = {
	'code': [
		'// MAIN //',
		'',
		'function dice() {',
		'  return new Int32Array( [1,2,3,4,5,6] );',
		'}'
	].join( '\n' ),
	'errors': [
		{
			'message': 'typed array constructor is invoked without loading it beforehand via require()',
			'type': 'NewExpression'
		}
	]
};
invalid.push( test );

test = {
	'code': [
		'var push = require( \'@stdlib/utils/push\' )',
		'',
		'var arr = [ 1.0, 2.0, 3.0, 4.0, 5.0 ];',
		'',
		'arr = push( arr, 6.0, 7.0 );',
		'// returns [ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0 ]',
		'',
		'arr = new Float64Array( [ 1.0, 2.0, 3.0, 4.0, 5.0 ] );',
		'// returns <Float64Array>[ 1.0, 2.0, 3.0, 4.0, 5.0 ]'
	].join( '\n' ),
	'errors': [
		{
			'message': 'typed array constructor is invoked without loading it beforehand via require()',
			'type': 'NewExpression'
		}
	]
};
invalid.push( test );

test = {
	'code': [
		'/**',
		'* Multiply matrices x and y.',
		'*',
		'* @private',
		'* @param {Float64Array} x - first input matrix',
		'* @param {Float64Array} y - second input matrix',
		'* @returns {Float64Array} matrix product',
		'*/',
		'function mmult( x, y ) {',
		'	var i;',
		'	var j;',
		'	var k;',
		'	var s;',
		'	var z;',
		'',
		'	z = new Float64Array( m * m );',
		'	for ( i = 0; i < m; i++) {',
		'		for ( j = 0; j < m; j++ ) {',
		'			s = 0;',
		'			for ( k = 0; k < m; k++ ) {',
		'				s += x[ (i*m) + k ] * y[ (k*m) + j ];',
		'				z[ (i*m) + j ] = s;',
		'			}',
		'		}',
		'	}',
		'	return z;',
		'} // end FUNCTION mmult()'
	].join( '\n' ),
	'errors': [
		{
			'message': 'typed array constructor is invoked without loading it beforehand via require()',
			'type': 'NewExpression'
		}
	]
};
invalid.push( test );

// EXPORTS //

module.exports = invalid;
<|endoftext|>


<commit_before>YUI.add("model-list-tweets", function(Y) {
    "use strict";

    var falco      = Y.namespace("Falco"),
        models     = Y.namespace("Falco.Models"),
        extensions = Y.namespace("Extensions"),

        Tweets;

    Tweets = Y.Base.create("tweets", Y.LazyModelList, [
        extensions.ModelListMore,
    ], {
        model : models.Tweet,

        sync : function(action, options, done) {
            var args = {};

            if(this.size()) {
                args.since_id = this.item(0).id_str;
            }

            args = Y.merge(
                { count : 200 },
                this.get("config") || {},
                args
            );

            this.loading = true;

            falco.twitter.get(this.get("api"), args, function(err, resp) {
                if(err) {
                    return done(err);
                }

                done(err, resp);
            });
        },

        // Ensure that tweets use string IDs instead of Numbers
        parse : function(response) {
            var tweets = response,
                path   = this.get("selector");

            if(path) {
                tweets = Y.Object.getValue(response, path);

                if(!tweets) {
                    this.fire("error", {
                        error    : "Invalid selector path",
                        response : response,
                        src      : "parse"
                    });

                    return null;
                }
            }

            return tweets.map(function(tweet) {
                tweet.id = tweet.id_str;

                return tweet;
            });
        },

        // Compare using parsed Date values
        comparator : function(tweet) {
            return Date.parse(tweet.created_at);
        },

        // Sort in reverse chronological order
        _sort : function(a, b) {
            return this.comparator(b) - this.comparator(a);
        }
    }, {
        ATTRS : {
            api      : null,
            config   : null,
            selector : null
        }
    });

    models.Tweets = Tweets;

}, "@VERSION@", {
    requires : [
        // YUI
        "base-build",
        "lazy-model-list",

        // Extensions
        "extension-model-list-more",

        // Models
        "model-tweet"
    ]
});
<commit_msg>Only use since_id if this is a more request<commit_after>YUI.add("model-list-tweets", function(Y) {
    "use strict";

    var falco      = Y.namespace("Falco"),
        models     = Y.namespace("Falco.Models"),
        extensions = Y.namespace("Extensions"),

        Tweets;

    Tweets = Y.Base.create("tweets", Y.LazyModelList, [
        extensions.ModelListMore,
    ], {
        model : models.Tweet,

        sync : function(action, options, done) {
            var args = {};

            if(action === "more" && this.size()) {
                args.since_id = this.item(0).id_str;
            }

            args = Y.merge(
                { count : 200 },
                this.get("config") || {},
                args
            );

            falco.twitter.get(this.get("api"), args, function(err, resp) {
                if(err) {
                    return done(err);
                }

                done(err, resp);
            });
        },

        // Ensure that tweets use string IDs instead of Numbers
        parse : function(response) {
            var tweets = response,
                path   = this.get("selector");

            if(path) {
                tweets = Y.Object.getValue(response, path);

                if(!tweets) {
                    this.fire("error", {
                        error    : "Invalid selector path",
                        response : response,
                        src      : "parse"
                    });

                    return null;
                }
            }

            return tweets.map(function(tweet) {
                tweet.id = tweet.id_str;

                return tweet;
            });
        },

        // Compare using parsed Date values
        comparator : function(tweet) {
            return Date.parse(tweet.created_at);
        },

        // Sort in reverse chronological order
        _sort : function(a, b) {
            return this.comparator(b) - this.comparator(a);
        }
    }, {
        ATTRS : {
            api      : null,
            config   : null,
            selector : null
        }
    });

    models.Tweets = Tweets;

}, "@VERSION@", {
    requires : [
        // YUI
        "base-build",
        "lazy-model-list",

        // Extensions
        "extension-model-list-more",

        // Models
        "model-tweet"
    ]
});
<|endoftext|>


<commit_before><commit_msg>working on server<commit_after>'use strict';

const pg = require('pg');
const fs = require('fs');
const express = require('express');
const bodyParser = require('body-parser');
const requestProxy = require('express-request-proxy');
const PORT = process.env.PORT || 3000;
const app = express();

const conString = ''; //TODO when database is set-up
const client = new pg.Client(conString);
client.connect();
client.on('error', err => console.log(err));

app.use(bodyParser.json());
app.use(express.static("./public"));

app.listen(PORT, () => console.log(`Server started on port ${PORT}!`));
<|endoftext|>


<commit_before>'use strict';
var apiService = require('../apiService').getInstance();

function CategoryMenuResponse() {
    this._categories = apiService.getSellingProductCategories();
    console.info("CATEGORIES", this._categories);
}

CategoryMenuResponse.prototype = {
    getResponse: function () {
        var response = {
            attachment: {
                type: "template",
                payload: {
                    template_type: "button",
                    text: "Pick a category?",
                    buttons: []
                }
            }
        };

        if (this._categories !== undefined) {
            this._categories.forEach(function (category) {
                console.info("category", category);
                var newButton = {
                    type: "postback",
                    title: category.name,
                    payload: {}
                };

                newButton.payload = "category#" + category._id;
                response.attachment.payload.buttons.push(newButton);
            });
        }
        console.info("RESPONSE", response);
        return JSON.stringify(response);
    }
};

/**
 * @returns {CategoryMenuResponse}
 */
module.exports.getInstance = function () {
    return new CategoryMenuResponse();
};
<commit_msg>make request sync<commit_after>'use strict';
var apiService = require('../apiService').getInstance();

function CategoryMenuResponse() {
    this._categories = apiService.getSellingProductCategories();
}

CategoryMenuResponse.prototype = {
    getResponse: function () {
        var response = {
            attachment: {
                type: "template",
                payload: {
                    template_type: "button",
                    text: "Pick a category?",
                    buttons: []
                }
            }
        };
        console.log("Category 1st response", response);
        if (this._categories !== undefined) {
            this._categories.forEach(function (category) {
                console.info("category", category);
                var newButton = {
                    type: "postback",
                    title: category.name,
                    payload: {}
                };

                newButton.payload = "category#" + category._id;
                response.attachment.payload.buttons.push(newButton);
            });
        }
        console.info("RESPONSE", response);
        return JSON.stringify(response);
    }
};

/**
 * @returns {CategoryMenuResponse}
 */
module.exports.getInstance = function () {
    return new CategoryMenuResponse();
};
<|endoftext|>


<commit_before>var express = require('express');

var port = process.env.PORT || '3000';
var host = process.env.HOST || '0.0.0.0';

var app = express();

app.use(express.static('src'))
  .set('views', 'views')
  .set('view engine', 'ejs');

app.get('/dashboard/:user/:festival', function (req, res) {
  res.render('pages/dashboard', {data: [50, 250], festival: 'Rollende keuken', totalUsage: '34%', url: req.url, appliances: [{name: 'Koffie'}, {name: 'Frituur'}]});
});

app.get('/login', function (req, res) {
  res.render('pages/login');
});

app.get('/', function (req, res) {
  res.render('pages/home', {user: 'foodChef', festivals: [{name: 'rollende keukens', date: '10 mei', image: 'http://www.recensiequeens.nl/wp-content/uploads/2014/05/rollende-keukens.jpg'}]});
});

app.get('/register', function (req, res) {
  res.render('pages/register');
});

app.get('/add/appliances', function (req, res) {
  res.render('pages/appliances');
});

app.listen(port, host, function () {
  console.log('Server running', host, ':', port);
});
<commit_msg>:wrench: Fix appliance link<commit_after>var express = require('express');

var port = process.env.PORT || '3000';
var host = process.env.HOST || '0.0.0.0';

var app = express();

app.use(express.static('src'))
  .set('views', 'views')
  .set('view engine', 'ejs');

app.get('/dashboard/:user/:festival', function (req, res) {
  res.render('pages/dashboard', {data: [50, 250], festival: 'Rollende keuken', totalUsage: '34%', url: req.url, appliances: [{name: 'Koffie'}, {name: 'Frituur'}]});
});

app.get('/login', function (req, res) {
  res.render('pages/login');
});

app.get('/', function (req, res) {
  res.render('pages/home', {user: 'foodChef', festivals: [{name: 'rollende keukens', date: '10 mei', image: 'http://www.recensiequeens.nl/wp-content/uploads/2014/05/rollende-keukens.jpg'}]});
});

app.get('/register', function (req, res) {
  res.render('pages/register');
});

app.get('/appliances/:user/:festival', function (req, res) {
  res.render('pages/appliances');
});

app.listen(port, host, function () {
  console.log('Server running', host, ':', port);
});
<|endoftext|>