<commit_before>import models from '../models/index';
import helper from '../helpers/helper';

const createDocument = (request, response) => {
  helper.verifyDocumentParams(request)
  .then((result) => {
    const verifiedParams = result.mapped();
    const noErrors = result.isEmpty();
    if (!noErrors) {
      response.status(412).json({ message: verifiedParams });
      return;
    }
    models.Document.create({
      title: request.body.title,
      content: request.body.content,
      access: request.body.access,
      userId: request.decoded.data.userId,
    })
    .then((document) => {
      response.status(201).json({
        message: 'New Document created successfully',
        title: document.title,
        ownerId: request.decoded.data.userId,
      });
    })
    .catch((error) => {
      response.status(409).json({
        message: 'An error occured creating new document',
        data: error,
      });
    });
  });
};

const getAllDocument = (request, response) => {
  const paginate = helper.paginate(request);
  const isAdmin = RegExp('admin', 'gi').test(request.decoded.data.roleType);
  let query;
  if (isAdmin) {
    query = { order: [['createdAt', 'DESC']],
      offset: paginate[0],
      limit: paginate[1],
    };
  } else {
    query = { order: [['createdAt', 'DESC']],
      offset: paginate[0],
      limit: paginate[1],
      where: {
        $or: [
          { userId: request.decoded.data.userId },
          { access: 'public' }
        ]
      }
    };
  }
  models.Document.findAndCountAll(query)
  .then((document) => {
    response.status(200).json({
      documentCount: document.count,
      message: 'successful',
      document: document.rows,
    });
  })
  .catch((error) => {
    response.status(400).json({
      message: 'An error occured retrieving documents',
      data: error,
    });
  });
};

const updateDocument = (request, response) => {
  const documentId = request.params.id;
  const isAdmin = RegExp('admin', 'gi').test(request.decoded.data.roleType);
  let query;
  if (isAdmin) {
    query = { where: { id: documentId }, returning: true, plain: true, };
  } else {
    query = { where: { id: documentId, userId: request.decoded.data.userId },
      returning: true,
      plain: true, };
  }
  models.Document.update(request.body, query)
  .then((document) => {
    if (!document.length === 0) {
      response.status(200).json({
        message: 'successful',
        document
      });
    } else {
      response.status(401).json({
        message: 'You do not have access to view/update the available documents',
        document
      });
    }
  })
  .catch((error) => {
    response.status(400).json({
      message: `An error occured updating document, confirm you
      have access right to update this document.`,
      error,
    });
  });
};

module.exports = {
  createDocument,
  getAllDocument,
  updateDocument,
};
<commit_msg>feat (feature):Delete Document<commit_after>import models from '../models/index';
import helper from '../helpers/helper';

const createDocument = (request, response) => {
  helper.verifyDocumentParams(request)
  .then((result) => {
    const verifiedParams = result.mapped();
    const noErrors = result.isEmpty();
    if (!noErrors) {
      response.status(412).json({ message: verifiedParams });
      return;
    }
    models.Document.create({
      title: request.body.title,
      content: request.body.content,
      access: request.body.access,
      userId: request.decoded.data.userId,
    })
    .then((document) => {
      response.status(201).json({
        message: 'New Document created successfully',
        title: document.title,
        ownerId: request.decoded.data.userId,
      });
    })
    .catch((error) => {
      response.status(409).json({
        message: 'An error occured creating new document',
        data: error,
      });
    });
  });
};

const getAllDocument = (request, response) => {
  const paginate = helper.paginate(request);
  const isAdmin = RegExp('admin', 'gi').test(request.decoded.data.roleType);
  let query;
  if (isAdmin) {
    query = { order: [['createdAt', 'DESC']],
      offset: paginate[0],
      limit: paginate[1],
    };
  } else {
    query = { order: [['createdAt', 'DESC']],
      offset: paginate[0],
      limit: paginate[1],
      where: {
        $or: [
          { userId: request.decoded.data.userId },
          { access: 'public' }
        ]
      }
    };
  }
  models.Document.findAndCountAll(query)
  .then((document) => {
    response.status(200).json({
      documentCount: document.count,
      message: 'successful',
      document: document.rows,
    });
  })
  .catch((error) => {
    response.status(400).json({
      message: 'An error occured retrieving documents',
      data: error,
    });
  });
};

const updateDocument = (request, response) => {
  const documentId = request.params.id;
  const isAdmin = RegExp('admin', 'gi').test(request.decoded.data.roleType);
  let query;
  if (isAdmin) {
    query = { where: { id: documentId }, returning: true, plain: true, };
  } else {
    query = { where: { id: documentId, userId: request.decoded.data.userId },
      returning: true,
      plain: true, };
  }
  models.Document.update(request.body, query)
  .then((document) => {
    if (!document.length === 0) {
      response.status(200).json({
        message: 'successful',
        document
      });
    } else {
      response.status(401).json({
        message: 'You do not have access to view/update the available documents',
        document
      });
    }
  })
  .catch((error) => {
    response.status(400).json({
      message: `An error occured updating document, confirm you
      have access right to update this document.`,
      error,
    });
  });
};

const deleteDocument = (request, response) => {
  const documentId = request.params.id;
  const isAdmin = RegExp('admin', 'gi').test(request.decoded.data.roleType);
  let query;
  if (isAdmin) {
    query = { where: { id: documentId } };
  } else {
    query = { where: { id: documentId, userId: request.decoded.data.userId } };
  }
  models.Document.destroy(query)
  .then((document) => {
    if (!document.length === 0) {
      response.status(200).json({
        message: 'successful',
        document
      });
    } else {
      response.status(401).json({
        message: 'You do not have access to view/delete the available documents',
        document
      });
    }
  })
  .catch((error) => {
    response.status(400).json({
      message: 'An error occured! Document could not be deleted',
      error,
    });
  });
};

module.exports = {
  createDocument,
  getAllDocument,
  updateDocument,
  deleteDocument,
};
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

var docgen = require('react-docgen');
var docgenHelpers = require('./docgenHelpers');
var fs = require('fs');
var path = require('path');
var slugify = require('../core/slugify');
var jsDocs = require('../jsdocs/jsdocs.js');

function getNameFromPath(filepath) {
  var ext = null;
  while (ext = path.extname(filepath)) {
    filepath = path.basename(filepath, ext);
  }
  if (filepath === 'LayoutPropTypes') {
    return 'Flexbox';
  }
  return filepath;
}

function getExample(componentName) {
  var path = '../Examples/UIExplorer/' + componentName + 'Example.js';
  if (!fs.existsSync(path)) {
    return;
  }
  return {
    path: path,
    content: fs.readFileSync(path).toString(),
  };
}

function componentsToMarkdown(type, json, filepath, i, styles) {
  var componentName = getNameFromPath(filepath);

  var docFilePath = '../docs/' + componentName + '.md';
  if (fs.existsSync(docFilePath)) {
    json.fullDescription = fs.readFileSync(docFilePath).toString();
  }
  json.type = type;
  json.filepath = filepath.replace(/^\.\.\//, '');
  json.componentName = componentName;
  if (styles) {
    json.styles = styles;
  }
  json.example = getExample(componentName);

  var res = [
    '---',
    'id: ' + slugify(componentName),
    'title: ' + componentName,
    'layout: autodocs',
    'category: ' + (type === 'style' ? 'Polyfills' : type + 's'),
    'permalink: docs/' + slugify(componentName) + '.html',
    'next: ' + (all[i + 1] ?
      slugify(getNameFromPath(all[i + 1])) :
      'network'),
    '---',
    JSON.stringify(json, null, 2),
  ].filter(function(line) { return line; }).join('\n');
  return res;
}

var n;

function renderComponent(filepath) {
  var json = docgen.parse(
    fs.readFileSync(filepath),
    docgenHelpers.findExportedOrFirst,
    docgen.defaultHandlers.concat(docgenHelpers.stylePropTypeHandler)
  );
  return componentsToMarkdown('component', json, filepath, n++, styleDocs);
}

function renderAPI(type) {
  return function(filepath) {
    var json;
    try {
      json = jsDocs(fs.readFileSync(filepath).toString());
    } catch(e) {
      console.error('Cannot parse file', filepath);
      json = {};
    }
    return componentsToMarkdown(type, json, filepath, n++);
  };
}

function renderStyle(filepath) {
  var json = docgen.parse(
    fs.readFileSync(filepath),
    docgenHelpers.findExportedObject,
    [docgen.handlers.propTypeHandler]
  );
  return componentsToMarkdown('style', json, filepath, n++);
}

var components = [
  '../Libraries/Components/ActivityIndicatorIOS/ActivityIndicatorIOS.ios.js',
  '../Libraries/Components/DatePicker/DatePickerIOS.ios.js',
  '../Libraries/Image/Image.ios.js',
  '../Libraries/CustomComponents/ListView/ListView.js',
  '../Libraries/Components/MapView/MapView.js',
  '../Libraries/CustomComponents/Navigator/Navigator.js',
  '../Libraries/Components/Navigation/NavigatorIOS.ios.js',
  '../Libraries/Picker/PickerIOS.ios.js',
  '../Libraries/Components/ScrollView/ScrollView.js',
  '../Libraries/Components/SliderIOS/SliderIOS.js',
  '../Libraries/Components/SwitchIOS/SwitchIOS.ios.js',
  '../Libraries/Components/TabBarIOS/TabBarIOS.ios.js',
  '../Libraries/Text/Text.js',
  '../Libraries/Components/TextInput/TextInput.js',
  '../Libraries/Components/Touchable/TouchableHighlight.js',
  '../Libraries/Components/Touchable/TouchableOpacity.js',
  '../Libraries/Components/Touchable/TouchableWithoutFeedback.js',
  '../Libraries/Components/View/View.js',
  '../Libraries/Components/WebView/WebView.ios.js',
];

var apis = [
  '../Libraries/Utilities/AlertIOS.js',
  '../Libraries/Animation/Animation.js',
  '../Libraries/AppRegistry/AppRegistry.js',
  '../Libraries/AppStateIOS/AppStateIOS.ios.js',
  '../Libraries/Storage/AsyncStorage.ios.js',
  '../Libraries/CameraRoll/CameraRoll.js',
  '../Libraries/Interaction/InteractionManager.js',
  '../Libraries/Animation/LayoutAnimation.js',
  '../Libraries/LinkingIOS/LinkingIOS.js',
  '../Libraries/Network/NetInfo.js',
  '../Libraries/vendor/react/browser/eventPlugins/PanResponder.js',
  '../Libraries/Utilities/PixelRatio.js',
  '../Libraries/PushNotificationIOS/PushNotificationIOS.js',
  '../Libraries/Components/StatusBar/StatusBarIOS.ios.js',
  '../Libraries/StyleSheet/StyleSheet.js',
  '../Libraries/Vibration/VibrationIOS.ios.js',
];

var styles = [
  '../Libraries/StyleSheet/LayoutPropTypes.js',
  '../Libraries/Components/View/ViewStylePropTypes.js',
  '../Libraries/Text/TextStylePropTypes.js',
  '../Libraries/Image/ImageStylePropTypes.js',
];

var polyfills = [
  '../Libraries/GeoLocation/Geolocation.ios.js',
];

var all = components
  .concat(apis)
  .concat(styles.slice(0, 1))
  .concat(polyfills);

var styleDocs = styles.slice(1).reduce(function(docs, filepath) {
  docs[path.basename(filepath).replace(path.extname(filepath), '')] =
    docgen.parse(
      fs.readFileSync(filepath),
      docgenHelpers.findExportedObject,
      [docgen.handlers.propTypeHandler]
    );
  return docs;
}, {});

module.exports = function() {
  n = 0;
  return [].concat(
    components.map(renderComponent),
    apis.map(renderAPI('api')),
    styles.slice(0, 1).map(renderStyle),
    polyfills.map(renderAPI('Polyfill'))
  );
};
<commit_msg>fix ../<commit_after>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

var docgen = require('react-docgen');
var docgenHelpers = require('./docgenHelpers');
var fs = require('fs');
var path = require('path');
var slugify = require('../core/slugify');
var jsDocs = require('../jsdocs/jsdocs.js');

function getNameFromPath(filepath) {
  var ext = null;
  while (ext = path.extname(filepath)) {
    filepath = path.basename(filepath, ext);
  }
  if (filepath === 'LayoutPropTypes') {
    return 'Flexbox';
  }
  return filepath;
}

function getExample(componentName) {
  var path = '../Examples/UIExplorer/' + componentName + 'Example.js';
  if (!fs.existsSync(path)) {
    return;
  }
  return {
    path: path.replace(/^\.\.\//, ''),
    content: fs.readFileSync(path).toString(),
  };
}

function componentsToMarkdown(type, json, filepath, i, styles) {
  var componentName = getNameFromPath(filepath);

  var docFilePath = '../docs/' + componentName + '.md';
  if (fs.existsSync(docFilePath)) {
    json.fullDescription = fs.readFileSync(docFilePath).toString();
  }
  json.type = type;
  json.filepath = filepath.replace(/^\.\.\//, '');
  json.componentName = componentName;
  if (styles) {
    json.styles = styles;
  }
  json.example = getExample(componentName);

  var res = [
    '---',
    'id: ' + slugify(componentName),
    'title: ' + componentName,
    'layout: autodocs',
    'category: ' + (type === 'style' ? 'Polyfills' : type + 's'),
    'permalink: docs/' + slugify(componentName) + '.html',
    'next: ' + (all[i + 1] ?
      slugify(getNameFromPath(all[i + 1])) :
      'network'),
    '---',
    JSON.stringify(json, null, 2),
  ].filter(function(line) { return line; }).join('\n');
  return res;
}

var n;

function renderComponent(filepath) {
  var json = docgen.parse(
    fs.readFileSync(filepath),
    docgenHelpers.findExportedOrFirst,
    docgen.defaultHandlers.concat(docgenHelpers.stylePropTypeHandler)
  );
  return componentsToMarkdown('component', json, filepath, n++, styleDocs);
}

function renderAPI(type) {
  return function(filepath) {
    var json;
    try {
      json = jsDocs(fs.readFileSync(filepath).toString());
    } catch(e) {
      console.error('Cannot parse file', filepath);
      json = {};
    }
    return componentsToMarkdown(type, json, filepath, n++);
  };
}

function renderStyle(filepath) {
  var json = docgen.parse(
    fs.readFileSync(filepath),
    docgenHelpers.findExportedObject,
    [docgen.handlers.propTypeHandler]
  );
  return componentsToMarkdown('style', json, filepath, n++);
}

var components = [
  '../Libraries/Components/ActivityIndicatorIOS/ActivityIndicatorIOS.ios.js',
  '../Libraries/Components/DatePicker/DatePickerIOS.ios.js',
  '../Libraries/Image/Image.ios.js',
  '../Libraries/CustomComponents/ListView/ListView.js',
  '../Libraries/Components/MapView/MapView.js',
  '../Libraries/CustomComponents/Navigator/Navigator.js',
  '../Libraries/Components/Navigation/NavigatorIOS.ios.js',
  '../Libraries/Picker/PickerIOS.ios.js',
  '../Libraries/Components/ScrollView/ScrollView.js',
  '../Libraries/Components/SliderIOS/SliderIOS.js',
  '../Libraries/Components/SwitchIOS/SwitchIOS.ios.js',
  '../Libraries/Components/TabBarIOS/TabBarIOS.ios.js',
  '../Libraries/Text/Text.js',
  '../Libraries/Components/TextInput/TextInput.js',
  '../Libraries/Components/Touchable/TouchableHighlight.js',
  '../Libraries/Components/Touchable/TouchableOpacity.js',
  '../Libraries/Components/Touchable/TouchableWithoutFeedback.js',
  '../Libraries/Components/View/View.js',
  '../Libraries/Components/WebView/WebView.ios.js',
];

var apis = [
  '../Libraries/Utilities/AlertIOS.js',
  '../Libraries/Animation/Animation.js',
  '../Libraries/AppRegistry/AppRegistry.js',
  '../Libraries/AppStateIOS/AppStateIOS.ios.js',
  '../Libraries/Storage/AsyncStorage.ios.js',
  '../Libraries/CameraRoll/CameraRoll.js',
  '../Libraries/Interaction/InteractionManager.js',
  '../Libraries/Animation/LayoutAnimation.js',
  '../Libraries/LinkingIOS/LinkingIOS.js',
  '../Libraries/Network/NetInfo.js',
  '../Libraries/vendor/react/browser/eventPlugins/PanResponder.js',
  '../Libraries/Utilities/PixelRatio.js',
  '../Libraries/PushNotificationIOS/PushNotificationIOS.js',
  '../Libraries/Components/StatusBar/StatusBarIOS.ios.js',
  '../Libraries/StyleSheet/StyleSheet.js',
  '../Libraries/Vibration/VibrationIOS.ios.js',
];

var styles = [
  '../Libraries/StyleSheet/LayoutPropTypes.js',
  '../Libraries/Components/View/ViewStylePropTypes.js',
  '../Libraries/Text/TextStylePropTypes.js',
  '../Libraries/Image/ImageStylePropTypes.js',
];

var polyfills = [
  '../Libraries/GeoLocation/Geolocation.ios.js',
];

var all = components
  .concat(apis)
  .concat(styles.slice(0, 1))
  .concat(polyfills);

var styleDocs = styles.slice(1).reduce(function(docs, filepath) {
  docs[path.basename(filepath).replace(path.extname(filepath), '')] =
    docgen.parse(
      fs.readFileSync(filepath),
      docgenHelpers.findExportedObject,
      [docgen.handlers.propTypeHandler]
    );
  return docs;
}, {});

module.exports = function() {
  n = 0;
  return [].concat(
    components.map(renderComponent),
    apis.map(renderAPI('api')),
    styles.slice(0, 1).map(renderStyle),
    polyfills.map(renderAPI('Polyfill'))
  );
};
<|endoftext|>


<commit_before>/* @flow */

import Path from 'path'
import Pundle from 'pundle'
import PundleDev from 'pundle-dev'
import send from 'send'
import { DIRECTORY_NAME } from './config'
import type CLI from './cli'
import type State from './state'
import type { Motion$Config } from './types'

export const X = '✗'
export const TICK = '✓'

export function fillConfig(config: Motion$Config) {
  if (typeof config.dataDirectory !== 'string') {
    config.dataDirectory = Path.join(config.rootDirectory, DIRECTORY_NAME)
  }
}

export function getLocalModulePath(name: string): string {
  return Path.dirname(require.resolve(`${name}/package.json`))
}

// From: goo.gl/fZA6BF
export function getRandomNumber(min: number, max: number): number {
  return Math.floor(Math.random() * (max - min)) + min
}

export async function getPundleInstance(
  state: State,
  config: Motion$Config,
  cli: CLI,
  terminal: boolean,
  development: boolean,
  errorCallback: Function
): Object {
  const pundleConfig = {
    hmr: development,
    entry: [require.resolve('babel-regenerator-runtime'), config.rootDirectory],
    rootDirectory: config.rootDirectory,
    resolve: {
      root: config.rootDirectory
    },
    replaceVariables: {
      'process.env.NODE_ENV': `"${development ? 'development' : 'production'}"`
    }
  }

  const userPlugins = (state.config.babel && state.config.babel.plugins || [])
    .map(plugin => require.resolve(Path.join(config.rootDirectory, '.motion', plugin)))

  const plugins = [
    [require.resolve('pundle-npm-installer'), {
      save: state.get().npm_save,
      rootDirectory: config.rootDirectory,
      onBeforeInstall(id, name) {
        if (terminal) {
          const message = `Installing ${name}`
          cli.addSpinner(message)
        }
      },
      onAfterInstall(id, name, error) {
        if (terminal) {
          const message = `Installing ${name}`
          cli.removeSpinner(message)
          if (error) {
            cli.log(`Install ${name} ${X}`)
            cli.log(error)
          } else {
            cli.log(`Install ${name} ${TICK}`)
          }
        } else if (error) {
          errorCallback(error)
        }
      }
    }],
    [require.resolve('babel-pundle'), {
      config: {
        presets: [require.resolve('babel-preset-motion')],
        plugins: userPlugins
      },
      ignored: /(node_modules|bower_components|\.motion)/
    }],
    require.resolve('./pundle/resolver')
  ]

  if (!development) {
    const pundle = new Pundle(pundleConfig)
    await pundle.loadPlugins(plugins)
    return pundle
  }
  const pundle = new PundleDev({
    pundle: pundleConfig,
    watcher: {
      onError(error) {
        errorCallback(error)
      }
    },
    middleware: {
      sourceMap: true,
      sourceRoot: config.dataDirectory,
      publicPath: '/',
      publicBundlePath: '/_/bundle.js'
    },
    server: {
      port: state.get().web_server_port
    }
  })
  await pundle.pundle.loadPlugins(plugins)
  pundle.server.use('*', function serveRequest(req, res, next, error = false) {
    // Ignore both bundle and it's map
    if (req.baseUrl.indexOf('/_/bundle.js') === 0) {
      next()
      return
    }
    send(req, req.baseUrl, { root: config.dataDirectory, index: 'index.html' })
      .on('error', function() {
        if (error) {
          next()
        } else {
          req.baseUrl = '/index.html'
          serveRequest(req, res, next, true)
        }
      })
      .on('directory', function() {
        next()
      })
      .pipe(res)
  })
  return pundle
}
<commit_msg>:new: Support both local and module babel plugins<commit_after>/* @flow */

import Path from 'path'
import Pundle from 'pundle'
import PundleDev from 'pundle-dev'
import send from 'send'
import { DIRECTORY_NAME } from './config'
import type CLI from './cli'
import type State from './state'
import type { Motion$Config } from './types'

export const X = '✗'
export const TICK = '✓'

export function fillConfig(config: Motion$Config) {
  if (typeof config.dataDirectory !== 'string') {
    config.dataDirectory = Path.join(config.rootDirectory, DIRECTORY_NAME)
  }
}

export function getLocalModulePath(name: string): string {
  return Path.dirname(require.resolve(`${name}/package.json`))
}

// From: goo.gl/fZA6BF
export function getRandomNumber(min: number, max: number): number {
  return Math.floor(Math.random() * (max - min)) + min
}

export async function getPundleInstance(
  state: State,
  config: Motion$Config,
  cli: CLI,
  terminal: boolean,
  development: boolean,
  errorCallback: Function
): Object {
  const pundleConfig = {
    hmr: development,
    entry: [require.resolve('babel-regenerator-runtime'), config.rootDirectory],
    rootDirectory: config.rootDirectory,
    resolve: {
      root: config.rootDirectory
    },
    replaceVariables: {
      'process.env.NODE_ENV': `"${development ? 'development' : 'production'}"`
    }
  }

  const userPlugins = (state.config.babel && state.config.babel.plugins || [])
    .map(function(plugin) {
      return plugin.substr(0, 1) === '.' ? Path.join(config.rootDirectory, plugin) : Path.join(config.rootDirectory, 'node_modules', plugin)
    })

  const plugins = [
    [require.resolve('pundle-npm-installer'), {
      save: state.get().npm_save,
      rootDirectory: config.rootDirectory,
      onBeforeInstall(id, name) {
        if (terminal) {
          const message = `Installing ${name}`
          cli.addSpinner(message)
        }
      },
      onAfterInstall(id, name, error) {
        if (terminal) {
          const message = `Installing ${name}`
          cli.removeSpinner(message)
          if (error) {
            cli.log(`Install ${name} ${X}`)
            cli.log(error)
          } else {
            cli.log(`Install ${name} ${TICK}`)
          }
        } else if (error) {
          errorCallback(error)
        }
      }
    }],
    [require.resolve('babel-pundle'), {
      config: {
        presets: [require.resolve('babel-preset-motion')],
        plugins: userPlugins
      },
      ignored: /(node_modules|bower_components|\.motion)/
    }],
    require.resolve('./pundle/resolver')
  ]

  if (!development) {
    const pundle = new Pundle(pundleConfig)
    await pundle.loadPlugins(plugins)
    return pundle
  }
  const pundle = new PundleDev({
    pundle: pundleConfig,
    watcher: {
      onError(error) {
        errorCallback(error)
      }
    },
    middleware: {
      sourceMap: true,
      sourceRoot: config.dataDirectory,
      publicPath: '/',
      publicBundlePath: '/_/bundle.js'
    },
    server: {
      port: state.get().web_server_port
    }
  })
  await pundle.pundle.loadPlugins(plugins)
  pundle.server.use('*', function serveRequest(req, res, next, error = false) {
    // Ignore both bundle and it's map
    if (req.baseUrl.indexOf('/_/bundle.js') === 0) {
      next()
      return
    }
    send(req, req.baseUrl, { root: config.dataDirectory, index: 'index.html' })
      .on('error', function() {
        if (error) {
          next()
        } else {
          req.baseUrl = '/index.html'
          serveRequest(req, res, next, true)
        }
      })
      .on('directory', function() {
        next()
      })
      .pipe(res)
  })
  return pundle
}
<|endoftext|>


<commit_before>/** @module api */
import * as auth from './auth.js';
import {
  CLOUD_RESOURCE_MANAGER_API_BASE,
  HEALTHCARE_API_BASE,
  HEALTHCARE_BETA_API_BASE,
} from './config.js';

/**
 * Fetches a url using a stored access token, signing the user in
 * if no access token exists
 * @param {string} url The url to fetch
 * @return {Promise<Response>} Fetch response object
 */
const authenticatedFetch = async (url) => {
  const accessToken = auth.getAccessToken();
  if (accessToken) {
    const response = await fetch(url, {
      headers: {
        'Authorization': `Bearer ${accessToken}`,
      },
    });

    if (!response.ok) {
      if (response.status == 401) {
        auth.signInToGoogle();
      } else {
        throw new Error(await response.text());
      }
    }

    return response;
  } else {
    auth.signInToGoogle();
  }
};

/**
 * Fetches a list of the users google cloud projects recursively
 * @param {string=} pageToken Page token to use for the request
 * @param {Array=} projects Projects fetched from a previous iteration
 * @return {Promise<Array<string>>} List of projects available to the user
 */
const fetchProjects = async (pageToken, projects) => {
  const endpoint = '/v1/projects' +
      (pageToken ? `?pageToken=${pageToken}` : '');
  const response =
    await authenticatedFetch(CLOUD_RESOURCE_MANAGER_API_BASE + endpoint);
  const data = await response.json();

  // If next page token is present in the response, fetch again and
  // pass along the current project list
  if (data.nextPageToken) {
    if (projects) {
      return fetchProjects(data.nextPageToken,
          [...projects, ...data.projects]);
    }
    return fetchProjects(data.nextPageToken, data.projects);
  }

  // Return a list of project Id's
  if (projects) {
    return [...projects, ...data.projects].map((project) => project.projectId);
  }
  return data.projects.map((project) => project.projectId);
};

/**
 * Fetches a list of the possible locations for a given project
 * @param {string} projectId Project id to search locations for
 * @return {Promise<Array<string>>} List of locations available for project
 */
const fetchLocations = async (projectId) => {
  const endpoint = `/v1beta1/projects/${projectId}/locations`;
  const response =
    await authenticatedFetch(HEALTHCARE_BETA_API_BASE + endpoint);
  const data = await response.json();

  // Return a list of location Id's
  return data.locations.map((location) => location.locationId);
};

/**
 * Fetches a list of the datasets in a project location
 * @param {string} projectId Project id
 * @param {string} location Location
 * @return {Promise<Array<string>>} List of datasets available
 */
const fetchDatasets = async (projectId, location) => {
  // TODO: Handle page tokens
  const endpoint = `/v1/projects/${projectId}/locations/${location}/datasets`;
  const response =
    await authenticatedFetch(HEALTHCARE_API_BASE + endpoint);
  const data = await response.json();

  // Return a list of datasets by only using content of string after last '/'
  return data.datasets.map((dataset) => dataset.name.split('/').slice(-1)[0]);
};

/**
 * Fetches a list of the dicomStores in a dataset
 * @param {string} projectId Project ID
 * @param {string} location Location
 * @param {string} dataset Dataset
 * @return {Promise<Array<string>>} List of dicomStores available
 */
const fetchDicomStores = async (projectId, location, dataset) => {
  // TODO: Handle page tokens
  const endpoint =
    `/v1/projects/${projectId}/locations/${location}/datasets/${dataset}` +
    `/dicomStores`;
  const response =
    await authenticatedFetch(HEALTHCARE_API_BASE + endpoint);
  const data = await response.json();

  // Return a list of dicomStores by only using content of string after last '/'
  return data.dicomStores.map((dicomStore) =>
    dicomStore.name.split('/').slice(-1)[0]);
};

/**
 * Fetches a list of studies in a dicom store
 * @param {string} projectId Project ID
 * @param {string} location Location
 * @param {string} dataset Dataset
 * @param {string} dicomStore Dicom Store
 * @return {Promise<Array<Object>>} List of studies in the dicom store
 */
const fetchStudies =
async (projectId, location, dataset, dicomStore) => {
  const endpoint =
    `/v1/projects/${projectId}/locations/${location}/datasets/${dataset}` +
    `/dicomStores/${dicomStore}/dicomWeb/studies`;
  const response =
    await authenticatedFetch(HEALTHCARE_API_BASE + endpoint);
  const data = await response.json();

  return data;
};

/**
 * Fetches a list of series in a study
 * @param {string} projectId Project ID
 * @param {string} location Location
 * @param {string} dataset Dataset
 * @param {string} dicomStore Dicom Store
 * @param {string} studyId Study UID
 * @return {Promise<Array<Object>>} List of series in the study
 */
const fetchSeries =
async (projectId, location, dataset, dicomStore, studyId) => {
  const endpoint =
    `/v1/projects/${projectId}/locations/${location}/datasets/${dataset}` +
    `/dicomStores/${dicomStore}/dicomWeb/studies/${studyId}/series`;
  const response =
    await authenticatedFetch(HEALTHCARE_API_BASE + endpoint);
  const data = await response.json();

  return data;
};

export {authenticatedFetch, fetchProjects, fetchLocations, fetchDatasets,
  fetchDicomStores, fetchStudies, fetchSeries};
<commit_msg>Added todo to add search query to fetchProjects<commit_after>/** @module api */
import * as auth from './auth.js';
import {
  CLOUD_RESOURCE_MANAGER_API_BASE,
  HEALTHCARE_API_BASE,
  HEALTHCARE_BETA_API_BASE,
} from './config.js';

/**
 * Fetches a url using a stored access token, signing the user in
 * if no access token exists
 * @param {string} url The url to fetch
 * @return {Promise<Response>} Fetch response object
 */
const authenticatedFetch = async (url) => {
  const accessToken = auth.getAccessToken();
  if (accessToken) {
    const response = await fetch(url, {
      headers: {
        'Authorization': `Bearer ${accessToken}`,
      },
    });

    if (!response.ok) {
      if (response.status == 401) {
        auth.signInToGoogle();
      } else {
        throw new Error(await response.text());
      }
    }

    return response;
  } else {
    auth.signInToGoogle();
  }
};

// TODO: Add ability to filter by search query, to
//       later implement with navigation views
/**
 * Fetches a list of the users google cloud projects recursively
 * @param {string=} pageToken Page token to use for the request
 * @param {Array=} projects Projects fetched from a previous iteration
 * @return {Promise<Array<string>>} List of projects available to the user
 */
const fetchProjects = async (pageToken, projects) => {
  const endpoint = '/v1/projects' +
      (pageToken ? `?pageToken=${pageToken}` : '');
  const response =
    await authenticatedFetch(CLOUD_RESOURCE_MANAGER_API_BASE + endpoint);
  const data = await response.json();

  // If next page token is present in the response, fetch again and
  // pass along the current project list
  if (data.nextPageToken) {
    if (projects) {
      return fetchProjects(data.nextPageToken,
          [...projects, ...data.projects]);
    }
    return fetchProjects(data.nextPageToken, data.projects);
  }

  // Return a list of project Id's
  if (projects) {
    return [...projects, ...data.projects].map((project) => project.projectId);
  }
  return data.projects.map((project) => project.projectId);
};

/**
 * Fetches a list of the possible locations for a given project
 * @param {string} projectId Project id to search locations for
 * @return {Promise<Array<string>>} List of locations available for project
 */
const fetchLocations = async (projectId) => {
  const endpoint = `/v1beta1/projects/${projectId}/locations`;
  const response =
    await authenticatedFetch(HEALTHCARE_BETA_API_BASE + endpoint);
  const data = await response.json();

  // Return a list of location Id's
  return data.locations.map((location) => location.locationId);
};

/**
 * Fetches a list of the datasets in a project location
 * @param {string} projectId Project id
 * @param {string} location Location
 * @return {Promise<Array<string>>} List of datasets available
 */
const fetchDatasets = async (projectId, location) => {
  // TODO: Handle page tokens
  const endpoint = `/v1/projects/${projectId}/locations/${location}/datasets`;
  const response =
    await authenticatedFetch(HEALTHCARE_API_BASE + endpoint);
  const data = await response.json();

  // Return a list of datasets by only using content of string after last '/'
  return data.datasets.map((dataset) => dataset.name.split('/').slice(-1)[0]);
};

/**
 * Fetches a list of the dicomStores in a dataset
 * @param {string} projectId Project ID
 * @param {string} location Location
 * @param {string} dataset Dataset
 * @return {Promise<Array<string>>} List of dicomStores available
 */
const fetchDicomStores = async (projectId, location, dataset) => {
  // TODO: Handle page tokens
  const endpoint =
    `/v1/projects/${projectId}/locations/${location}/datasets/${dataset}` +
    `/dicomStores`;
  const response =
    await authenticatedFetch(HEALTHCARE_API_BASE + endpoint);
  const data = await response.json();

  // Return a list of dicomStores by only using content of string after last '/'
  return data.dicomStores.map((dicomStore) =>
    dicomStore.name.split('/').slice(-1)[0]);
};

/**
 * Fetches a list of studies in a dicom store
 * @param {string} projectId Project ID
 * @param {string} location Location
 * @param {string} dataset Dataset
 * @param {string} dicomStore Dicom Store
 * @return {Promise<Array<Object>>} List of studies in the dicom store
 */
const fetchStudies =
async (projectId, location, dataset, dicomStore) => {
  const endpoint =
    `/v1/projects/${projectId}/locations/${location}/datasets/${dataset}` +
    `/dicomStores/${dicomStore}/dicomWeb/studies`;
  const response =
    await authenticatedFetch(HEALTHCARE_API_BASE + endpoint);
  const data = await response.json();

  return data;
};

/**
 * Fetches a list of series in a study
 * @param {string} projectId Project ID
 * @param {string} location Location
 * @param {string} dataset Dataset
 * @param {string} dicomStore Dicom Store
 * @param {string} studyId Study UID
 * @return {Promise<Array<Object>>} List of series in the study
 */
const fetchSeries =
async (projectId, location, dataset, dicomStore, studyId) => {
  const endpoint =
    `/v1/projects/${projectId}/locations/${location}/datasets/${dataset}` +
    `/dicomStores/${dicomStore}/dicomWeb/studies/${studyId}/series`;
  const response =
    await authenticatedFetch(HEALTHCARE_API_BASE + endpoint);
  const data = await response.json();

  return data;
};

export {authenticatedFetch, fetchProjects, fetchLocations, fetchDatasets,
  fetchDicomStores, fetchStudies, fetchSeries};
<|endoftext|>


<commit_before>const gulp = require('gulp');
const loadPlugins = require('gulp-load-plugins');
const del = require('del');
const glob = require('glob');
const path = require('path');
const isparta = require('isparta');
const webpack = require('webpack');
const webpackStream = require('webpack-stream');

const Instrumenter = isparta.Instrumenter;
const mochaGlobals = require('./test/setup/.globals');
const manifest = require('./package.json');

// Load all of our Gulp plugins
const $ = loadPlugins();

// Gather the library data from `package.json`
const config = manifest.babelBoilerplateOptions;
const mainFile = manifest.main;
const destinationFolder = path.dirname(mainFile);
const exportFileName = path.basename(mainFile, path.extname(mainFile));

function cleanDist(done) {
  del([destinationFolder]).then(() => done());
}

function cleanTmp(done) {
  del(['tmp']).then(() => done());
}

// Lint a set of files
function lint(files) {
  return gulp.src(files)
    .pipe($.eslint())
    .pipe($.eslint.format())
    .pipe($.eslint.failAfterError());
}

function lintSrc() {
  return lint('src/**/*.js');
}

function lintTest() {
  return lint('test/**/*.js');
}

function lintGulpfile() {
  return lint('gulpfile.js');
}

function build() {
  return gulp.src(path.join('src', config.entryFileName))
    .pipe(webpackStream({
      output: {
        filename: exportFileName + '.js',
        libraryTarget: 'umd',
        library: config.mainVarName
      },
      // Add your own externals here. For instance,
      // {
      //   jquery: true
      // }
      // would externalize the `jquery` module.
      externals: {},
      module: {
        loaders: [
          { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader' }
        ]
      },
      devtool: 'source-map'
    }))
    .pipe(gulp.dest(destinationFolder))
    .pipe($.filter(['**', '!**/*.js.map']))
    .pipe($.rename(exportFileName + '.min.js'))
    .pipe($.sourcemaps.init({ loadMaps: true }))
    .pipe($.uglify())
    .pipe($.sourcemaps.write('./'))
    .pipe(gulp.dest(destinationFolder));
}

function _mocha() {
  return gulp.src(['test/setup/node.js', 'test/unit/**/*.js'], {read: false})
    .pipe($.mocha({
      reporter: 'dot',
      globals: Object.keys(mochaGlobals.globals),
      ignoreLeaks: false
    }));
}

function _registerBabel() {
  require('babel-register');
}

function test() {
  _registerBabel();
  return _mocha();
}

function coverage(done) {
  _registerBabel();
  gulp.src(['src/**/*.js'])
    .pipe($.istanbul({
      instrumenter: Instrumenter,
      includeUntested: true
    }))
    .pipe($.istanbul.hookRequire())
    .on('finish', () => {
      return test()
        .pipe($.istanbul.writeReports())
        .on('end', done);
    });
}

const watchFiles = ['src/**/*', 'test/**/*', 'package.json', '**/.eslintrc'];

// Run the headless unit tests as you make changes.
function watch() {
  gulp.watch(watchFiles, ['test']);
}

function testBrowser() {
  // Our testing bundle is made up of our unit tests, which
  // should individually load up pieces of our application.
  // We also include the browser setup file.
  const testFiles = glob.sync('./test/unit/**/*.js');
  const allFiles = ['./test/setup/browser.js'].concat(testFiles);

  // Lets us differentiate between the first build and subsequent builds
  var firstBuild = true;

  // This empty stream might seem like a hack, but we need to specify all of our files through
  // the `entry` option of webpack. Otherwise, it ignores whatever file(s) are placed in here.
  return gulp.src('')
    .pipe($.plumber())
    .pipe(webpackStream({
      watch: true,
      entry: allFiles,
      output: {
        filename: '__spec-build.js'
      },
      // Externals isn't necessary here since these are for tests.
      module: {
        loaders: [
          // This is what allows us to author in future JavaScript
          { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader' },
          // This allows the test setup scripts to load `package.json`
          { test: /\.json$/, exclude: /node_modules/, loader: 'json-loader' }
        ]
      },
      plugins: [
        // By default, webpack does `n=>n` compilation with entry files. This concatenates
        // them into a single chunk.
        new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1 })
      ],
      devtool: 'inline-source-map'
    }, null, function() {
      if (firstBuild) {
        $.livereload.listen({port: 35729, host: 'localhost', start: true});
        var watcher = gulp.watch(watchFiles, ['lint']);
      } else {
        $.livereload.reload('./tmp/__spec-build.js');
      }
      firstBuild = false;
    }))
    .pipe(gulp.dest('./tmp'));
}

// Remove the built files
gulp.task('clean', cleanDist);

// Remove our temporary files
gulp.task('clean-tmp', cleanTmp);

// Lint our source code
gulp.task('lint-src', lintSrc);

// Lint our test code
gulp.task('lint-test', lintTest);

// Lint this file
gulp.task('lint-gulpfile', lintGulpfile);

// Lint everything
gulp.task('lint', ['lint-src', 'lint-test', 'lint-gulpfile']);

// Build two versions of the library
gulp.task('build', ['lint', 'clean'], build);

// Lint and run our tests
gulp.task('test', ['lint'], test);

// Set up coverage and run tests
gulp.task('coverage', ['lint'], coverage);

// Set up a livereload environment for our spec runner `test/runner.html`
gulp.task('test-browser', ['lint', 'clean-tmp'], testBrowser);

// Run the headless unit tests as you make changes.
gulp.task('watch', watch);

// An alias of test
gulp.task('default', ['test']);
<commit_msg>Update Gulpfile per linting rules<commit_after>const gulp = require('gulp');
const loadPlugins = require('gulp-load-plugins');
const del = require('del');
const glob = require('glob');
const path = require('path');
const isparta = require('isparta');
const webpack = require('webpack');
const webpackStream = require('webpack-stream');

const Instrumenter = isparta.Instrumenter;
const mochaGlobals = require('./test/setup/.globals');
const manifest = require('./package.json');

// Load all of our Gulp plugins
const $ = loadPlugins();

// Gather the library data from `package.json`
const config = manifest.babelBoilerplateOptions;
const mainFile = manifest.main;
const destinationFolder = path.dirname(mainFile);
const exportFileName = path.basename(mainFile, path.extname(mainFile));

function cleanDist(done) {
  del([destinationFolder]).then(() => done());
}

function cleanTmp(done) {
  del(['tmp']).then(() => done());
}

// Lint a set of files
function lint(files) {
  return gulp.src(files)
    .pipe($.eslint())
    .pipe($.eslint.format())
    .pipe($.eslint.failAfterError());
}

function lintSrc() {
  return lint('src/**/*.js');
}

function lintTest() {
  return lint('test/**/*.js');
}

function lintGulpfile() {
  return lint('gulpfile.js');
}

function build() {
  return gulp.src(path.join('src', config.entryFileName))
    .pipe(webpackStream({
      output: {
        filename: `${exportFileName}.js`,
        libraryTarget: 'umd',
        library: config.mainVarName
      },
      // Add your own externals here. For instance,
      // {
      //   jquery: true
      // }
      // would externalize the `jquery` module.
      externals: {},
      module: {
        loaders: [
          {test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader'}
        ]
      },
      devtool: 'source-map'
    }))
    .pipe(gulp.dest(destinationFolder))
    .pipe($.filter(['**', '!**/*.js.map']))
    .pipe($.rename(`${exportFileName}.min.js`))
    .pipe($.sourcemaps.init({loadMaps: true}))
    .pipe($.uglify())
    .pipe($.sourcemaps.write('./'))
    .pipe(gulp.dest(destinationFolder));
}

function _mocha() {
  return gulp.src(['test/setup/node.js', 'test/unit/**/*.js'], {read: false})
    .pipe($.mocha({
      reporter: 'dot',
      globals: Object.keys(mochaGlobals.globals),
      ignoreLeaks: false
    }));
}

function _registerBabel() {
  require('babel-register');
}

function test() {
  _registerBabel();
  return _mocha();
}

function coverage(done) {
  _registerBabel();
  gulp.src(['src/**/*.js'])
    .pipe($.istanbul({
      instrumenter: Instrumenter,
      includeUntested: true
    }))
    .pipe($.istanbul.hookRequire())
    .on('finish', () => {
      return test()
        .pipe($.istanbul.writeReports())
        .on('end', done);
    });
}

const watchFiles = ['src/**/*', 'test/**/*', 'package.json', '**/.eslintrc'];

// Run the headless unit tests as you make changes.
function watch() {
  gulp.watch(watchFiles, ['test']);
}

function testBrowser() {
  // Our testing bundle is made up of our unit tests, which
  // should individually load up pieces of our application.
  // We also include the browser setup file.
  const testFiles = glob.sync('./test/unit/**/*.js');
  const allFiles = ['./test/setup/browser.js'].concat(testFiles);

  // Lets us differentiate between the first build and subsequent builds
  var firstBuild = true;

  // This empty stream might seem like a hack, but we need to specify all of our files through
  // the `entry` option of webpack. Otherwise, it ignores whatever file(s) are placed in here.
  return gulp.src('')
    .pipe($.plumber())
    .pipe(webpackStream({
      watch: true,
      entry: allFiles,
      output: {
        filename: '__spec-build.js'
      },
      // Externals isn't necessary here since these are for tests.
      module: {
        loaders: [
          // This is what allows us to author in future JavaScript
          {test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader'},
          // This allows the test setup scripts to load `package.json`
          {test: /\.json$/, exclude: /node_modules/, loader: 'json-loader'}
        ]
      },
      plugins: [
        // By default, webpack does `n=>n` compilation with entry files. This concatenates
        // them into a single chunk.
        new webpack.optimize.LimitChunkCountPlugin({maxChunks: 1})
      ],
      devtool: 'inline-source-map'
    }, null, () => {
      if (firstBuild) {
        $.livereload.listen({port: 35729, host: 'localhost', start: true});
        gulp.watch(watchFiles, ['lint']);
      } else {
        $.livereload.reload('./tmp/__spec-build.js');
      }
      firstBuild = false;
    }))
    .pipe(gulp.dest('./tmp'));
}

// Remove the built files
gulp.task('clean', cleanDist);

// Remove our temporary files
gulp.task('clean-tmp', cleanTmp);

// Lint our source code
gulp.task('lint-src', lintSrc);

// Lint our test code
gulp.task('lint-test', lintTest);

// Lint this file
gulp.task('lint-gulpfile', lintGulpfile);

// Lint everything
gulp.task('lint', ['lint-src', 'lint-test', 'lint-gulpfile']);

// Build two versions of the library
gulp.task('build', ['lint', 'clean'], build);

// Lint and run our tests
gulp.task('test', ['lint'], test);

// Set up coverage and run tests
gulp.task('coverage', ['lint'], coverage);

// Set up a livereload environment for our spec runner `test/runner.html`
gulp.task('test-browser', ['lint', 'clean-tmp'], testBrowser);

// Run the headless unit tests as you make changes.
gulp.task('watch', watch);

// An alias of test
gulp.task('default', ['test']);
<|endoftext|>


<commit_before>var Lnf = require("lnf");
var R = require('ramda');
var Twitter = require('twitter');
var dateFormat = require('dateformat');
var fs = require('fs');
var mkdirp = require('mkdirp');
var path = require('path');

var client = new Twitter({
  consumer_key: process.env.TWITTER_CONSUMER_KEY,
  consumer_secret: process.env.TWITTER_CONSUMER_SECRET,
  access_token_key: process.env.TWITTER_ACCESS_TOKEN_KEY,
  access_token_secret: process.env.TWITTER_ACCESS_TOKEN_SECRET,
});

var MAIN_TAG = 'reactjs';
var OUTPUT_ROOT = path.join(__dirname, 'output');

var params = {
  q: '#' + MAIN_TAG,
  result_type: 'mixed',
  count: '100',
};

function writeOutputFile(now, outputFilename, outputFilenameSuffix, outputData) {
  var outputDir = path.join(OUTPUT_ROOT, dateFormat(now, 'yyyy-mm-dd'), dateFormat(now, 'hh-MM'));
  var outputJSONPath = path.join(outputDir, outputFilename);

  mkdirp(outputDir, function(error) {
    if (error) {
      console.error('Mkdirp Error:', error);
      return;
    }
    var outputJSON = JSON.stringify(outputData, null, 2);
    fs.writeFile(outputJSONPath, outputJSON, function(error) {
      if (error) {
        console.error('WriteFile Error:', error)
        return;
      }
      console.log('-- written:', outputFilename);

      var symlinkPath = path.join(OUTPUT_ROOT, outputFilenameSuffix);
      Lnf(outputJSONPath, symlinkPath, function(error) {
        if (error) {
          console.error('Symlink Error:', error);
          return;
        }

        console.log('-- created symlink:', symlinkPath);
      });
    });
  });
}

function searchFofMatchingStatusses() {
  client.get('search/tweets', params, function(error, tweets, response) {
    if (!error) {
      var statuses = tweets.statuses;
      var processedStatuses = R.map((status) => {
        return {
          _hashtags: R.reject(R.equals(MAIN_TAG), R.map(R.prop('text'), R.path(['entities', 'hashtags'], status))) || [],
          user: R.pick(['screen_name', 'profile_image_url_https'], status.user),
          text: status.text,
          created_at: status.created_at,
        };
      }, statuses);
      var selectedProcessedStatuses = R.reject(status => status._hashtags.length < 1, processedStatuses)
      var groupedStatuses = R.groupBy(R.path(['_hashtags', 0]), selectedProcessedStatuses);

      console.log('---- fetched at:', Date());
      console.log(JSON.stringify(Object.keys(groupedStatuses), null));

      var now = new Date();
      var outputFilenameSuffix = 'simple.json'
      var outputFilename = dateFormat('yyyy-mm-dd-hh-MM-ss') + '-' + outputFilenameSuffix;
      var outputData = {
        'groups': groupedStatuses,
        'filename': outputFilename,
      };

      writeOutputFile(now, outputFilename, outputFilenameSuffix, outputData);
    } else {
      console.error('Twitter API Error:', error);
    }
  });
}

searchFofMatchingStatusses();
setInterval(searchFofMatchingStatusses, 5500);
<commit_msg>Add full.json<commit_after>var Lnf = require("lnf");
var R = require('ramda');
var Twitter = require('twitter');
var dateFormat = require('dateformat');
var fs = require('fs');
var mkdirp = require('mkdirp');
var path = require('path');

var client = new Twitter({
  consumer_key: process.env.TWITTER_CONSUMER_KEY,
  consumer_secret: process.env.TWITTER_CONSUMER_SECRET,
  access_token_key: process.env.TWITTER_ACCESS_TOKEN_KEY,
  access_token_secret: process.env.TWITTER_ACCESS_TOKEN_SECRET,
});

var MAIN_TAG = 'reactjs';
var OUTPUT_ROOT = path.join(__dirname, 'output');

var params = {
  q: '#' + MAIN_TAG,
  result_type: 'mixed',
  count: '100',
};

function writeOutputFile(now, outputFilename, outputFilenameSuffix, outputData) {
  var outputDir = path.join(OUTPUT_ROOT, dateFormat(now, 'yyyy-mm-dd'), dateFormat(now, 'hh-MM'));
  var outputJSONPath = path.join(outputDir, outputFilename);

  mkdirp(outputDir, function(error) {
    if (error) {
      console.error('Mkdirp Error:', error);
      return;
    }
    var outputJSON = JSON.stringify(outputData, null, 2);
    fs.writeFile(outputJSONPath, outputJSON, function(error) {
      if (error) {
        console.error('WriteFile Error:', error)
        return;
      }
      console.log('-- written:', outputFilename);

      var symlinkPath = path.join(OUTPUT_ROOT, outputFilenameSuffix);
      Lnf(outputJSONPath, symlinkPath, function(error) {
        if (error) {
          console.error('Symlink Error:', error);
          return;
        }

        console.log('-- created symlink:', symlinkPath);
      });
    });
  });
}

function processAndWriteStatuses(statuses, statusMapCallback, now, outputFilenameSuffix) {
    var processedStatuses = R.map(statusMapCallback, statuses);
    var selectedProcessedStatuses = R.reject(status => status._hashtags.length < 1, processedStatuses)
    var groupedStatuses = R.groupBy(R.path(['_hashtags', 0]), selectedProcessedStatuses);

    var outputFilename = dateFormat(now, 'yyyy-mm-dd-hh-MM-ss') + '-' + outputFilenameSuffix;
    var outputData = {
      'groups': groupedStatuses,
      'filename': outputFilename,
    };
    writeOutputFile(now, outputFilename, outputFilenameSuffix, outputData);
    return outputData;
}

function getHastags(status) {
  return R.reject(R.equals(MAIN_TAG), R.map(R.prop('text'), R.path(['entities', 'hashtags'], status))) || [];
}

function searchFofMatchingStatusses() {
  client.get('search/tweets', params, function(error, tweets, response) {
    if (!error) {
      var statuses = tweets.statuses;
      var now = new Date();
      console.log('---- fetched at:', now);

      var outputFilenameSuffix = 'simple.json'

      processAndWriteStatuses(statuses, (status) => {
        return {
          _hashtags: getHastags(status),
          user: R.pick(['screen_name', 'profile_image_url_https'], status.user),
          text: status.text,
          created_at: status.created_at,
        };
      }, now, 'simple.json');

      var outputData = processAndWriteStatuses(statuses, (status) => {
        return R.merge(status, {
          _hashtags: getHastags(status),
        });
      }, now, 'full.json');

      console.log(JSON.stringify(Object.keys(outputData.groups), null));
    } else {
      console.error('Twitter API Error:', error);
    }
  });
}

searchFofMatchingStatusses();
setInterval(searchFofMatchingStatusses, 5500);
<|endoftext|>


<commit_before>var gulp         = require('gulp');
var browserSync  = require('browser-sync');
var cp           = require('child_process');
var harp         = require('harp');
var jshint       = require('gulp-jshint');
var uglify       = require('gulp-uglify');
var gulpSequence = require('gulp-sequence');
var imagemin     = require('gulp-imagemin');

gulp.task('serve', function () {
  harp.server('.', {
    port: 9000
  });
});

gulp.task('browser-sync', function() {
  browserSync({
    proxy: "localhost:9000"
  });
});

gulp.task('jshint', function() {
  return gulp.src('public/**/*.js')
    .pipe(jshint())
    .pipe(jshint.reporter('default'));
});

gulp.task('compile', function (done) {
  cp.exec('harp compile . www', {stdio: 'inherit'})
    .on('close', done)
});

gulp.task('watch', function () {
    gulp.watch('public/**/*.js', ['jshint']);
    gulp.watch('public/**/*.{js,jade,styl,haml,sass,scss,less,ejs,css,html}', browserSync.reload);
});

gulp.task('scripts', function() {
  return gulp.src(['./public/**/*.js', '!./public/vendor/**/src/**/*.js'], {base: './public'})
    .pipe(uglify())
    .pipe(gulp.dest('www'));
});

gulp.task('images', function() {
    return gulp.src('./public/images/*', {base: './public'})
    .pipe(imagemin({
        progressive: true,
        svgoPlugins: [{removeViewBox: false}]
    }))
    .pipe(gulp.dest('www/images'));
});

gulp.task('default', ['serve', 'browser-sync', 'watch']);
gulp.task('build', gulpSequence('jshint', 'compile', ['scripts', 'images']));
<commit_msg>watch markdown for changes<commit_after>var gulp         = require('gulp');
var browserSync  = require('browser-sync');
var cp           = require('child_process');
var harp         = require('harp');
var jshint       = require('gulp-jshint');
var uglify       = require('gulp-uglify');
var gulpSequence = require('gulp-sequence');
var imagemin     = require('gulp-imagemin');

gulp.task('serve', function () {
  harp.server('.', {
    port: 9000
  });
});

gulp.task('browser-sync', function() {
  browserSync({
    proxy: "localhost:9000"
  });
});

gulp.task('jshint', function() {
  return gulp.src('public/**/*.js')
    .pipe(jshint())
    .pipe(jshint.reporter('default'));
});

gulp.task('compile', function (done) {
  cp.exec('harp compile . www', {stdio: 'inherit'})
    .on('close', done)
});

gulp.task('watch', function () {
    gulp.watch('public/**/*.js', ['jshint']);
    gulp.watch('public/**/*.{js,jade,styl,haml,sass,scss,less,ejs,css,html,md}', browserSync.reload);
});

gulp.task('scripts', function() {
  return gulp.src(['./public/**/*.js', '!./public/vendor/**/src/**/*.js'], {base: './public'})
    .pipe(uglify())
    .pipe(gulp.dest('www'));
});

gulp.task('images', function() {
    return gulp.src('./public/images/*', {base: './public'})
    .pipe(imagemin({
        progressive: true,
        svgoPlugins: [{removeViewBox: false}]
    }))
    .pipe(gulp.dest('www/images'));
});

gulp.task('default', ['serve', 'browser-sync', 'watch']);
gulp.task('build', gulpSequence('jshint', 'compile', ['scripts', 'images']));
<|endoftext|>


<commit_before>$(document).ready(function() {
  var myDataRef = new Firebase('https://theremouse.firebaseio.com/');
	var theremins = {};
	var userId = Math.floor(Math.random() * 1000000) + 1;

	var audioCtx = new(window.AudioContext || window.webkitAudioContext)();

	$(document).mousemove(function(event) {
    var x = event.pageX - 900;
    var y = event.pageY;
		$(".x").text("X: " + x);
		$(".y").text("Y: " + y);

		myDataRef.push({xCoord: x, yCoord: y, userId: userId});

    updateView(x, y);
	});

	myDataRef.on('child_added', function(snapshot) {
    var userId = snapshot.val().userId;
  	if (!theremins[userId]) {
  		var theremin = new Theremin(audioCtx);
  		theremins[userId.toString()] = theremin;
  	}
  	var x = snapshot.val().xCoord;
  	var y = snapshot.val().yCoord;
  	theremins[userId].update(x, y);
  });

  // clean the database every 5 seconds
  // it's only used for the real time polyphonic feature
  setInterval(function() {myDataRef.remove()}, 5000)
});

function updateView(axisX, axisY) {
  var width = $('body').width();
  var height = $('body').height();

  var hue = Math.floor(axisX / width * 360);
  var saturation = Math.floor(axisY / height * 100);
  var lightness = Math.floor(axisY / height * 100);

  $('body').css('background', 'hsl(' + hue + ',' + saturation + '%, ' + lightness + '%)');
}
<commit_msg>fix to x integer display<commit_after>$(document).ready(function() {
  var myDataRef = new Firebase('https://theremouse.firebaseio.com/');
	var theremins = {};
	var userId = Math.floor(Math.random() * 1000000) + 1;

	var audioCtx = new(window.AudioContext || window.webkitAudioContext)();

	$(document).mousemove(function(event) {
    var x = event.pageX - 900;
    var y = event.pageY;
		$(".x").text("X: " + (x + 900));
		$(".y").text("Y: " + y);

		myDataRef.push({xCoord: x, yCoord: y, userId: userId});

    updateView(x, y);
	});

	myDataRef.on('child_added', function(snapshot) {
    var userId = snapshot.val().userId;
  	if (!theremins[userId]) {
  		var theremin = new Theremin(audioCtx);
  		theremins[userId.toString()] = theremin;
  	}
  	var x = snapshot.val().xCoord;
  	var y = snapshot.val().yCoord;
  	theremins[userId].update(x, y);
  });

  // clean the database every 5 seconds
  // it's only used for the real time polyphonic feature
  setInterval(function() {myDataRef.remove()}, 5000)
});

function updateView(axisX, axisY) {
  var width = $('body').width();
  var height = $('body').height();

  var hue = Math.floor(axisX / width * 360);
  var saturation = Math.floor(axisY / height * 100);
  var lightness = Math.floor(axisY / height * 100);

  $('body').css('background', 'hsl(' + hue + ',' + saturation + '%, ' + lightness + '%)');
}
<|endoftext|>


<commit_before>var util = require("util");
var path = require("path");
var Q = require("q");
var _ = require("lodash");
var swig = require("../template");

var fs = require("../fs");
var parse = require("../../parse");
var BaseGenerator = require("../generator");
var links = require("../../utils/links");
var indexer = require('./search_indexer');
var glossaryIndexer = require('./glossary_indexer');

var Generator = function() {
    BaseGenerator.apply(this, arguments);

    // Attach methods to instance
    _.bindAll(this);

    this.revision = Date.now();
    this.indexer = indexer();
};
util.inherits(Generator, BaseGenerator);

// Load all templates
Generator.prototype.loadTemplates = function() {
    this.template = swig.compileFile(
        this.plugins.template("site") || path.resolve(this.options.theme, 'templates/site.html')
    );
    this.langsTemplate = swig.compileFile(
        this.plugins.template("langs") || path.resolve(this.options.theme, 'templates/langs.html')
    );
    this.glossaryTemplate = swig.compileFile(
        this.plugins.template("glossary") || path.resolve(this.options.theme, 'templates/glossary.html')
    );
};

// Load plugins
Generator.prototype.loadPlugins = function() {
    var that = this;

    return BaseGenerator.prototype.loadPlugins.apply(this)
    .then(function() {
        return that.loadTemplates();
    });
};

// Generate a template
Generator.prototype._writeTemplate = function(tpl, options, output, interpolate) {
    var that = this;

    interpolate = interpolate || _.identity;
    return Q()
    .then(function(sections) {
        return tpl(_.extend({
            revision: that.revision,

            title: that.options.title,
            description: that.options.description,

            glossary: that.options.glossary,

            summary: that.options.summary,
            allNavigation: that.options.navigation,

            plugins: that.plugins,
            pluginsConfig: JSON.stringify(that.options.pluginsConfig),
            htmlSnippet: _.partialRight(that.plugins.html, that, options),

            options: that.options
        }, options));
    })
    .then(interpolate)
    .then(function(html) {
        return fs.writeFile(
            output,
            html
        );
    });
};

Generator.prototype.indexPage = function(lexed, pagePath) {
    // Setup glossary indexer if not yet setup
    if(!this.glossaryIndexer) {
        this.glossaryIndexer = glossaryIndexer(this.options.glossary);
    }

    this.indexer.add(lexed, pagePath);
    this.glossaryIndexer.add(lexed, pagePath);
    return Q();
};

// Convert a markdown file into a normalized data set
Generator.prototype.prepareFile  = function(content, _input) {
    var that = this;

    var input = path.join(this.options.input, _input);

    var page = {
        path: _input,
        rawPath: input,
        content: content,
        progress: parse.progress(this.options.navigation, _input)
    };

    var _callHook = function(name) {
        return that.callHook(name, page)
        .then(function(_page) {
            page = _page;
            return page;
        });
    };

    return Q()
    .then(function() {
        // Send content to plugins
        return _callHook("page:before");
    })
    .then(function() {
        // Lex page
        return parse.lex(page.content);
    })
    .then(function(lexed) {
        page.lexed = lexed;

        // Get HTML generated sections
        return parse.page(lexed, {
            dir: path.dirname(_input) || '/',
            outdir: path.dirname(_input) || '/',
        });
    })
    .then(function(sections) {
        page.sections = sections;

        // Use plugin hook
        return _callHook("page");
    })
    .then(function() {
        return page;
    });
};

// Convert a markdown file to html
Generator.prototype.convertFile = function(content, _input) {
    var that = this;

    var _output = _input.replace(".md", ".html");
    if (_output == "README.html") _output = "index.html";
    var output = path.join(this.options.output, _output);
    var basePath = path.relative(path.dirname(output), this.options.output) || ".";

    return this.prepareFile(content, _input)
    .then(function(page) {
        // Index page in search
        return that.indexPage(page.lexed, _output).thenResolve(page);
    })
    .then(function(page) {
        // Write file
        return that._writeTemplate(that.template, {
            progress: page.progress,

            _input: page.path,
            content: page.sections,

            basePath: basePath,
            staticBase: links.join(basePath, "gitbook"),
        }, output, function(html) {
            page.content = html;

            return that.callHook("page:after", page).get("content")
        });
    });
};

// Generate languages index
Generator.prototype.langsIndex = function(langs) {
    var that = this;
    var basePath = ".";

    return this._writeTemplate(this.langsTemplate, {
        langs: langs.list,

        basePath: basePath,
        staticBase: path.join(basePath, "gitbook"),
    }, path.join(this.options.output, "index.html"))
    .then(function() {
        // Copy assets
        return that.copyAssets();
    });
};

// Generate glossary
Generator.prototype.writeGlossary = function() {
    var that = this;
    var basePath = ".";

    // No glossary
    if (!this.glossaryIndexer) return Q();

    // Transform the glossary to get term, description, files
    var glossary = _.chain(this.glossaryIndexer.invertedIdx)
    .map(function(links, id) {
        var term = _.find(that.options.glossary, { 'id': id });

        return {
            id: id,
            name: term.name,
            description: term.description,
            files: _.chain(links)
                .map(function(link) {
                    var name = link.slice(0, -5);

                    if (name == "index") {
                        name = "README";
                    }
                    return that.options.navigation[name+".md"];
                })
                .sortBy("percent")
                .value()
        }
    })
    .sortBy("name")
    .value();

    return this._writeTemplate(this.glossaryTemplate, {
        glossaryIndex: glossary,
        basePath: basePath,
        staticBase: path.join(basePath, "gitbook"),
    }, path.join(this.options.output, "GLOSSARY.html"));
};

// Copy assets
Generator.prototype.copyAssets = function() {
    var that = this;

    // Copy gitbook assets
    return fs.copy(
        path.join(that.options.theme, "assets"),
        path.join(that.options.output, "gitbook")
    )

    // Copy plugins assets
    .then(function() {
        return Q.all(
            _.map(that.plugins.list, function(plugin) {
                var pluginAssets = path.join(that.options.output, "gitbook/plugins/", plugin.name);
                return plugin.copyAssets(pluginAssets, {
                    base: this.pluginAssetsBase
                });
            })
        );
    });
};

// Dump search index to disk
Generator.prototype.writeSearchIndex = function() {
    return fs.writeFile(
        path.join(this.options.output, 'search_index.json'),
        this.indexer.dump()
    );
};

// Dump glossary index to disk
Generator.prototype.writeGlossaryIndex = function() {
    if (!this.glossaryIndexer) return Q();

    return fs.writeFile(
        path.join(this.options.output, 'glossary_index.json'),
        JSON.stringify(this.options.glossary)
    );
};

Generator.prototype.finish = function() {
    return this.copyAssets()
    .then(this.copyCover)
    .then(this.writeGlossary)
    .then(this.writeGlossaryIndex)
    .then(this.writeSearchIndex);
};

module.exports = Generator;
<commit_msg>Fix correct folder for assets<commit_after>var util = require("util");
var path = require("path");
var Q = require("q");
var _ = require("lodash");
var swig = require("../template");

var fs = require("../fs");
var parse = require("../../parse");
var BaseGenerator = require("../generator");
var links = require("../../utils/links");
var indexer = require('./search_indexer');
var glossaryIndexer = require('./glossary_indexer');

var Generator = function() {
    BaseGenerator.apply(this, arguments);

    // Attach methods to instance
    _.bindAll(this);

    this.revision = Date.now();
    this.indexer = indexer();
};
util.inherits(Generator, BaseGenerator);

// Load all templates
Generator.prototype.loadTemplates = function() {
    this.template = swig.compileFile(
        this.plugins.template("site") || path.resolve(this.options.theme, 'templates/site.html')
    );
    this.langsTemplate = swig.compileFile(
        this.plugins.template("langs") || path.resolve(this.options.theme, 'templates/langs.html')
    );
    this.glossaryTemplate = swig.compileFile(
        this.plugins.template("glossary") || path.resolve(this.options.theme, 'templates/glossary.html')
    );
};

// Load plugins
Generator.prototype.loadPlugins = function() {
    var that = this;

    return BaseGenerator.prototype.loadPlugins.apply(this)
    .then(function() {
        return that.loadTemplates();
    });
};

// Generate a template
Generator.prototype._writeTemplate = function(tpl, options, output, interpolate) {
    var that = this;

    interpolate = interpolate || _.identity;
    return Q()
    .then(function(sections) {
        return tpl(_.extend({
            revision: that.revision,

            title: that.options.title,
            description: that.options.description,

            glossary: that.options.glossary,

            summary: that.options.summary,
            allNavigation: that.options.navigation,

            plugins: that.plugins,
            pluginsConfig: JSON.stringify(that.options.pluginsConfig),
            htmlSnippet: _.partialRight(that.plugins.html, that, options),

            options: that.options
        }, options));
    })
    .then(interpolate)
    .then(function(html) {
        return fs.writeFile(
            output,
            html
        );
    });
};

Generator.prototype.indexPage = function(lexed, pagePath) {
    // Setup glossary indexer if not yet setup
    if(!this.glossaryIndexer) {
        this.glossaryIndexer = glossaryIndexer(this.options.glossary);
    }

    this.indexer.add(lexed, pagePath);
    this.glossaryIndexer.add(lexed, pagePath);
    return Q();
};

// Convert a markdown file into a normalized data set
Generator.prototype.prepareFile  = function(content, _input) {
    var that = this;

    var input = path.join(this.options.input, _input);

    var page = {
        path: _input,
        rawPath: input,
        content: content,
        progress: parse.progress(this.options.navigation, _input)
    };

    var _callHook = function(name) {
        return that.callHook(name, page)
        .then(function(_page) {
            page = _page;
            return page;
        });
    };

    return Q()
    .then(function() {
        // Send content to plugins
        return _callHook("page:before");
    })
    .then(function() {
        // Lex page
        return parse.lex(page.content);
    })
    .then(function(lexed) {
        page.lexed = lexed;

        // Get HTML generated sections
        return parse.page(lexed, {
            dir: path.dirname(_input) || '/',
            outdir: path.dirname(_input) || '/',
        });
    })
    .then(function(sections) {
        page.sections = sections;

        // Use plugin hook
        return _callHook("page");
    })
    .then(function() {
        return page;
    });
};

// Convert a markdown file to html
Generator.prototype.convertFile = function(content, _input) {
    var that = this;

    var _output = _input.replace(".md", ".html");
    if (_output == "README.html") _output = "index.html";
    var output = path.join(this.options.output, _output);
    var basePath = path.relative(path.dirname(output), this.options.output) || ".";

    return this.prepareFile(content, _input)
    .then(function(page) {
        // Index page in search
        return that.indexPage(page.lexed, _output).thenResolve(page);
    })
    .then(function(page) {
        // Write file
        return that._writeTemplate(that.template, {
            progress: page.progress,

            _input: page.path,
            content: page.sections,

            basePath: basePath,
            staticBase: links.join(basePath, "gitbook"),
        }, output, function(html) {
            page.content = html;

            return that.callHook("page:after", page).get("content")
        });
    });
};

// Generate languages index
Generator.prototype.langsIndex = function(langs) {
    var that = this;
    var basePath = ".";

    return this._writeTemplate(this.langsTemplate, {
        langs: langs.list,

        basePath: basePath,
        staticBase: path.join(basePath, "gitbook"),
    }, path.join(this.options.output, "index.html"))
    .then(function() {
        // Copy assets
        return that.copyAssets();
    });
};

// Generate glossary
Generator.prototype.writeGlossary = function() {
    var that = this;
    var basePath = ".";

    // No glossary
    if (!this.glossaryIndexer) return Q();

    // Transform the glossary to get term, description, files
    var glossary = _.chain(this.glossaryIndexer.invertedIdx)
    .map(function(links, id) {
        var term = _.find(that.options.glossary, { 'id': id });

        return {
            id: id,
            name: term.name,
            description: term.description,
            files: _.chain(links)
                .map(function(link) {
                    var name = link.slice(0, -5);

                    if (name == "index") {
                        name = "README";
                    }
                    return that.options.navigation[name+".md"];
                })
                .sortBy("percent")
                .value()
        }
    })
    .sortBy("name")
    .value();

    return this._writeTemplate(this.glossaryTemplate, {
        glossaryIndex: glossary,
        basePath: basePath,
        staticBase: path.join(basePath, "gitbook"),
    }, path.join(this.options.output, "GLOSSARY.html"));
};

// Copy assets
Generator.prototype.copyAssets = function() {
    var that = this;

    // Copy gitbook assets
    return fs.copy(
        path.join(that.options.theme, "assets"),
        path.join(that.options.output, "gitbook")
    )

    // Copy plugins assets
    .then(function() {
        return Q.all(
            _.map(that.plugins.list, function(plugin) {
                var pluginAssets = path.join(that.options.output, "gitbook/plugins/", plugin.name);
                return plugin.copyAssets(pluginAssets, {
                    base: that.pluginAssetsBase
                });
            })
        );
    });
};

// Dump search index to disk
Generator.prototype.writeSearchIndex = function() {
    return fs.writeFile(
        path.join(this.options.output, 'search_index.json'),
        this.indexer.dump()
    );
};

// Dump glossary index to disk
Generator.prototype.writeGlossaryIndex = function() {
    if (!this.glossaryIndexer) return Q();

    return fs.writeFile(
        path.join(this.options.output, 'glossary_index.json'),
        JSON.stringify(this.options.glossary)
    );
};

Generator.prototype.finish = function() {
    return this.copyAssets()
    .then(this.copyCover)
    .then(this.writeGlossary)
    .then(this.writeGlossaryIndex)
    .then(this.writeSearchIndex);
};

module.exports = Generator;
<|endoftext|>


<commit_before>"use strict";

const { ServiceMgr } = require("service");
const path = require("path");
const fs = require("fs-extra-promise");
const readLastLines = require("read-last-lines");

class FsBackend {
    constructor(name, params) {
        this.name = name;
        this.params = params;
    }

    async start() {
    }

    _getBasePath(repository) {
        return path.join(this.params.path, repository._id);
    }

    _getLogPath(repoPath, log) {
        /* Assume _id is an uuid-v4 with dashes. Split by dash to
         * limit the number of nodes per directory a little bit... */
        const repPathParts = log._id.split("-");
        // Use last part as filename, rest as directory-structure
        const filename = repPathParts.pop();
        const dir = path.join(repoPath, ...repPathParts);
        const absPath = path.join(dir, filename);

        return { absPath, dir, filename };
    }

    async _assertRepo(repoPath, expectExist = true) {
        const exist = await fs.existsAsync(repoPath);
        if (expectExist && !exist) {
            throw new Error("Repository location does not exist");
        } else if (!expectExist && exist) {
            throw new Error("Repository location already exist");
        }
    }

    async createRepo(repository) {
        const repoPath = this._getBasePath(repository);

        // TODO: Fix possible race, dir might be created between existsAsync and mkdirsAsync
        await this._assertRepo(repoPath, false);

        await fs.mkdirsAsync(repoPath);
    }

    async updateRepo(/* repository */) {
    }

    async removeRepo(repository) {
        const repoPath = this._getBasePath(repository);

        await this._assertRepo(repoPath);

        await fs.removeAsync(repoPath);
    }

    makeFileName(repository, id) {
        return path.join(this._getBasePath(repository), id.replace(/-/g, "/"));
    }

    async saveLog(repository, log) {
        const filename = this.makeFileName(repository, log._id);
        await fs.ensureFileAsync(filename);
    }

    async appendLog(repository, id, data) {
        try {
            await fs.appendFileAsync(this.makeFileName(repository, id), data);
            // TODO: Notify of update somewhere
        } catch (error) {
            ServiceMgr.instance.log("error", `Error when appending to log id = ${id} data = ${data} error = (${error})`);
        }
    }

    async uploadLog(repository, log, fileStream) {
        const repoPath = this._getBasePath(repository);
        const { absPath: logFilePath, dir: logDir } = this._getLogPath(repoPath, log);

        await this._assertRepo(repoPath);

        // Okay not to check for collisions? This is handled at type level in db?

        await fs.mkdirsAsync(logDir);

        const result = {
            storagePath: logFilePath
        };

        return new Promise((resolve, reject) => {
            fileStream
                .pipe(fs.createWriteStream(logFilePath))
                .on("finish", () => resolve(result))
                .on("error", reject);
        });
    }

    async getLogReadStream(repository, log) {
        const repoPath = this._getBasePath(repository);
        const { absPath: logFilePath } = this._getLogPath(repoPath, log);

        await this._assertRepo(repoPath);
        if (!(await fs.existsAsync(logFilePath))) {
            const error = new Error("Log file doesn't exist");
            error.status = 404;
            throw error;
        }

        return fs.createReadStream(logFilePath);
    }

    async getLastLines(repository, log, limit) {
        const repoPath = this._getBasePath(repository);
        const { absPath: logFilePath } = this._getLogPath(repoPath, log);

        const data = await readLastLines.read(logFilePath, limit);

        return data.split("\n");
    }

    async removeLog(repository, log) {
        const repoPath = this._getBasePath(repository);
        const { absPath: logFilePath } = this._getLogPath(repoPath, log);

        await this._assertRepo(repoPath);

        // TODO: Fix possible race, dir might be created between existsAsync and writeFileAsync
        if (!(await fs.existsAsync(logFilePath))) {
            throw new Error("Log location doesn't exist");
        }

        await fs.removeAsync(logFilePath);
    }

    async dispose() {
    }
}

module.exports = FsBackend;
<commit_msg>LogRepo: Possible fix of issue described in issue #222 but for LogRepo<commit_after>"use strict";

const { ServiceMgr } = require("service");
const path = require("path");
const fs = require("fs-extra-promise");
const readLastLines = require("read-last-lines");

class FsBackend {
    constructor(name, params) {
        this.name = name;
        this.params = params;
    }

    async start() {
    }

    _getBasePath(repository) {
        return path.join(this.params.path, repository._id);
    }

    _getLogPath(repoPath, log) {
        /* Assume _id is an uuid-v4 with dashes. Split by dash to
         * limit the number of nodes per directory a little bit... */
        const repPathParts = log._id.split("-");
        // Use last part as filename, rest as directory-structure
        const filename = repPathParts.pop();
        const dir = path.join(repoPath, ...repPathParts);
        const absPath = path.join(dir, filename);

        return { absPath, dir, filename };
    }

    async _assertRepo(repoPath, expectExist = true) {
        const exist = await fs.existsAsync(repoPath);
        if (expectExist && !exist) {
            throw new Error("Repository location does not exist");
        } else if (!expectExist && exist) {
            throw new Error("Repository location already exist");
        }
    }

    async createRepo(repository) {
        const repoPath = this._getBasePath(repository);

        // TODO: Fix possible race, dir might be created between existsAsync and mkdirsAsync
        await this._assertRepo(repoPath, false);

        await fs.mkdirsAsync(repoPath);
    }

    async updateRepo(/* repository */) {
    }

    async removeRepo(repository) {
        const repoPath = this._getBasePath(repository);

        await this._assertRepo(repoPath);

        await fs.removeAsync(repoPath);
    }

    makeFileName(repository, id) {
        return path.join(this._getBasePath(repository), id.replace(/-/g, "/"));
    }

    async saveLog(repository, log) {
        const filename = this.makeFileName(repository, log._id);
        await fs.ensureFileAsync(filename);
    }

    async appendLog(repository, id, data) {
        try {
            await fs.appendFileAsync(this.makeFileName(repository, id), data);
            // TODO: Notify of update somewhere
        } catch (error) {
            ServiceMgr.instance.log("error", `Error when appending to log id = ${id} data = ${data} error = (${error})`);
        }
    }

    async uploadLog(repository, log, fileStream) {
        const repoPath = this._getBasePath(repository);
        const { absPath: logFilePath, dir: logDir } = this._getLogPath(repoPath, log);

        await this._assertRepo(repoPath);

        // Okay not to check for collisions? This is handled at type level in db?

        await fs.mkdirsAsync(logDir);

        const writeStream = fs.createWriteStream(logFilePath);

        // Wait until writeStream is open before piping data to it
        // see http://stackoverflow.com/questions/12906694/fs-createwritestream-does-not-immediately-create-file
        await new Promise((resolve, reject) => {
            writeStream
                .on("open", resolve)
                .on("error", reject);
        });

        await new Promise((resolve, reject) => {
            fileStream
                .pipe(writeStream)
                .on("finish", resolve)
                .on("error", (error) => {
                    // Manually close write-stream on error
                    writeStream.end();
                    reject(error);
                });
        });

        return {
            storagePath: logFilePath
        };
    }

    async getLogReadStream(repository, log) {
        const repoPath = this._getBasePath(repository);
        const { absPath: logFilePath } = this._getLogPath(repoPath, log);

        await this._assertRepo(repoPath);
        if (!(await fs.existsAsync(logFilePath))) {
            const error = new Error("Log file doesn't exist");
            error.status = 404;
            throw error;
        }

        return fs.createReadStream(logFilePath);
    }

    async getLastLines(repository, log, limit) {
        const repoPath = this._getBasePath(repository);
        const { absPath: logFilePath } = this._getLogPath(repoPath, log);

        const data = await readLastLines.read(logFilePath, limit);

        return data.split("\n");
    }

    async removeLog(repository, log) {
        const repoPath = this._getBasePath(repository);
        const { absPath: logFilePath } = this._getLogPath(repoPath, log);

        await this._assertRepo(repoPath);

        // TODO: Fix possible race, dir might be created between existsAsync and writeFileAsync
        if (!(await fs.existsAsync(logFilePath))) {
            throw new Error("Log location doesn't exist");
        }

        await fs.removeAsync(logFilePath);
    }

    async dispose() {
    }
}

module.exports = FsBackend;
<|endoftext|>