<commit_before>import {
  CREATE,
  DELETE,
  DELETE_MANY,
  GET_LIST,
  GET_MANY,
  GET_MANY_REFERENCE,
  GET_ONE,
  UPDATE,
} from 'react-admin';
import isPlainObject from 'lodash.isplainobject';
import qs from 'qs';
import fetchHydra from './fetchHydra';

class ReactAdminDocument {
  constructor(obj) {
    Object.assign(this, obj, {
      originId: obj.id,
      id: obj['@id'],
    });
  }

  /**
   * @return {string}
   */
  toString() {
    return `[object ${this.id}]`;
  }
}

/**
 * Local cache containing embedded documents.
 * It will be used to prevent useless extra HTTP query if the relation is displayed.
 *
 * @type {Map}
 */
const reactAdminDocumentsCache = new Map();

/**
 * Transforms a JSON-LD document to a react-admin compatible document.
 *
 * @param {Object} document
 * @param {bool} clone
 *
 * @return {ReactAdminDocument}
 */
export const transformJsonLdDocumentToReactAdminDocument = (
  document,
  clone = true,
  addToCache = true,
) => {
  if (clone) {
    // deep clone documents
    document = JSON.parse(JSON.stringify(document));
  }

  // The main document is a JSON-LD document, convert it and store it in the cache
  if (document['@id']) {
    document = new ReactAdminDocument(document);
  }

  // Replace embedded objects by their IRIs, and store the object itself in the cache to reuse without issuing new HTTP requests.
  Object.keys(document).forEach(key => {
    // to-one
    if (isPlainObject(document[key]) && document[key]['@id']) {
      if (addToCache) {
        reactAdminDocumentsCache[
          document[key]['@id']
        ] = transformJsonLdDocumentToReactAdminDocument(
          document[key],
          false,
          false,
        );
      }
      document[key] = document[key]['@id'];

      return;
    }

    // to-many
    if (
      Array.isArray(document[key]) &&
      document[key].length &&
      isPlainObject(document[key][0]) &&
      document[key][0]['@id']
    ) {
      document[key] = document[key].map(obj => {
        if (addToCache) {
          reactAdminDocumentsCache[
            obj['@id']
          ] = transformJsonLdDocumentToReactAdminDocument(obj, false, false);
        }

        return obj['@id'];
      });
    }
  });

  return document;
};

/**
 * Maps react-admin queries to a Hydra powered REST API
 *
 * @see http://www.hydra-cg.com/
 *
 * @example
 * CREATE   => POST http://my.api.url/posts/123
 * DELETE   => DELETE http://my.api.url/posts/123
 * GET_LIST => GET http://my.api.url/posts
 * GET_MANY => GET http://my.api.url/posts/123, GET http://my.api.url/posts/456, GET http://my.api.url/posts/789
 * GET_ONE  => GET http://my.api.url/posts/123
 * UPDATE   => PUT http://my.api.url/posts/123
 */
export default ({entrypoint, resources = []}, httpClient = fetchHydra) => {
  /**
   * @param {Object} resource
   * @param {Object} data
   *
   * @returns {Promise}
   */
  const convertReactAdminDataToHydraData = (resource, data = {}) => {
    const fieldData = [];
    resource.fields.forEach(({name, normalizeData}) => {
      if (!(name in data) || undefined === normalizeData) {
        return;
      }

      fieldData[name] = normalizeData(data[name]);
    });

    const fieldDataKeys = Object.keys(fieldData);
    const fieldDataValues = Object.values(fieldData);

    return Promise.all(fieldDataValues).then(fieldData => {
      const object = {};
      for (let i = 0; i < fieldDataKeys.length; i++) {
        object[fieldDataKeys[i]] = fieldData[i];
      }

      return {...data, ...object};
    });
  };

  /**
   * @param {Object} resource
   * @param {Object} data
   *
   * @returns {Promise}
   */
  const transformReactAdminDataToRequestBody = (resource, data = {}) => {
    resource = resources.find(({name}) => resource === name);
    if (undefined === resource) {
      return Promise.resolve(data);
    }

    return convertReactAdminDataToHydraData(resource, data).then(data => {
      return undefined === resource.encodeData
        ? JSON.stringify(data)
        : resource.encodeData(data);
    });
  };

  /**
   * @param {string} type
   * @param {string} resource
   * @param {Object} params
   *
   * @returns {Object}
   */
  const convertReactAdminRequestToHydraRequest = (type, resource, params) => {
    switch (type) {
      case CREATE:
        return transformReactAdminDataToRequestBody(resource, params.data).then(
          body => ({
            options: {
              body,
              method: 'POST',
            },
            url: `${entrypoint}/${resource}`,
          }),
        );

      case DELETE:
        return Promise.resolve({
          options: {
            method: 'DELETE',
          },
          url: entrypoint + params.id,
        });

      case GET_LIST: {
        const {
          pagination: {page},
          sort: {field, order},
        } = params;

        return Promise.resolve({
          options: {},
          url: `${entrypoint}/${resource}?${qs.stringify({
            ...params.filter,
            order: {
              [field]: order,
            },
            page,
          })}`,
        });
      }

      case GET_MANY_REFERENCE:
        return Promise.resolve({
          options: {},
          url: `${entrypoint}/${resource}?${qs.stringify({
            [params.target]: params.id,
          })}`,
        });

      case GET_ONE:
        return Promise.resolve({
          options: {},
          url: entrypoint + params.id,
        });

      case UPDATE:
        return transformReactAdminDataToRequestBody(resource, params.data).then(
          body => ({
            options: {
              body,
              method: 'PUT',
            },
            url: entrypoint + params.id,
          }),
        );

      default:
        throw new Error(`Unsupported fetch action type ${type}`);
    }
  };

  /**
   * @param {string} resource
   * @param {Object} data
   *
   * @returns {Promise}
   */
  const convertHydraDataToReactAdminData = (resource, data = {}) => {
    resource = resources.find(({name}) => resource === name);
    if (undefined === resource) {
      return Promise.resolve(data);
    }

    const fieldData = {};
    resource.fields.forEach(({name, denormalizeData}) => {
      if (!(name in data) || undefined === denormalizeData) {
        return;
      }

      fieldData[name] = denormalizeData(data[name]);
    });

    const fieldDataKeys = Object.keys(fieldData);
    const fieldDataValues = Object.values(fieldData);

    return Promise.all(fieldDataValues).then(fieldData => {
      const object = {};
      for (let i = 0; i < fieldDataKeys.length; i++) {
        object[fieldDataKeys[i]] = fieldData[i];
      }

      return {...data, ...object};
    });
  };

  /**
   * @param {Object} response
   * @param {string} resource
   * @param {string} type
   *
   * @returns {Promise}
   */
  const convertHydraResponseToReactAdminResponse = (
    type,
    resource,
    response,
  ) => {
    switch (type) {
      case GET_LIST:
      case GET_MANY_REFERENCE:
        // TODO: support other prefixes than "hydra:"
        return Promise.resolve(
          response.json['hydra:member'].map(
            transformJsonLdDocumentToReactAdminDocument,
          ),
        )
          .then(data =>
            Promise.all(
              data.map(data =>
                convertHydraDataToReactAdminData(resource, data),
              ),
            ),
          )
          .then(data => ({data, total: response.json['hydra:totalItems']}));

      case DELETE:
        return Promise.resolve(() => ({data: {}}));

      default:
        return Promise.resolve(
          transformJsonLdDocumentToReactAdminDocument(response.json),
        )
          .then(data => convertHydraDataToReactAdminData(resource, data))
          .then(data => ({data}));
    }
  };

  /**
   * @param {string} type
   * @param {string} resource
   * @param {Object} params
   *
   * @returns {Promise}
   */
  const fetchApi = (type, resource, params) => {
    // Hydra doesn't handle MANY requests, so we fallback to calling the ONE request n times instead
    switch (type) {
      case GET_MANY:
        return Promise.all(
          params.ids.map(
            id =>
              reactAdminDocumentsCache[id]
                ? Promise.resolve({data: reactAdminDocumentsCache[id]})
                : fetchApi(GET_ONE, resource, {id}),
          ),
        ).then(responses => ({data: responses.map(({data}) => data)}));

      case DELETE_MANY:
        return Promise.all(
          params.ids.map(id => fetchApi(DELETE, resource, {id})),
        ).then(responses => ({data: {}}));

      default:
        return convertReactAdminRequestToHydraRequest(type, resource, params)
          .then(({url, options}) => httpClient(url, options))
          .then(response =>
            convertHydraResponseToReactAdminResponse(type, resource, response),
          );
    }
  };

  return fetchApi;
};
<commit_msg>Fix singular DELETE<commit_after>import {
  CREATE,
  DELETE,
  DELETE_MANY,
  GET_LIST,
  GET_MANY,
  GET_MANY_REFERENCE,
  GET_ONE,
  UPDATE,
} from 'react-admin';
import isPlainObject from 'lodash.isplainobject';
import qs from 'qs';
import fetchHydra from './fetchHydra';

class ReactAdminDocument {
  constructor(obj) {
    Object.assign(this, obj, {
      originId: obj.id,
      id: obj['@id'],
    });
  }

  /**
   * @return {string}
   */
  toString() {
    return `[object ${this.id}]`;
  }
}

/**
 * Local cache containing embedded documents.
 * It will be used to prevent useless extra HTTP query if the relation is displayed.
 *
 * @type {Map}
 */
const reactAdminDocumentsCache = new Map();

/**
 * Transforms a JSON-LD document to a react-admin compatible document.
 *
 * @param {Object} document
 * @param {bool} clone
 *
 * @return {ReactAdminDocument}
 */
export const transformJsonLdDocumentToReactAdminDocument = (
  document,
  clone = true,
  addToCache = true,
) => {
  if (clone) {
    // deep clone documents
    document = JSON.parse(JSON.stringify(document));
  }

  // The main document is a JSON-LD document, convert it and store it in the cache
  if (document['@id']) {
    document = new ReactAdminDocument(document);
  }

  // Replace embedded objects by their IRIs, and store the object itself in the cache to reuse without issuing new HTTP requests.
  Object.keys(document).forEach(key => {
    // to-one
    if (isPlainObject(document[key]) && document[key]['@id']) {
      if (addToCache) {
        reactAdminDocumentsCache[
          document[key]['@id']
        ] = transformJsonLdDocumentToReactAdminDocument(
          document[key],
          false,
          false,
        );
      }
      document[key] = document[key]['@id'];

      return;
    }

    // to-many
    if (
      Array.isArray(document[key]) &&
      document[key].length &&
      isPlainObject(document[key][0]) &&
      document[key][0]['@id']
    ) {
      document[key] = document[key].map(obj => {
        if (addToCache) {
          reactAdminDocumentsCache[
            obj['@id']
          ] = transformJsonLdDocumentToReactAdminDocument(obj, false, false);
        }

        return obj['@id'];
      });
    }
  });

  return document;
};

/**
 * Maps react-admin queries to a Hydra powered REST API
 *
 * @see http://www.hydra-cg.com/
 *
 * @example
 * CREATE   => POST http://my.api.url/posts/123
 * DELETE   => DELETE http://my.api.url/posts/123
 * GET_LIST => GET http://my.api.url/posts
 * GET_MANY => GET http://my.api.url/posts/123, GET http://my.api.url/posts/456, GET http://my.api.url/posts/789
 * GET_ONE  => GET http://my.api.url/posts/123
 * UPDATE   => PUT http://my.api.url/posts/123
 */
export default ({entrypoint, resources = []}, httpClient = fetchHydra) => {
  /**
   * @param {Object} resource
   * @param {Object} data
   *
   * @returns {Promise}
   */
  const convertReactAdminDataToHydraData = (resource, data = {}) => {
    const fieldData = [];
    resource.fields.forEach(({name, normalizeData}) => {
      if (!(name in data) || undefined === normalizeData) {
        return;
      }

      fieldData[name] = normalizeData(data[name]);
    });

    const fieldDataKeys = Object.keys(fieldData);
    const fieldDataValues = Object.values(fieldData);

    return Promise.all(fieldDataValues).then(fieldData => {
      const object = {};
      for (let i = 0; i < fieldDataKeys.length; i++) {
        object[fieldDataKeys[i]] = fieldData[i];
      }

      return {...data, ...object};
    });
  };

  /**
   * @param {Object} resource
   * @param {Object} data
   *
   * @returns {Promise}
   */
  const transformReactAdminDataToRequestBody = (resource, data = {}) => {
    resource = resources.find(({name}) => resource === name);
    if (undefined === resource) {
      return Promise.resolve(data);
    }

    return convertReactAdminDataToHydraData(resource, data).then(data => {
      return undefined === resource.encodeData
        ? JSON.stringify(data)
        : resource.encodeData(data);
    });
  };

  /**
   * @param {string} type
   * @param {string} resource
   * @param {Object} params
   *
   * @returns {Object}
   */
  const convertReactAdminRequestToHydraRequest = (type, resource, params) => {
    switch (type) {
      case CREATE:
        return transformReactAdminDataToRequestBody(resource, params.data).then(
          body => ({
            options: {
              body,
              method: 'POST',
            },
            url: `${entrypoint}/${resource}`,
          }),
        );

      case DELETE:
        return Promise.resolve({
          options: {
            method: 'DELETE',
          },
          url: entrypoint + params.id,
        });

      case GET_LIST: {
        const {
          pagination: {page},
          sort: {field, order},
        } = params;

        return Promise.resolve({
          options: {},
          url: `${entrypoint}/${resource}?${qs.stringify({
            ...params.filter,
            order: {
              [field]: order,
            },
            page,
          })}`,
        });
      }

      case GET_MANY_REFERENCE:
        return Promise.resolve({
          options: {},
          url: `${entrypoint}/${resource}?${qs.stringify({
            [params.target]: params.id,
          })}`,
        });

      case GET_ONE:
        return Promise.resolve({
          options: {},
          url: entrypoint + params.id,
        });

      case UPDATE:
        return transformReactAdminDataToRequestBody(resource, params.data).then(
          body => ({
            options: {
              body,
              method: 'PUT',
            },
            url: entrypoint + params.id,
          }),
        );

      default:
        throw new Error(`Unsupported fetch action type ${type}`);
    }
  };

  /**
   * @param {string} resource
   * @param {Object} data
   *
   * @returns {Promise}
   */
  const convertHydraDataToReactAdminData = (resource, data = {}) => {
    resource = resources.find(({name}) => resource === name);
    if (undefined === resource) {
      return Promise.resolve(data);
    }

    const fieldData = {};
    resource.fields.forEach(({name, denormalizeData}) => {
      if (!(name in data) || undefined === denormalizeData) {
        return;
      }

      fieldData[name] = denormalizeData(data[name]);
    });

    const fieldDataKeys = Object.keys(fieldData);
    const fieldDataValues = Object.values(fieldData);

    return Promise.all(fieldDataValues).then(fieldData => {
      const object = {};
      for (let i = 0; i < fieldDataKeys.length; i++) {
        object[fieldDataKeys[i]] = fieldData[i];
      }

      return {...data, ...object};
    });
  };

  /**
   * @param {Object} response
   * @param {string} resource
   * @param {string} type
   *
   * @returns {Promise}
   */
  const convertHydraResponseToReactAdminResponse = (
    type,
    resource,
    response,
  ) => {
    switch (type) {
      case GET_LIST:
      case GET_MANY_REFERENCE:
        // TODO: support other prefixes than "hydra:"
        return Promise.resolve(
          response.json['hydra:member'].map(
            transformJsonLdDocumentToReactAdminDocument,
          ),
        )
          .then(data =>
            Promise.all(
              data.map(data =>
                convertHydraDataToReactAdminData(resource, data),
              ),
            ),
          )
          .then(data => ({data, total: response.json['hydra:totalItems']}));

      case DELETE:
        return Promise.resolve({data: {}});

      default:
        return Promise.resolve(
          transformJsonLdDocumentToReactAdminDocument(response.json),
        )
          .then(data => convertHydraDataToReactAdminData(resource, data))
          .then(data => ({data}));
    }
  };

  /**
   * @param {string} type
   * @param {string} resource
   * @param {Object} params
   *
   * @returns {Promise}
   */
  const fetchApi = (type, resource, params) => {
    // Hydra doesn't handle MANY requests, so we fallback to calling the ONE request n times instead
    switch (type) {
      case GET_MANY:
        return Promise.all(
          params.ids.map(
            id =>
              reactAdminDocumentsCache[id]
                ? Promise.resolve({data: reactAdminDocumentsCache[id]})
                : fetchApi(GET_ONE, resource, {id}),
          ),
        ).then(responses => ({data: responses.map(({data}) => data)}));

      case DELETE_MANY:
        return Promise.all(
          params.ids.map(id => fetchApi(DELETE, resource, {id})),
        ).then(responses => ({data: {}}));

      default:
        return convertReactAdminRequestToHydraRequest(type, resource, params)
          .then(({url, options}) => httpClient(url, options))
          .then(response =>
            convertHydraResponseToReactAdminResponse(type, resource, response),
          );
    }
  };

  return fetchApi;
};
<|endoftext|>


<commit_before>// This is main process of Electron, started as first thing when your
// app starts. This script is running through entire life of your application.
// It doesn't have any windows which you can see on screen, but we can open
// window from here.

import { app, BrowserWindow, ipcMain } from 'electron';
import devHelper from './vendor/electron_boilerplate/dev_helper';
import windowStateKeeper from './vendor/electron_boilerplate/window_state';
import certificate from './certificate';
import Toaster from 'electron-toaster';
import os from 'os';
const toaster = new Toaster();

// Special module holding environment variables which you declared
// in config/env_xxx.json file.
import env from './env';

var mainWindow;

if (process.platform !== 'darwin') {
    var shouldQuit = app.makeSingleInstance(function() {
        // Someone tried to run a second instance, we should focus our window.
        if (mainWindow) {
            mainWindow.show();
            mainWindow.focus();
        }
    });

    if (shouldQuit) {
        app.quit();
    }
}

// Preserver of the window size and position between app launches.
var mainWindowState = windowStateKeeper('main', {
    width: 1000,
    height: 600
});

// ==== Quick check to fetch Operating System and it's version ==>>
// Add here any OS without native support for notifications to Toaster is used
var useToaster = false;

// Windows 7 or older
if (os.platform() === 'win32' || os.platform() === 'win64') {
    if (parseFloat(os.release) < 6.2) useToaster = true;
};
// =========================================================================>>

app.on('ready', function () {

    mainWindow = new BrowserWindow({
        x: mainWindowState.x,
        y: mainWindowState.y,
        width: mainWindowState.width,
        height: mainWindowState.height,
        minWidth: 600,
        minHeight: 400
    });

    if (mainWindowState.isMaximized) {
        mainWindow.maximize();
    }

    if (mainWindowState.isMinimized) {
        mainWindow.minimize();
    }

    if (mainWindowState.isHidden) {
        mainWindow.hide();
    }

    if (env.name === 'test') {
        mainWindow.loadURL('file://' + __dirname + '/spec.html');
    } else {
        mainWindow.loadURL('file://' + __dirname + '/app.html');
    }

    if (env.name !== 'production') {
        devHelper.setDevMenu();
        mainWindow.openDevTools();
    }

    mainWindow.on('close', function (event) {
        if (mainWindow.forceClose) {
            mainWindowState.saveState(mainWindow);
            return;
        }
        event.preventDefault();
        mainWindow.hide();
        mainWindowState.saveState(mainWindow);
    });

    app.on('before-quit', function() {
        mainWindowState.saveState(mainWindow);
        mainWindow.forceClose = true;
    });

    mainWindow.on('resize', function() {
        mainWindowState.saveState(mainWindow);
    });

    mainWindow.on('move', function() {
        mainWindowState.saveState(mainWindow);
    });

    app.on('activate', function(){
        mainWindow.show();
    });

    mainWindow.webContents.on('will-navigate', function(event) {
        event.preventDefault();
    });

	if(useToaster) {

	    toaster.init(mainWindow);

		ipcMain.on('notification-shim', (e, msg) => {

			mainWindow.webContents.executeJavaScript(`
				require('electron').ipcRenderer.send('electron-toaster-message', {
					title: '${msg.title}',
					message: \`${msg.options.body}\`,
					width: 400,
					htmlFile: 'file://'+__dirname+'/notification.html?'
				});
			`);
		});
	};

    certificate.initWindow(mainWindow);
});

app.on('window-all-closed', function () {
    app.quit();
});
<commit_msg>Revert "Fixed Toaster OS check to use os.release()"<commit_after>// This is main process of Electron, started as first thing when your
// app starts. This script is running through entire life of your application.
// It doesn't have any windows which you can see on screen, but we can open
// window from here.

import { app, BrowserWindow, ipcMain } from 'electron';
import devHelper from './vendor/electron_boilerplate/dev_helper';
import windowStateKeeper from './vendor/electron_boilerplate/window_state';
import certificate from './certificate';
import Toaster from 'electron-toaster';
const toaster = new Toaster();

// Special module holding environment variables which you declared
// in config/env_xxx.json file.
import env from './env';

var mainWindow;

if (process.platform !== 'darwin') {
    var shouldQuit = app.makeSingleInstance(function() {
        // Someone tried to run a second instance, we should focus our window.
        if (mainWindow) {
            mainWindow.show();
            mainWindow.focus();
        }
    });

    if (shouldQuit) {
        app.quit();
    }
}

// Preserver of the window size and position between app launches.
var mainWindowState = windowStateKeeper('main', {
    width: 1000,
    height: 600
});

// ==== Quick check to fetch OS Name and set Toaster notifications on/off ==>>
// Add here any OS without native support for notifications
var useToaster = false;

// Windows 7 / 2008 R2
if (navigator.userAgent.indexOf("Windows NT 6.2")!=-1) useToaster = true;

// Windows Vista / 2008
if (navigator.userAgent.indexOf("Windows NT 6.0")!=-1) useToaster = true;

// Windows XP / 2003
if (navigator.userAgent.indexOf("Windows NT 5.2")!=-1) useToaster = true;
if (navigator.userAgent.indexOf("Windows NT 5.1")!=-1) useToaster = true;
// =========================================================================>>

app.on('ready', function () {

    mainWindow = new BrowserWindow({
        x: mainWindowState.x,
        y: mainWindowState.y,
        width: mainWindowState.width,
        height: mainWindowState.height,
        minWidth: 600,
        minHeight: 400
    });

    if (mainWindowState.isMaximized) {
        mainWindow.maximize();
    }

    if (mainWindowState.isMinimized) {
        mainWindow.minimize();
    }

    if (mainWindowState.isHidden) {
        mainWindow.hide();
    }

    if (env.name === 'test') {
        mainWindow.loadURL('file://' + __dirname + '/spec.html');
    } else {
        mainWindow.loadURL('file://' + __dirname + '/app.html');
    }

    if (env.name !== 'production') {
        devHelper.setDevMenu();
        mainWindow.openDevTools();
    }

    mainWindow.on('close', function (event) {
        if (mainWindow.forceClose) {
            mainWindowState.saveState(mainWindow);
            return;
        }
        event.preventDefault();
        mainWindow.hide();
        mainWindowState.saveState(mainWindow);
    });

    app.on('before-quit', function() {
        mainWindowState.saveState(mainWindow);
        mainWindow.forceClose = true;
    });

    mainWindow.on('resize', function() {
        mainWindowState.saveState(mainWindow);
    });

    mainWindow.on('move', function() {
        mainWindowState.saveState(mainWindow);
    });

    app.on('activate', function(){
        mainWindow.show();
    });

    mainWindow.webContents.on('will-navigate', function(event) {
        event.preventDefault();
    });

	if(useToaster) {

	    toaster.init(mainWindow);

		ipcMain.on('notification-shim', (e, msg) => {

			mainWindow.webContents.executeJavaScript(`
				require('electron').ipcRenderer.send('electron-toaster-message', {
					title: '${msg.title}',
					message: \`${msg.options.body}\`,
					width: 400,
					htmlFile: 'file://'+__dirname+'/notification.html?'
				});
			`);
		});
	};

    certificate.initWindow(mainWindow);
});

app.on('window-all-closed', function () {
    app.quit();
});
<|endoftext|>


<commit_before>'use strict';

(function (angular) {
  angular
    .module('mediaCenterRSSPluginContent')
    .controller('ContentHomeCtrl', ['$scope', 'DataStore', 'Buildfire', 'TAG_NAMES', 'LAYOUTS', 'FeedParseService', '$timeout',
      function ($scope, DataStore, Buildfire, TAG_NAMES, LAYOUTS, FeedParseService, $timeout) {
        /*
         * Private variables
         *
         * _data used to specify default values to save when user visit first time.
         * @type {object}
         * @private
         *
         * tmrDelay used to hold the time returned by $timeout
         * @private
         *
         *  */
        var ContentHome = this
          , _data = {
            "content": {
              "carouselImages": [],
              "description": "",
              "rssUrl": "https://twitrss.me/twitter_user_to_rss/?user=microsoft"
            },
            "design": {
              "itemListLayout": LAYOUTS.itemListLayouts[0].name,
              "itemDetailsLayout": LAYOUTS.itemDetailsLayouts[0].name,
              "itemListBgImage": "",
              "itemDetailsBgImage": ""
            }
          }
          , tmrDelay = null;

        /*
         * ContentHome.editor used to add, edit and delete images from your carousel.It will create a new instance of the buildfire carousel editor component.
         */
        ContentHome.editor = new Buildfire.components.carousel.editor("#carousel");

        /*
         * ContentHome.isValidUrl is used to show/hide Success alert message when rss feed url is valid. Its default value is false.
         * @type {boolean}
         */
        ContentHome.isValidUrl = false;

        /*  ContentHome.isInValidUrl is used to show/hide Error alert message when rss feed url is invalid. Its default value is false.
         * @type {boolean}
         */
        ContentHome.isInValidUrl = false;

       /* /!*
         * ContentHome.isSaved is used to show/hide Success alert message when data saved successfully. Its default value is false.
         * @type {boolean}
         *!/
        ContentHome.isSaved = false;*/

        /*
         * ContentHome.isNotSaved is used to show/hide Error alert message when data not saved. Its default value is false.
         * @type {boolean}
         */
        ContentHome.isNotSaved = false;

        /*
         * ContentHome.isValidateButtonClicked is used to disable validate button when clicked to validate RSS feed url and enabled when response has received. Its default value is false.
         * @type {boolean}
         */
        ContentHome.isValidateButtonClicked = false;

        /*
         * ContentHome.descriptionWYSIWYGOptions are optional options used for WYSIWYG text editor.
         * @type {object}
         */
        ContentHome.descriptionWYSIWYGOptions = {
          plugins: 'advlist autolink link image lists charmap print preview',
          skin: 'lightgray',
          trusted: true,
          theme: 'modern'
        };

        /*
         * ContentHome.data is user's data of design and content sections which used throughout the app.
         * @type {object}
         */
        ContentHome.data = angular.copy(_data);

        /*
         * ContentHome.masterData used to hold previous saved user's data.
         * @type {object}
         */
        ContentHome.masterData = null;

        /*
         * ContentHome.rssFeedUrl used as ng-model to show previously saved valid rss feed url.
         * @type {string}
         */
        ContentHome.rssFeedUrl = '';

        /* saveData(data, tag) private function
         * It will Call the Datastore.save method to save the data object
         * @param data: data to save in datastore.
         * @param tag: An alias given to saved data
         */
        var saveData = function (newObj, tag) {
          if (typeof newObj === 'undefined') {
            return;
          }
          var success = function (result) {
              console.info('Saved data result: ', result);
            /*  ContentHome.isSaved = true;
              $timeout(function () {
                ContentHome.isSaved = false;
              }, 1000);*/
              updateMasterItem(newObj);
            }
            , error = function (err) {
              console.error('Error while saving data : ', err);
              ContentHome.isNotSaved = true;
              $timeout(function () {
                ContentHome.isNotSaved = false;
              }, 1000);
            };
          DataStore.save(newObj, tag).then(success, error);
        };

        /**
         * saveDataWithDelay(newObj) private function
         * It will create an artificial delay so api isn't called on every character entered
         * @param newObj is an updated data object
         */
        var saveDataWithDelay = function (newObj) {
          if (newObj) {
            if (isUnchanged(newObj)) {
              return;
            }
            if (tmrDelay) {
              clearTimeout(tmrDelay);
            }
            tmrDelay = setTimeout(function () {
              console.log('0>>>>>',newObj, ContentHome.masterData);
              saveData(JSON.parse(angular.toJson(newObj)), TAG_NAMES.RSS_FEED_INFO);
            }, 500);
          }
        };

        /**
         * init() private function
         * It is used to fetch previously saved user's data
         */
        var init = function () {
          var success = function (result) {
              console.info('Init success result:', result);
              if (Object.keys(result.data).length > 0) {
                updateMasterItem(result.data);
                ContentHome.data = result.data;
              }
              if (!ContentHome.data) {
                updateMasterItem(_data);
                ContentHome.data = angular.copy(_data);
              } else {
                if (ContentHome.data.content && !ContentHome.data.content.carouselImages) {
                  ContentHome.editor.loadItems([]);
                }
                else {
                  ContentHome.editor.loadItems(ContentHome.data.content.carouselImages);
                }
                if (ContentHome.data.content.rssUrl)
                  ContentHome.rssFeedUrl = ContentHome.data.content.rssUrl;
              }
              //updateMasterItem(ContentHome.data);
              if (tmrDelay) {
                clearTimeout(tmrDelay)
              }
            }
            , error = function (err) {
              console.error('Error while getting data', err);
              if (tmrDelay) {
                clearTimeout(tmrDelay)
              }

            };
          DataStore.get(TAG_NAMES.RSS_FEED_INFO).then(success, error);
        };

        /**
         * function updateMasterItem(data)
         * Used to update master data with newly saved user's data object.
         * @param data is an updated data.
         */
        function updateMasterItem(data) {
          ContentHome.masterData = angular.copy(data);
        }

        /**
         * function isUnchanged(data)
         * Used to check master data object and updated data object are same or not
         * @param data
         * @returns {*|boolean}
         */
        function isUnchanged(data) {
          console.log('-1',data, ContentHome.masterData);
          return angular.equals(data, ContentHome.masterData);
        }

        /**
         *  updateMasterItem() function invocation to update master data with default data.
         */
        updateMasterItem(_data);

        /**
         *  init() function invocation to fetch previously saved user's data from datastore.
         */
        init();

        /**
         * ContentHome.editor.onAddItems function will be called when new image item(s) added to carousel image item list.
         * @param items
         */
        ContentHome.editor.onAddItems = function (items) {
          ContentHome.data.content.carouselImages.push.apply(ContentHome.data.content.carouselImages, items);
          $scope.$digest();
        };

        // this method will be called when an item deleted from the list
        /**
         * ContentHome.editor.onDeleteItem will be called when an image item deleted from carousel image item list
         * @param item
         * @param index
         */
        ContentHome.editor.onDeleteItem = function (item, index) {
          ContentHome.data.content.carouselImages.splice(index, 1);
          $scope.$digest();
        };

        /**
         * ContentHome.editor.onItemChange function will be called when you edit details of a carousel image item.
         * @param item
         * @param index
         */
        ContentHome.editor.onItemChange = function (item, index) {
          ContentHome.data.content.carouselImages.splice(index, 1, item);
          $scope.$digest();
        };

        /**
         * ContentHome.editor.onOrderChange function will be called when you change the order of image item in the list.
         * @param item
         * @param oldIndex
         * @param newIndex
         */
        ContentHome.editor.onOrderChange = function (item, oldIndex, newIndex) {
          var temp = ContentHome.data.content.carouselImages[oldIndex];
          ContentHome.data.content.carouselImages[oldIndex] = ContentHome.data.content.carouselImages[newIndex];
          ContentHome.data.content.carouselImages[newIndex] = temp;
          $scope.$digest();
        };

        /**
         * ContentHome.validateFeedUrl function will called when you click validate button to check Rss feed url is either valid or not.
         */
        ContentHome.validateFeedUrl = function () {
          Buildfire.spinner.show();
          var success = function () {
              ContentHome.isValidUrl = true;
              ContentHome.isValidateButtonClicked = false;
              ContentHome.data.content.rssUrl = ContentHome.rssFeedUrl;
              Buildfire.spinner.hide();
              $timeout(function () {
                ContentHome.isValidUrl = false;
              }, 3000);
            }
            , error = function () {
              ContentHome.isInValidUrl = true;
              ContentHome.isValidateButtonClicked = false;
              Buildfire.spinner.hide();
              $timeout(function () {
                ContentHome.isInValidUrl = false;
              }, 3000);
            };
          ContentHome.isValidateButtonClicked = true;
          FeedParseService.validateFeedUrl(ContentHome.rssFeedUrl).then(success, error);
        };

        /**
         * ContentHome.clearData function will called when RSS feed url removed from RSS feed url input box.
         */
        ContentHome.clearData = function () {
          if (!ContentHome.rssFeedUrl) {
            ContentHome.data.content.rssUrl = '';
          }
        };

        /**
         * $scope.$watch will Watch for changes in user's data object and trigger the saveDataWithDelay function if data changed
         */
        $scope.$watch(function () {
          return ContentHome.data;
        }, saveDataWithDelay, true);
      }]);
})(window.angular);
<commit_msg>Default data vanishes on the first update<commit_after>'use strict';

(function (angular) {
    angular
        .module('mediaCenterRSSPluginContent')
        .controller('ContentHomeCtrl', ['$scope', 'DataStore', 'Buildfire', 'TAG_NAMES', 'LAYOUTS', 'FeedParseService', '$timeout',
            function ($scope, DataStore, Buildfire, TAG_NAMES, LAYOUTS, FeedParseService, $timeout) {
                /*
                 * Private variables
                 *
                 * _data used to specify default values to save when user visit first time.
                 * @type {object}
                 * @private
                 *
                 * tmrDelay used to hold the time returned by $timeout
                 * @private
                 *
                 *  */
                var ContentHome = this
                    , _defaultData = {
                        "content": {
                            "carouselImages": [],
                            "description": "",
                            "rssUrl": "https://twitrss.me/twitter_user_to_rss/?user=microsoft"
                        },
                        "design": {
                            "itemListLayout": LAYOUTS.itemListLayouts[0].name,
                            "itemDetailsLayout": LAYOUTS.itemDetailsLayouts[0].name,
                            "itemListBgImage": "",
                            "itemDetailsBgImage": ""
                        },
                        "default": true
                    }
                    , tmrDelay = null;

                /*
                 * ContentHome.editor used to add, edit and delete images from your carousel.It will create a new instance of the buildfire carousel editor component.
                 */
                ContentHome.editor = new Buildfire.components.carousel.editor("#carousel");

                /*
                 * ContentHome.isValidUrl is used to show/hide Success alert message when rss feed url is valid. Its default value is false.
                 * @type {boolean}
                 */
                ContentHome.isValidUrl = false;

                /*  ContentHome.isInValidUrl is used to show/hide Error alert message when rss feed url is invalid. Its default value is false.
                 * @type {boolean}
                 */
                ContentHome.isInValidUrl = false;

                /* /!*
                 * ContentHome.isSaved is used to show/hide Success alert message when data saved successfully. Its default value is false.
                 * @type {boolean}
                 *!/
                 ContentHome.isSaved = false;*/

                /*
                 * ContentHome.isNotSaved is used to show/hide Error alert message when data not saved. Its default value is false.
                 * @type {boolean}
                 */
                ContentHome.isNotSaved = false;

                /*
                 * ContentHome.isValidateButtonClicked is used to disable validate button when clicked to validate RSS feed url and enabled when response has received. Its default value is false.
                 * @type {boolean}
                 */
                ContentHome.isValidateButtonClicked = false;

                /*
                 * ContentHome.descriptionWYSIWYGOptions are optional options used for WYSIWYG text editor.
                 * @type {object}
                 */
                ContentHome.descriptionWYSIWYGOptions = {
                    plugins: 'advlist autolink link image lists charmap print preview',
                    skin: 'lightgray',
                    trusted: true,
                    theme: 'modern'
                };

                /*
                 * ContentHome.data is user's data of design and content sections which used throughout the app.
                 * @type {object}
                 */
                ContentHome.data = angular.copy(_defaultData);

                /*
                 * ContentHome.masterData used to hold previous saved user's data.
                 * @type {object}
                 */
                ContentHome.masterData = null;

                /*
                 * ContentHome.rssFeedUrl used as ng-model to show previously saved valid rss feed url.
                 * @type {string}
                 */
                ContentHome.rssFeedUrl = '';

                /* saveData(data, tag) private function
                 * It will Call the Datastore.save method to save the data object
                 * @param data: data to save in datastore.
                 * @param tag: An alias given to saved data
                 */
                var saveData = function (newObj, tag) {
                    if (typeof newObj === 'undefined') {
                        return;
                    }
                    var success = function (result) {
                            console.info('Saved data result: ', result);
                            /*  ContentHome.isSaved = true;
                             $timeout(function () {
                             ContentHome.isSaved = false;
                             }, 1000);*/
                            updateMasterItem(newObj);
                        }
                        , error = function (err) {
                            console.error('Error while saving data : ', err);
                            ContentHome.isNotSaved = true;
                            $timeout(function () {
                                ContentHome.isNotSaved = false;
                            }, 1000);
                        };
                    DataStore.save(newObj, tag).then(success, error);
                };

                /**
                 * saveDataWithDelay(newObj) private function
                 * It will create an artificial delay so api isn't called on every character entered
                 * @param newObj is an updated data object
                 */
                var saveDataWithDelay = function (newObj) {
                    if (newObj) {
                        if (isUnchanged(newObj)) {
                            return;
                        }
                        if (tmrDelay) {
                            clearTimeout(tmrDelay);
                        }
                        tmrDelay = setTimeout(function () {
                            if (newObj.default == true) {
                                delete newObj.default;

                                if (newObj.content.rssUrl == _defaultData.content.rssUrl) {
                                    newObj.content.rssUrl = '';
                                    ContentHome.rssFeedUrl = '';
                                }

                            }
                            console.log('0>>>>>', newObj, ContentHome.masterData);
                            saveData(JSON.parse(angular.toJson(newObj)), TAG_NAMES.RSS_FEED_INFO);
                        }, 500);
                    }
                };

                /**
                 * init() private function
                 * It is used to fetch previously saved user's data
                 */
                var init = function () {
                    var success = function (result) {
                            console.info('Init success result:', result);
                            if (Object.keys(result.data).length > 0) {
                                updateMasterItem(result.data);
                                ContentHome.data = result.data;
                            }
                            if (!ContentHome.data) {
                                updateMasterItem(_defaultData);
                                ContentHome.data = angular.copy(_defaultData);
                            } else {
                                if (ContentHome.data.content && !ContentHome.data.content.carouselImages) {
                                    ContentHome.editor.loadItems([]);
                                }
                                else {
                                    ContentHome.editor.loadItems(ContentHome.data.content.carouselImages);
                                }
                                if (ContentHome.data.content.rssUrl)
                                    ContentHome.rssFeedUrl = ContentHome.data.content.rssUrl;
                            }
                            //updateMasterItem(ContentHome.data);
                            if (tmrDelay) {
                                clearTimeout(tmrDelay)
                            }
                        }
                        , error = function (err) {
                            console.error('Error while getting data', err);
                            if (tmrDelay) {
                                clearTimeout(tmrDelay)
                            }

                        };
                    DataStore.get(TAG_NAMES.RSS_FEED_INFO).then(success, error);
                };

                /**
                 * function updateMasterItem(data)
                 * Used to update master data with newly saved user's data object.
                 * @param data is an updated data.
                 */
                function updateMasterItem(data) {
                    ContentHome.masterData = angular.copy(data);
                }

                /**
                 * function isUnchanged(data)
                 * Used to check master data object and updated data object are same or not
                 * @param data
                 * @returns {*|boolean}
                 */
                function isUnchanged(data) {
                    console.log('-1', data, ContentHome.masterData);
                    return angular.equals(data, ContentHome.masterData);
                }

                /**
                 *  updateMasterItem() function invocation to update master data with default data.
                 */
                updateMasterItem(_defaultData);

                /**
                 *  init() function invocation to fetch previously saved user's data from datastore.
                 */
                init();

                /**
                 * ContentHome.editor.onAddItems function will be called when new image item(s) added to carousel image item list.
                 * @param items
                 */
                ContentHome.editor.onAddItems = function (items) {
                    ContentHome.data.content.carouselImages.push.apply(ContentHome.data.content.carouselImages, items);
                    $scope.$digest();
                };

                // this method will be called when an item deleted from the list
                /**
                 * ContentHome.editor.onDeleteItem will be called when an image item deleted from carousel image item list
                 * @param item
                 * @param index
                 */
                ContentHome.editor.onDeleteItem = function (item, index) {
                    ContentHome.data.content.carouselImages.splice(index, 1);
                    $scope.$digest();
                };

                /**
                 * ContentHome.editor.onItemChange function will be called when you edit details of a carousel image item.
                 * @param item
                 * @param index
                 */
                ContentHome.editor.onItemChange = function (item, index) {
                    ContentHome.data.content.carouselImages.splice(index, 1, item);
                    $scope.$digest();
                };

                /**
                 * ContentHome.editor.onOrderChange function will be called when you change the order of image item in the list.
                 * @param item
                 * @param oldIndex
                 * @param newIndex
                 */
                ContentHome.editor.onOrderChange = function (item, oldIndex, newIndex) {
                    var temp = ContentHome.data.content.carouselImages[oldIndex];
                    ContentHome.data.content.carouselImages[oldIndex] = ContentHome.data.content.carouselImages[newIndex];
                    ContentHome.data.content.carouselImages[newIndex] = temp;
                    $scope.$digest();
                };

                /**
                 * ContentHome.validateFeedUrl function will called when you click validate button to check Rss feed url is either valid or not.
                 */
                ContentHome.validateFeedUrl = function () {
                    Buildfire.spinner.show();
                    var success = function () {
                            ContentHome.isValidUrl = true;
                            ContentHome.isValidateButtonClicked = false;
                            ContentHome.data.content.rssUrl = ContentHome.rssFeedUrl;
                            Buildfire.spinner.hide();
                            $timeout(function () {
                                ContentHome.isValidUrl = false;
                            }, 3000);
                        }
                        , error = function () {
                            ContentHome.isInValidUrl = true;
                            ContentHome.isValidateButtonClicked = false;
                            Buildfire.spinner.hide();
                            $timeout(function () {
                                ContentHome.isInValidUrl = false;
                            }, 3000);
                        };
                    ContentHome.isValidateButtonClicked = true;
                    FeedParseService.validateFeedUrl(ContentHome.rssFeedUrl).then(success, error);
                };

                /**
                 * ContentHome.clearData function will called when RSS feed url removed from RSS feed url input box.
                 */
                ContentHome.clearData = function () {
                    if (!ContentHome.rssFeedUrl) {
                        ContentHome.data.content.rssUrl = '';
                    }
                };

                /**
                 * $scope.$watch will Watch for changes in user's data object and trigger the saveDataWithDelay function if data changed
                 */
                $scope.$watch(function () {
                    return ContentHome.data;
                }, saveDataWithDelay, true);
            }]);
})(window.angular);
<|endoftext|>


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

Log = Proto.clone().newSlots({
	exception: null
}).setSlots({
	writeln: function()
	{
		var args = Arguments_asArray(arguments);
		//var now = new Date;
		//args.prepend(now.getFullYear() + "-" + (now.getMonth() + 1) + "-" + now.getDate() + " " + now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds() + "." + now.getMilliseconds())
		util.log(args.join(""));
		if(this.exception())
		{
			writeln(this.exception().stack);
			this.setException(null);
		}
		return this;
	}
})<commit_msg>Update Log.js<commit_after>var util = require('util');

Log = Proto.clone().newSlots({
	exception: null
}).setSlots({
	writeln: function()
	{
		util.log(Arguments_asArray(arguments).join(""));
		var exception = this.exception();
		if(exception)
		{
			writeln(exception.stack || exception);
			this.setException(null);
		}
		return this;
	}
})<|endoftext|>


<commit_before>define(['./dom/collection',
        './dom/traversal',
        './dom/manipulation',
        './dom/style',
        './dom/events',
        './selector',
        './class'],
function(Collection, Traversal, Manipulation, Style, Events, select, klass) {

  klass.augment(Collection, Traversal);
  klass.augment(Collection, Manipulation);
  klass.augment(Collection, Style);
  klass.augment(Collection, Events);

  function dom(nodes) {
    if (typeof nodes == 'string') { nodes = select(nodes) }
    return new Collection(nodes);
  }

  dom.create = function(tag, attrs, content) {
    //var el = dom(document.createElement(tag));
    // TODO: Find a convention for what to return here.  Wrapped DOM node,
    //       or native DOM node?
    var el = document.createElement(tag);
    // TODO: Implement support for this stuff.
    if (attrs) el.attr(attrs);
    if (content) el.html(content);
    return el;
  }

  return dom;
});
<commit_msg>Add temporary fromHTML function.<commit_after>define(['./dom/collection',
        './dom/traversal',
        './dom/manipulation',
        './dom/style',
        './dom/events',
        './selector',
        './class'],
function(Collection, Traversal, Manipulation, Style, Events, select, klass) {

  klass.augment(Collection, Traversal);
  klass.augment(Collection, Manipulation);
  klass.augment(Collection, Style);
  klass.augment(Collection, Events);

  function dom(nodes) {
    if (typeof nodes == 'string') { nodes = select(nodes) }
    return new Collection(nodes);
  }

  dom.create = function(tag, attrs, content) {
    //var el = dom(document.createElement(tag));
    // TODO: Find a convention for what to return here.  Wrapped DOM node,
    //       or native DOM node?
    var el = document.createElement(tag);
    // TODO: Implement support for this stuff.
    if (attrs) el.attr(attrs);
    if (content) el.html(content);
    return el;
  }

  // TODO: This should be handled automatically within create().
  // http://stackoverflow.com/questions/494143/creating-a-new-dom-element-from-an-html-string-using-built-in-dom-methods-or-pro
  dom.fromHTML = function(str) {
    var div = document.createElement('div');
    div.innerHTML = str;
    var elements = div.childNodes;
    return new Collection(elements);
  }

  return dom;
});
<|endoftext|>


<commit_before>import React from 'react';

const CountTo = React.createClass({

  propTypes: {
    from: React.PropTypes.number,
    to: React.PropTypes.number.isRequired,
    speed: React.PropTypes.number.isRequired,
    delay: React.PropTypes.number,
    onComplete: React.PropTypes.func,
    digits: React.PropTypes.number,
    className: React.PropTypes.string
  },

  getInitialState() {
    return {
      counter: this.props.from || 0
    };
  },

  componentDidMount() {
    this.start(this.props);
  },

  componentWillReceiveProps(nextProps) {
    this.start(nextProps);
  },

  componentWillUnmount() {
    this.clear();
  },

  start(props) {
    this.clear();
    this.setState(this.getInitialState(), () => {
      const delay = this.props.delay || 100;
      this.loopsCounter = 0;
      this.loops = Math.ceil(props.speed / delay);
      this.increment = (props.to - this.state.counter) / this.loops;
      this.interval = setInterval(this.next.bind(this, props), delay);
    });
  },

  next(props) {
    if (this.loopsCounter < this.loops) {
      this.loopsCounter++;
      this.setState({
        counter: this.state.counter + this.increment
      });
    } else {
      this.clear();
      if (props.onComplete) {
        props.onComplete();
      }
    }
  },

  clear() {
    clearInterval(this.interval);
  },

  render() {
    return (
      {this.state.counter.toFixed(this.props.digits)}
    );
  }

});

export default CountTo;
<commit_msg>lint error fix<commit_after>import React from 'react';

const CountTo = React.createClass({

  propTypes: {
    from: React.PropTypes.number,
    to: React.PropTypes.number.isRequired,
    speed: React.PropTypes.number.isRequired,
    delay: React.PropTypes.number,
    onComplete: React.PropTypes.func,
    digits: React.PropTypes.number,
    className: React.PropTypes.string
  },

  getInitialState() {
    return {
      counter: this.props.from || 0
    };
  },

  componentDidMount() {
    this.start(this.props);
  },

  componentWillReceiveProps(nextProps) {
    this.start(nextProps);
  },

  componentWillUnmount() {
    this.clear();
  },

  start(props) {
    this.clear();
    this.setState(this.getInitialState(), () => {
      const delay = this.props.delay || 100;
      this.loopsCounter = 0;
      this.loops = Math.ceil(props.speed / delay);
      this.increment = (props.to - this.state.counter) / this.loops;
      this.interval = setInterval(this.next.bind(this, props), delay);
    });
  },

  next(props) {
    if (this.loopsCounter < this.loops) {
      this.loopsCounter++;
      this.setState({
        counter: this.state.counter + this.increment
      });
    } else {
      this.clear();
      if (props.onComplete) {
        props.onComplete();
      }
    }
  },

  clear() {
    clearInterval(this.interval);
  },

  render() {
    return (

        {this.state.counter.toFixed(this.props.digits)}

    );
  }

});

export default CountTo;
<|endoftext|>


<commit_before>var pluralize = require('pluralize');
var q = require('q');
var CollectionService = require('./collection-service.js');
var CaseConverter = require('./case-converter.js');
var caseConverter = new CaseConverter();

/**
 * A tool for interacting with data records
 * @class RecordService
 * @param {Object} provider the datastore provider which handles reads and writes
 * @param {string} type the type of collection to create
 * @param {string} id (optional) the id of the record
 * @returns {Record}
 */
var RecordService = function(provider, type, id) {

  /**
   * Deletes the record
   * @function delete
   * @memberof RecordService
   * @instance
   * @returns {Promise} resolves with no data
   */
  this.delete = deleteRecord;

  /**
   * Returns this record's locally stored data
   * @function getData
   * @memberOf RecordService
   * @instance
   * @return {object}
   */
  this.getData = getData;

  /**
   * Returns this record's type
   * @function getID
   * @memberof RecordService
   * @instance
   * @returns {string}
   */
  this.getID = getID;

  /**
   * Returns this record's type
   * @function getType
   * @memberof RecordService
   * @instance
   * @returns {string}
   */
  this.getType = getType;

  /**
   * Associates related data
   *
   * Deep joins can be performed by passing
   * multiple config objects to this function
   * @function join
   * @memberof RecordService
   * @instance
   * @param {...(Object|Array)} config a map of properties to join on
   * @param {string} config.type the record type to join by
   * @param {boolean} config.many (optional) join with hasMany relation
   * @param {boolean} config.as (optional) join with named relation
   * @returns {Promise} promise resolves with the combined data object
   */
  this.join = join;

  /**
   * Reads the record's data from the datastore
   * @function load
   * @memberof RecordService
   * @instance
   * @returns {Promise} resolves with the record's data
   */
  this.load = load;

  /**
   * Gives this record the ability to link and traverse many related objects
   *
   * After calling this, the record will have addType(record) and
   * getTypes() methods. Example: Calling person.relateToMany('Device') will
   * expose addDevice(device) and getDevices() methods on the person record
   * @function relateToMany
   * @memberof RecordService
   * @instance
   * @param {string} type the type of record this record has many of
   * @param {string} as (optional) the name of the relation
   */
  this.relateToMany = relateToMany;

  /**
   * Gives this record the ability to link and traverse one related object
   *
   * After calling this, the record will have setType(record) and
   * getType() methods. Example: Calling person.relateToOne('Car') will
   * expose setCar(car) and getCar() methods on the person record
   * @function relateToOne
   * @memberof RecordService
   * @instance
   * @param {string} type the type of record this record has one of
   * @param {string} as (optional) the name of the relation
   */
  this.relateToOne = relateToOne;

  /**
   * Stores this record's data in the datastore
   *
   * Sets lastUpdatedAt on every save and
   * createdAt when saving a new record.
   * @function save
   * @memberof RecordService
   * @instance
   * @returns {Promise}
   */
  this.save = save;

  /**
   * Changes the record's data without saving to the datastore
   *
   * Useful for setting data on new records before adding relations
   * @function setData
   * @memberof RecordService
   * @instance
   * @param {Object} data the record's new data
   */
  this.setData = setData;

  /**
   * Syncs the record's data from the datastore
   * @function sync
   * @memberof RecordService
   * @instance
   * @param {Function} onDataChanged the callback that receives updates to the record's data
   * @returns {Promise} resolves with the record's data
   */
  this.sync = sync;

  /**
   * Removes the record's sync listener
   * @function unsync
   * @memberof RecordService
   * @instance
   */
  this.unsync = unsync;

  /**
   * Overwrite the record's data and save in the datastore
   * @function update
   * @memberof RecordService
   * @instance
   * @param {Object} data the record's new data
   * @returns {Promise}
   */
  this.update = update;

  if (!provider) {
    throw new Error('Provider required');
  }
  if (!type) {
    throw new Error('Type required');
  }
  var _provider = provider;
  var _type = caseConverter.toSnakeCase(type);
  var _id = id;
  var _data = {};

  var deletedRecordMessage = 'The record has been deleted';

  function getType() {
    return _type;
  }

  function getID() {
    return _id;
  }

  function getData() {
    return _data;
  }

  function setData(data) {
    var _record = this;
    if (!data) {
      return q.reject(new Error('Data required'));
    }
    var createdAt = _data.createdAt;
    _data = data;
    _data.createdAt = createdAt;
    return _record;
  };

  function save() {
    var record = this;
    if (!_data.createdAt) {
      _data.createdAt = new Date();
    }
    if (_data._id) {
      delete _data._id
    }
    _data.lastUpdatedAt = new Date();
    return _provider.save(pluralize(caseConverter.toCamelCase(_type)), _id, cloneProperties(_data))
      .then(function(id) {
        _id = id;
        return record;
      });
  };

  function update(data) {
    if (!data) {
      return q.reject(new Error('Data required'));
    }
    var createdAt = _data.createdAt;
    _data = data;
    _data.createdAt = createdAt;
    return this.save();
  };

  function load() {
    var deferred = q.defer();
    var _record = this;
    if (!_id) {
      deferred.reject(new Error('Cannot load a record without an id'));
    }
    _provider.load(pluralize(caseConverter.toCamelCase(_type)), _id)
      .then(function(data) {
        if (!data) {
          deferred.reject(new Error('Specified record does not exist remotely'));
          return;
        }
        if (data.deletedAt) {
          deferred.reject(new Error(deletedRecordMessage));
          return;
        }
        _data = data;
        _data._id = _record.getID();
        deferred.resolve(_data);
      }, function(err) {
        deferred.reject(err);
      });
    return deferred.promise;
  };

  function deleteRecord() {
    var deferred = q.defer();
    this.load().then(function(data) {
      _data.deletedAt = new Date();
      save().then(function() {
        deferred.resolve();
      }, function(err) {
        deferred.reject(err);
      });

    }, function(err) {
      this.reject(err);
    });
    return deferred.promise;
  }

  function sync(onDataChanged) {
    if (!_id) {
      return q.reject(new Error('Cannot sync a record without an id'));
    }
    return _provider.sync(pluralize(caseConverter.toCamelCase(_type)), _id, function(data) {
      _data = data;
      onDataChanged(data);
    });
  };

  function unsync() {
    _provider.unsync(pluralize(caseConverter.toCamelCase(_type)), _id);
  }

  function relateToOne(type, as) {
    var _record = this;
    if (as) {
      this['get' + caseConverter.toSnakeCase(as)] = function() {
        var id = _data[caseConverter.toCamelCase(as) + '_id'];
        if (!id) {
          return;
        }
        var record = new RecordService(_provider, type, id);
        return record;
      };
      this['set' + caseConverter.toSnakeCase(as)] = function(record) {
        if (record.getType() !== type) { throw new Error('Invalid type. Expecting "' + type + '", but saw "' + record.getType() + '"'); }
        var id = record.getID();
        _data[caseConverter.toCamelCase(as) + '_id'] = id;
        return _record;
      };
    } else {
      this['get' + caseConverter.toSnakeCase(type)] = function() {
        var id = _data[caseConverter.toCamelCase(type) + '_id'];
        if (!id) {
          return;
        }
        var record = new RecordService(_provider, type, id);
        return record;
      };
      this['set' + caseConverter.toSnakeCase(type)] = function(record) {
        var id = record.getID();
        _data[caseConverter.toCamelCase(record.getType()) + '_id'] = id;
        return _record;
      };
    }
  };

  function relateToMany(type, as) {
    var _record = this;
    var _collection;
    if (as) {
      this['get' + pluralize(caseConverter.toSnakeCase(as))] = function() {
        _collection = new CollectionService(_provider, type);
        if (_data[caseConverter.toCamelCase(as) + '_ids']) {
          var ids = Object.keys(_data[caseConverter.toCamelCase(as) + '_ids']);
          for (var i = 0; i < ids.length; i++) {
            var record = new RecordService(_provider, type, ids[i]);
            _collection.addRecord(record);
          }
        }
        return _collection;
      };
      this['add' + caseConverter.toSnakeCase(as)] = function(record) {
        if (record.getType() !== type) { throw new Error('Invalid type. Expecting "' + type + '", but saw "' + record.getType() + '"'); }
        var id = record.getID();
        var ids = _data[caseConverter.toCamelCase(as) + '_ids'];
        if (!ids) {
          _data[caseConverter.toCamelCase(as) + '_ids'] = {};
        }
        _data[caseConverter.toCamelCase(as) + '_ids'][id] = true;
        return _record;
      };
    } else {
      this['get' + pluralize(caseConverter.toSnakeCase(type))] = function() {
        _collection = new CollectionService(_provider, type);
        if (_data[caseConverter.toCamelCase(type) + '_ids']) {
          var ids = Object.keys(_data[caseConverter.toCamelCase(type) + '_ids']);
          for (var i = 0; i < ids.length; i++) {
            var record = new RecordService(_provider, type, ids[i]);
            _collection.addRecord(record);
          }
        }
        return _collection;
      };
      this['add' + caseConverter.toSnakeCase(type)] = function(record) {
        var id = record.getID();
        var ids = _data[caseConverter.toCamelCase(record.getType()) + '_ids'];
        if (!ids) {
          _data[caseConverter.toCamelCase(record.getType()) + '_ids'] = {};
        }
        _data[caseConverter.toCamelCase(record.getType()) + '_ids'][id] = true;
        return _record;
      };
    }
  };

  function join() {
    var _record = this;
    var args = [].slice.call(arguments);
    var deferred = q.defer();
    var joinConfigs = args.shift();
    if (!Array.isArray(joinConfigs) && joinConfigs) {
      var array = [];
      array.push(joinConfigs);
      joinConfigs = array;
    }
    _record.load()
      .then(function(data) {
        var promises = [];
        if (joinConfigs) {
          for (var i = 0; i < joinConfigs.length; i += 1) {
            (function(type, many, as) {
              var relation;
              if (many) {
                if (as) {
                  _record.relateToMany(type, as);
                  relation = eval('_record.get' + pluralize(caseConverter.toSnakeCase(as)) + '()');
                } else {
                  _record.relateToMany(type);
                  relation = eval('_record.get' + pluralize(caseConverter.toSnakeCase(type)) + '()');
                }
              } else {
                if (as) {
                  _record.relateToOne(type, as);
                  relation = eval('_record.get' + caseConverter.toSnakeCase(as) + '()');
                } else {
                  _record.relateToOne(type);
                  relation = eval('_record.get' + caseConverter.toSnakeCase(type) + '()');
                }
              }
              if (relation) {
                var promise;
                if (args.length === 0) {
                  var loadDeferred = q.defer();
                  relation.load().then(function(data) {
                    loadDeferred.resolve(data);
                  }, function(err) {
                    if (err.message === deletedRecordMessage) {
                      loadDeferred.resolve();
                    } else {
                      loadDeferred.reject(err);
                    }
                  });
                  promise = loadDeferred.promise;
                } else {
                  promise = relation.join.apply(relation, args);
                }
                promise
                  .then(function(relatedData) {
                    if (relatedData) {
                      if (as) {
                        var key = many ? pluralize(caseConverter.toCamelCase(as)) : caseConverter.toCamelCase(as);
                      } else {
                        var key = many ? pluralize(caseConverter.toCamelCase(type)) : caseConverter.toCamelCase(type);
                      }
                      data[key] = relatedData;
                    }
                  });
                promises.push(promise);
              }
            })(joinConfigs[i].type, joinConfigs[i].many, joinConfigs[i].as);
          }
        }
        return q.all(promises)
          .then(function() {
            return data;
          }, function(err) {
            deferred.reject(err);
          });
      }, function(err) {
        deferred.reject(err);
      })
      .then(function(joinedData) {
        if (!joinedData) {
          deferred.reject();
        }
        deferred.resolve(joinedData);
      });
    return deferred.promise;
  };
};

function isDate(object) {
  return Object.prototype.toString.call(object) === '[object Date]'
}

function cloneProperties(obj) {
  if (obj == null || typeof(obj) != 'object' || isDate(obj)) {
    return obj;
  }
  var temp = new obj.constructor();
  for (var key in obj) {
    temp[key] = cloneProperties(obj[key]);
  }
  return temp;
}

module.exports = RecordService;
<commit_msg>docs(record-service.js): fix error in getID doc<commit_after>var pluralize = require('pluralize');
var q = require('q');
var CollectionService = require('./collection-service.js');
var CaseConverter = require('./case-converter.js');
var caseConverter = new CaseConverter();

/**
 * A tool for interacting with data records
 * @class RecordService
 * @param {Object} provider the datastore provider which handles reads and writes
 * @param {string} type the type of collection to create
 * @param {string} id (optional) the id of the record
 * @returns {Record}
 */
var RecordService = function(provider, type, id) {

  /**
   * Deletes the record
   * @function delete
   * @memberof RecordService
   * @instance
   * @returns {Promise} resolves with no data
   */
  this.delete = deleteRecord;

  /**
   * Returns this record's locally stored data
   * @function getData
   * @memberOf RecordService
   * @instance
   * @return {object}
   */
  this.getData = getData;

  /**
   * Returns this record's ID
   * @function getID
   * @memberof RecordService
   * @instance
   * @returns {string}
   */
  this.getID = getID;

  /**
   * Returns this record's type
   * @function getType
   * @memberof RecordService
   * @instance
   * @returns {string}
   */
  this.getType = getType;

  /**
   * Associates related data
   *
   * Deep joins can be performed by passing
   * multiple config objects to this function
   * @function join
   * @memberof RecordService
   * @instance
   * @param {...(Object|Array)} config a map of properties to join on
   * @param {string} config.type the record type to join by
   * @param {boolean} config.many (optional) join with hasMany relation
   * @param {boolean} config.as (optional) join with named relation
   * @returns {Promise} promise resolves with the combined data object
   */
  this.join = join;

  /**
   * Reads the record's data from the datastore
   * @function load
   * @memberof RecordService
   * @instance
   * @returns {Promise} resolves with the record's data
   */
  this.load = load;

  /**
   * Gives this record the ability to link and traverse many related objects
   *
   * After calling this, the record will have addType(record) and
   * getTypes() methods. Example: Calling person.relateToMany('Device') will
   * expose addDevice(device) and getDevices() methods on the person record
   * @function relateToMany
   * @memberof RecordService
   * @instance
   * @param {string} type the type of record this record has many of
   * @param {string} as (optional) the name of the relation
   */
  this.relateToMany = relateToMany;

  /**
   * Gives this record the ability to link and traverse one related object
   *
   * After calling this, the record will have setType(record) and
   * getType() methods. Example: Calling person.relateToOne('Car') will
   * expose setCar(car) and getCar() methods on the person record
   * @function relateToOne
   * @memberof RecordService
   * @instance
   * @param {string} type the type of record this record has one of
   * @param {string} as (optional) the name of the relation
   */
  this.relateToOne = relateToOne;

  /**
   * Stores this record's data in the datastore
   *
   * Sets lastUpdatedAt on every save and
   * createdAt when saving a new record.
   * @function save
   * @memberof RecordService
   * @instance
   * @returns {Promise}
   */
  this.save = save;

  /**
   * Changes the record's data without saving to the datastore
   *
   * Useful for setting data on new records before adding relations
   * @function setData
   * @memberof RecordService
   * @instance
   * @param {Object} data the record's new data
   */
  this.setData = setData;

  /**
   * Syncs the record's data from the datastore
   * @function sync
   * @memberof RecordService
   * @instance
   * @param {Function} onDataChanged the callback that receives updates to the record's data
   * @returns {Promise} resolves with the record's data
   */
  this.sync = sync;

  /**
   * Removes the record's sync listener
   * @function unsync
   * @memberof RecordService
   * @instance
   */
  this.unsync = unsync;

  /**
   * Overwrite the record's data and save in the datastore
   * @function update
   * @memberof RecordService
   * @instance
   * @param {Object} data the record's new data
   * @returns {Promise}
   */
  this.update = update;

  if (!provider) {
    throw new Error('Provider required');
  }
  if (!type) {
    throw new Error('Type required');
  }
  var _provider = provider;
  var _type = caseConverter.toSnakeCase(type);
  var _id = id;
  var _data = {};

  var deletedRecordMessage = 'The record has been deleted';

  function getType() {
    return _type;
  }

  function getID() {
    return _id;
  }

  function getData() {
    return _data;
  }

  function setData(data) {
    var _record = this;
    if (!data) {
      return q.reject(new Error('Data required'));
    }
    var createdAt = _data.createdAt;
    _data = data;
    _data.createdAt = createdAt;
    return _record;
  };

  function save() {
    var record = this;
    if (!_data.createdAt) {
      _data.createdAt = new Date();
    }
    if (_data._id) {
      delete _data._id
    }
    _data.lastUpdatedAt = new Date();
    return _provider.save(pluralize(caseConverter.toCamelCase(_type)), _id, cloneProperties(_data))
      .then(function(id) {
        _id = id;
        return record;
      });
  };

  function update(data) {
    if (!data) {
      return q.reject(new Error('Data required'));
    }
    var createdAt = _data.createdAt;
    _data = data;
    _data.createdAt = createdAt;
    return this.save();
  };

  function load() {
    var deferred = q.defer();
    var _record = this;
    if (!_id) {
      deferred.reject(new Error('Cannot load a record without an id'));
    }
    _provider.load(pluralize(caseConverter.toCamelCase(_type)), _id)
      .then(function(data) {
        if (!data) {
          deferred.reject(new Error('Specified record does not exist remotely'));
          return;
        }
        if (data.deletedAt) {
          deferred.reject(new Error(deletedRecordMessage));
          return;
        }
        _data = data;
        _data._id = _record.getID();
        deferred.resolve(_data);
      }, function(err) {
        deferred.reject(err);
      });
    return deferred.promise;
  };

  function deleteRecord() {
    var deferred = q.defer();
    this.load().then(function(data) {
      _data.deletedAt = new Date();
      save().then(function() {
        deferred.resolve();
      }, function(err) {
        deferred.reject(err);
      });

    }, function(err) {
      this.reject(err);
    });
    return deferred.promise;
  }

  function sync(onDataChanged) {
    if (!_id) {
      return q.reject(new Error('Cannot sync a record without an id'));
    }
    return _provider.sync(pluralize(caseConverter.toCamelCase(_type)), _id, function(data) {
      _data = data;
      onDataChanged(data);
    });
  };

  function unsync() {
    _provider.unsync(pluralize(caseConverter.toCamelCase(_type)), _id);
  }

  function relateToOne(type, as) {
    var _record = this;
    if (as) {
      this['get' + caseConverter.toSnakeCase(as)] = function() {
        var id = _data[caseConverter.toCamelCase(as) + '_id'];
        if (!id) {
          return;
        }
        var record = new RecordService(_provider, type, id);
        return record;
      };
      this['set' + caseConverter.toSnakeCase(as)] = function(record) {
        if (record.getType() !== type) { throw new Error('Invalid type. Expecting "' + type + '", but saw "' + record.getType() + '"'); }
        var id = record.getID();
        _data[caseConverter.toCamelCase(as) + '_id'] = id;
        return _record;
      };
    } else {
      this['get' + caseConverter.toSnakeCase(type)] = function() {
        var id = _data[caseConverter.toCamelCase(type) + '_id'];
        if (!id) {
          return;
        }
        var record = new RecordService(_provider, type, id);
        return record;
      };
      this['set' + caseConverter.toSnakeCase(type)] = function(record) {
        var id = record.getID();
        _data[caseConverter.toCamelCase(record.getType()) + '_id'] = id;
        return _record;
      };
    }
  };

  function relateToMany(type, as) {
    var _record = this;
    var _collection;
    if (as) {
      this['get' + pluralize(caseConverter.toSnakeCase(as))] = function() {
        _collection = new CollectionService(_provider, type);
        if (_data[caseConverter.toCamelCase(as) + '_ids']) {
          var ids = Object.keys(_data[caseConverter.toCamelCase(as) + '_ids']);
          for (var i = 0; i < ids.length; i++) {
            var record = new RecordService(_provider, type, ids[i]);
            _collection.addRecord(record);
          }
        }
        return _collection;
      };
      this['add' + caseConverter.toSnakeCase(as)] = function(record) {
        if (record.getType() !== type) { throw new Error('Invalid type. Expecting "' + type + '", but saw "' + record.getType() + '"'); }
        var id = record.getID();
        var ids = _data[caseConverter.toCamelCase(as) + '_ids'];
        if (!ids) {
          _data[caseConverter.toCamelCase(as) + '_ids'] = {};
        }
        _data[caseConverter.toCamelCase(as) + '_ids'][id] = true;
        return _record;
      };
    } else {
      this['get' + pluralize(caseConverter.toSnakeCase(type))] = function() {
        _collection = new CollectionService(_provider, type);
        if (_data[caseConverter.toCamelCase(type) + '_ids']) {
          var ids = Object.keys(_data[caseConverter.toCamelCase(type) + '_ids']);
          for (var i = 0; i < ids.length; i++) {
            var record = new RecordService(_provider, type, ids[i]);
            _collection.addRecord(record);
          }
        }
        return _collection;
      };
      this['add' + caseConverter.toSnakeCase(type)] = function(record) {
        var id = record.getID();
        var ids = _data[caseConverter.toCamelCase(record.getType()) + '_ids'];
        if (!ids) {
          _data[caseConverter.toCamelCase(record.getType()) + '_ids'] = {};
        }
        _data[caseConverter.toCamelCase(record.getType()) + '_ids'][id] = true;
        return _record;
      };
    }
  };

  function join() {
    var _record = this;
    var args = [].slice.call(arguments);
    var deferred = q.defer();
    var joinConfigs = args.shift();
    if (!Array.isArray(joinConfigs) && joinConfigs) {
      var array = [];
      array.push(joinConfigs);
      joinConfigs = array;
    }
    _record.load()
      .then(function(data) {
        var promises = [];
        if (joinConfigs) {
          for (var i = 0; i < joinConfigs.length; i += 1) {
            (function(type, many, as) {
              var relation;
              if (many) {
                if (as) {
                  _record.relateToMany(type, as);
                  relation = eval('_record.get' + pluralize(caseConverter.toSnakeCase(as)) + '()');
                } else {
                  _record.relateToMany(type);
                  relation = eval('_record.get' + pluralize(caseConverter.toSnakeCase(type)) + '()');
                }
              } else {
                if (as) {
                  _record.relateToOne(type, as);
                  relation = eval('_record.get' + caseConverter.toSnakeCase(as) + '()');
                } else {
                  _record.relateToOne(type);
                  relation = eval('_record.get' + caseConverter.toSnakeCase(type) + '()');
                }
              }
              if (relation) {
                var promise;
                if (args.length === 0) {
                  var loadDeferred = q.defer();
                  relation.load().then(function(data) {
                    loadDeferred.resolve(data);
                  }, function(err) {
                    if (err.message === deletedRecordMessage) {
                      loadDeferred.resolve();
                    } else {
                      loadDeferred.reject(err);
                    }
                  });
                  promise = loadDeferred.promise;
                } else {
                  promise = relation.join.apply(relation, args);
                }
                promise
                  .then(function(relatedData) {
                    if (relatedData) {
                      if (as) {
                        var key = many ? pluralize(caseConverter.toCamelCase(as)) : caseConverter.toCamelCase(as);
                      } else {
                        var key = many ? pluralize(caseConverter.toCamelCase(type)) : caseConverter.toCamelCase(type);
                      }
                      data[key] = relatedData;
                    }
                  });
                promises.push(promise);
              }
            })(joinConfigs[i].type, joinConfigs[i].many, joinConfigs[i].as);
          }
        }
        return q.all(promises)
          .then(function() {
            return data;
          }, function(err) {
            deferred.reject(err);
          });
      }, function(err) {
        deferred.reject(err);
      })
      .then(function(joinedData) {
        if (!joinedData) {
          deferred.reject();
        }
        deferred.resolve(joinedData);
      });
    return deferred.promise;
  };
};

function isDate(object) {
  return Object.prototype.toString.call(object) === '[object Date]'
}

function cloneProperties(obj) {
  if (obj == null || typeof(obj) != 'object' || isDate(obj)) {
    return obj;
  }
  var temp = new obj.constructor();
  for (var key in obj) {
    temp[key] = cloneProperties(obj[key]);
  }
  return temp;
}

module.exports = RecordService;
<|endoftext|>


<commit_before>var inquirer = require('inquirer');
var chalk = require('chalk');
var generateApp = require('./generateApp');

module.exports = function (config) {
    var appName = 'My Amazing App';
    if (config.name) {
        var name = config.name.split(' ')[0];
        name = name.slice(0, 1).toUpperCase() + name.slice(1);
        appName = name + '\'s Amazing App';
    }

    function required(value) {
        return !!value.trim() || 'Required';
    }

    console.log([
        chalk.bold('ampersand.js') + ' - app generator',
        '',
        'This will make a new directory for your app in:',
        chalk.green(process.cwd()),
        '',
    ].join('\n'));

    var questions = [
        {
            name: 'projectFolder',
            message: 'What do you want to call the folder?',
            validate: required
        },
        {
            name: 'title',
            message: 'What is the human friendly title of your app?',
            default: appName,
            filter: function (value) {
                return value.replace('"', '');
            },
            validate: required
        },
        {
            type: 'list',
            name: 'serverFramework',
            message: 'Do you want to use hapi or express as a server framework?',
            default: config.framework || 'hapi',
            choices: ['hapi', 'express']
        },
        {
            name: 'author',
            message: 'What\'s your name? Used to populate "author" field of "package.json"' + chalk.blue('\n\n{\n  "name": "app",\n  "version": "0.0.1",\n  "author": "') + chalk.white('Your answer') + chalk.blue('",\n  "dependencies": ...\n}\n'),
            default: config.name,
            validate: required
        }
    ];

    inquirer.prompt(questions, function (answers) {
        generateApp(answers, function (err) {
            if (err) return console.log(chalk.red('error:'), err);
            console.log([
                '',
                chalk.green(chalk.bold(answers.title) + ' was created!'),
                'now cd to it, install dependencies, and run it:',
                chalk.grey('    $ cd ' + answers.projectFolder + ' && npm install && npm start'),
                ''
            ].join('\n\n'));
            process.stdin.destroy();
        });
    });
};
<commit_msg>Prompt for Author Name at end of multi-line question<commit_after>var inquirer = require('inquirer');
var chalk = require('chalk');
var generateApp = require('./generateApp');

module.exports = function (config) {
    var appName = 'My Amazing App';
    if (config.name) {
        var name = config.name.split(' ')[0];
        name = name.slice(0, 1).toUpperCase() + name.slice(1);
        appName = name + '\'s Amazing App';
    }

    function required(value) {
        return !!value.trim() || 'Required';
    }

    console.log([
        chalk.bold('ampersand.js') + ' - app generator',
        '',
        'This will make a new directory for your app in:',
        chalk.green(process.cwd()),
        '',
    ].join('\n'));

    var questions = [
        {
            name: 'projectFolder',
            message: 'What do you want to call the folder?',
            validate: required
        },
        {
            name: 'title',
            message: 'What is the human friendly title of your app?',
            default: appName,
            filter: function (value) {
                return value.replace('"', '');
            },
            validate: required
        },
        {
            type: 'list',
            name: 'serverFramework',
            message: 'Do you want to use hapi or express as a server framework?',
            default: config.framework || 'hapi',
            choices: ['hapi', 'express']
        },
        {
            name: 'author',
            message: [
                'What\'s your name? Used to populate "author" field of "package.json", as:',
                '',
                chalk.blue('{'),
                chalk.blue('  "name": "app",'),
                chalk.blue('  "version": "0.0.1",'),
                chalk.blue('  "author": "' + chalk.white('Your answer') + '",'),
                chalk.blue('  "dependencies": ...'),
                chalk.blue('}'),
                '',
                chalk.grey('Author Name:')
            ].join('\n'),
            default: config.name,
            validate: required
        }
    ];

    inquirer.prompt(questions, function (answers) {
        generateApp(answers, function (err) {
            if (err) return console.log(chalk.red('error:'), err);
            console.log([
                '',
                chalk.green(chalk.bold(answers.title) + ' was created!'),
                'now cd to it, install dependencies, and run it:',
                chalk.grey('    $ cd ' + answers.projectFolder + ' && npm install && npm start'),
                ''
            ].join('\n\n'));
            process.stdin.destroy();
        });
    });
};
<|endoftext|>


<commit_before>var emojiList = require('../../resources/emoji/emojiList'),
  parse = function (string) {
    // var emojis = string.match(/(:[\w+]+:)/g),
    var emojis = string.match(/(:[\w.&\-\+]+:)/g),
      parsedString = string;

    if (emojis) {
      var regex,
        emojiLabel,
        emojiURL;

      for (var i = 0; i < emojis.length; i++) {
        emojiLabel = emojis[i].replace(/:/g, '');
        regex = new RegExp(':[' + emojiLabel + ']+:', 'g');
        emojiURL = emojiList[emojiLabel];

        if (emojiURL) {
          parsedString = parsedString.replace(regex, '');
        }
      }

      regex = null;
      emojiLabel = null;
      emojiURL = null;
    }

    return parsedString;
  };

module.exports = {
  parse: parse
};
<commit_msg>:bug: Fixes on emoji parse<commit_after>var emojiList = require('../../resources/emoji/emojiList'),
  parse = function (string) {
    var emojis = string.match(/(:[\w.&\-\+]+:)/g),
      parsedString = string;

    if (emojis) {
      var regex,
        emojiLabel,
        emojiURL,
        dictionary = {};

      for (var i = 0; i < emojis.length; i++) {

        if (!dictionary[ emojis[i] ]) {
          emojiLabel = emojis[i].replace(/:/g, '');
          regex = new RegExp(':' + (emojiLabel.replace('+', '\\+').replace('-', '\\-')) + ':', 'g');
          emojiURL = emojiList[emojiLabel];

          if (emojiURL) {
            parsedString = parsedString.replace(regex, '');
          }

          dictionary[ emojis[i] ] = emojis[i];
        }
      }

      regex = null;
      emojiLabel = null;
      emojiURL = null;
      dictionary = null;
    }

    return parsedString;
  };

module.exports = {
  parse: parse
};
<|endoftext|>