<commit_before>/**
 * Controller基类
 * @return {[type]} [description]
 */
var fs = require("fs");
module.exports = Class(function(){
    return {
        init: function(http){
            this.http = http;
            this.view = null;
            //将http数据打到模版里
            this.assign("http", this.http);
            tag('action_start', this.http);
        },
        /**
         * 获取客户端的ip
         * @return {[type]} [description]
         */
        ip: function(){
            return this.http.ip();
        },
        /**
         * 实例化View类
         * @return {[type]} [description]
         */
        initView: function(){
            if (!this.view) {
                this.view = think_require("View")(this.http);
            };
            return this.view;
        },
        /**
         * 是否是GET请求
         * @return {Boolean} [description]
         */
        isGet: function(){
            return this.http.method == 'get';
        },
        /**
         * 是否是POST请求
         * @return {Boolean} [description]
         */
        isPost: function(){
            return this.http.method == 'post';
        },
        /**
         * 是否是特定METHOD请求
         * @param  {[type]}  method [description]
         * @return {Boolean}        [description]
         */
        isMethod: function(method){
            return this.http.method == method;
        },
        /**
         * 是否是AJAX请求
         * @return {Boolean} [description]
         */
        isAjax: function(){
            return this.header("X-Requested-With").toLowerCase() == "xmlhttprequest";
        },
        /**
         * 获取QUERY参数
         * @param  {[type]} name [description]
         * @return {[type]}      [description]
         */
        get: function(name){
            if (name === undefined) {
                return this.http.query;
            };
            return this.http.query[name] || "";
        },
        /**
         * 获取POST参数
         * @param  {[type]} name [description]
         * @return {[type]}      [description]
         */
        post: function(name){
            if (name === undefined) {
                return this.http.post;
            };
            return this.http.post[name] || "";
        },
        /**
         * 获取参数
         * @param  {[type]} name [description]
         * @return {[type]}      [description]
         */
        param: function(name){
            return this.post(name) || this.get(name);
        },
        /**
         * 获取上传的文件
         * @param  {[type]} name [description]
         * @return {[type]}      [description]
         */
        file: function(name){
            return this.http.file[name] || "";
        },
        /**
         * header操作
         * @param  {[type]} name  [description]
         * @param  {[type]} value [description]
         * @return {[type]}       [description]
         */
        header: function(name, value){
            if (value !== undefined) {
                this.http.setHeader(name, value);
                return this;
            };
            if (name === undefined) {
                return this.http.headers;
            };
            return this.http.getHeader(name);
        },
        /**
         * cookie操作
         * @param  {[type]} name    [description]
         * @param  {[type]} value   [description]
         * @param  {[type]} options [description]
         * @return {[type]}         [description]
         */
        cookie: function(name, value, options){
            if (value !== undefined) {
                this.http.setCookie(name, value, options);
                return this;
            };
            if (name === undefined) {
                return this.http.cookie;
            };
            return this.http.cookie[name];
        },
        /**
         * session
         * 如果是get操作，则返回一个promise
         * @param  {[type]} name  [description]
         * @param  {[type]} value [description]
         * @return {[type]}       [description]
         */
        session: function(name, value){
            think_require('Session').start(this.http);
            var instance = this.http.session;
            if (name === undefined) {
                return instance.rm();
            };
            if (value !== undefined) {
                instance.set(name, value);
                return this;
            };
            return instance.get(name);
        },
        /**
         * 跳转
         * @param  {[type]} url  [description]
         * @param  {[type]} code [description]
         * @return {[type]}      [description]
         */
        redirect: function(url, code){
            this.http.res.statusCode = code || 302;
            this.http.res.setHeader("Location", url);
            this.http.end();
        },
        /**
         * 赋值变量到模版
         * @param  {[type]} name  [description]
         * @param  {[type]} value [description]
         * @return {[type]}       [description]
         */
        assign: function(name, value){
            this.initView().assign(name, value);
            return this;
        },
        /**
         * 获取解析后的模版内容
         * @param  {[type]} templateFile [description]
         * @param  {[type]} content      [description]
         * @return {[type]}              [description]
         */
        fetch: function(templateFile, content){
            return this.initView().fetch(templateFile, content);
        },
        /**
         * 输出模版内容
         * @param  {[type]} templateFile [description]
         * @param  {[type]} charset      [description]
         * @param  {[type]} contentType  [description]
         * @param  {[type]} content      [description]
         * @return {[type]}              [description]
         */
        display: function(templateFile, charset, contentType, content){
            return this.initView().display(templateFile, charset, contentType, content);
        },
        /**
         * 输出错误
         * @param  {[type]} msg [description]
         * @return {[type]}     [description]
         */
        error: function(msg){
            throw_error(msg, this.http);
        },
        /**
         * 调用另一个controll里的aciton
         * 可以跨分组
         * A("Home/Test/index")
         * @param  {[type]} action [description]
         * @return {[type]}        [description]
         */
        action: function(action){
            A(action, this.http);
        },
        /**
         * json格式输出，并且支持jsonp的方式
         * @param  {[type]} data  [description]
         * @param  {[type]} jsonp [description]
         * @return {[type]}       [description]
         */
        json: function(data, jsonp){
            this.header("Content-Type", C("json_content_type") + ";charset=" + C("charset"));
            //标记content-type的header已经发送
            this.http.sendContentType = true;
            var callback = this.get(C("url_callback_name"));
            callback = callback.replace(/[^\w\.]/g, "");
            if (jsonp && callback) {
                this.echo(callback + "(");
                this.echo(data);
                this.end(")");
            }else{
                this.end(data);
            }
        },
        /**
         * 输出内容
         * 自动JSON.stringify
         * 自定将数字等转化为字符串
         * @param  {[type]} obj [description]
         * @return {[type]}     [description]
         */
        echo: function(obj, encoding){
            //自动发送Content-Type的header
            if (C('auto_send_content_type') && !this.http.sendContentType) {
                this.header("Content-Type", C("tpl_content_type") + ";charset=" + C("charset"));
                this.http.sendContentType = true;
            };
            if (is_array(obj) || is_object(obj)) {
                obj = JSON.stringify(obj);
            };
            if (!is_string(obj) && !(obj instanceof Buffer)) {
                obj += "";
            };
            this.http.res.write(obj, encoding || C('encoding'));
        },
        /**
         * 结束输出，输出完成时一定要调用这个方法
         * @param  {[type]} obj [description]
         * @return {[type]}     [description]
         */
        end: function(obj){
            if (obj) {
                this.echo(obj);
            };
            this.http.end();
        },
        /**
         * 下载文件
         * @return {[type]} [description]
         */
        download: function(file, contentType){
            if (!contentType) {
                var mime = require('mime');
                contentType = mime.lookup(file);
            };
            var http = this.http;
            var fileStream = fs.createReadStream(file);
            http.setHeader("Content-Type", contentType);
            fileStream.pipe(http.res);
            fileStream.on("end", function(){
                http.end();
            })
        },
        /**
         * 校验一个值是否合法
         * @param  {[type]} data      [description]
         * @param  {[type]} validType [description]
         * @return {[type]}           [description]
         */
        valid: function(data, validType){
            //单个值检测，只返回是否正常
            if (validType !== undefined) {
                data = {
                    value: data,
                    valid: validType
                };
                var result = think_require("Valid").check(data);
                return result.length == 0;
            };
            return think_require("Valid").check(data);
        }
    }
});<commit_msg>fix #4.<commit_after>/**
 * Controller基类
 * @return {[type]} [description]
 */
var fs = require("fs");
module.exports = Class(function(){
    return {
        init: function(http){
            this.http = http;
            this.view = null;
            //将http数据打到模版里
            this.assign("http", this.http);
            tag('action_start', this.http);
        },
        /**
         * 获取客户端的ip
         * @return {[type]} [description]
         */
        ip: function(){
            return this.http.ip();
        },
        /**
         * 实例化View类
         * @return {[type]} [description]
         */
        initView: function(){
            if (!this.view) {
                this.view = think_require("View")(this.http);
            };
            return this.view;
        },
        /**
         * 是否是GET请求
         * @return {Boolean} [description]
         */
        isGet: function(){
            return this.http.method == 'get';
        },
        /**
         * 是否是POST请求
         * @return {Boolean} [description]
         */
        isPost: function(){
            return this.http.method == 'post';
        },
        /**
         * 是否是特定METHOD请求
         * @param  {[type]}  method [description]
         * @return {Boolean}        [description]
         */
        isMethod: function(method){
            return this.http.method == method;
        },
        /**
         * 是否是AJAX请求
         * @return {Boolean} [description]
         */
        isAjax: function(){
            return this.header("X-Requested-With").toLowerCase() == "xmlhttprequest";
        },
        /**
         * 获取QUERY参数
         * @param  {[type]} name [description]
         * @return {[type]}      [description]
         */
        get: function(name){
            if (name === undefined) {
                return this.http.query;
            };
            return this.http.query[name] || "";
        },
        /**
         * 获取POST参数
         * @param  {[type]} name [description]
         * @return {[type]}      [description]
         */
        post: function(name){
            if (name === undefined) {
                return this.http.post;
            };
            return this.http.post[name] || "";
        },
        /**
         * 获取参数
         * @param  {[type]} name [description]
         * @return {[type]}      [description]
         */
        param: function(name){
            return this.post(name) || this.get(name);
        },
        /**
         * 获取上传的文件
         * @param  {[type]} name [description]
         * @return {[type]}      [description]
         */
        file: function(name){
            return this.http.file[name] || "";
        },
        /**
         * header操作
         * @param  {[type]} name  [description]
         * @param  {[type]} value [description]
         * @return {[type]}       [description]
         */
        header: function(name, value){
            if (is_object(name)) {
                for(var key in name){
                    this.header(key, name[key]);
                }
                return this;
            };
            if (value !== undefined) {
                if (name.toLowerCase() == 'content-type') {
                    this.http.sendContentType = true;
                };
                this.http.setHeader(name, value);
                return this;
            };
            if (name === undefined) {
                return this.http.headers;
            };
            return this.http.getHeader(name);
        },
        /**
         * cookie操作
         * @param  {[type]} name    [description]
         * @param  {[type]} value   [description]
         * @param  {[type]} options [description]
         * @return {[type]}         [description]
         */
        cookie: function(name, value, options){
            if (value !== undefined) {
                this.http.setCookie(name, value, options);
                return this;
            };
            if (name === undefined) {
                return this.http.cookie;
            };
            return this.http.cookie[name];
        },
        /**
         * session
         * 如果是get操作，则返回一个promise
         * @param  {[type]} name  [description]
         * @param  {[type]} value [description]
         * @return {[type]}       [description]
         */
        session: function(name, value){
            think_require('Session').start(this.http);
            var instance = this.http.session;
            if (name === undefined) {
                return instance.rm();
            };
            if (value !== undefined) {
                instance.set(name, value);
                return this;
            };
            return instance.get(name);
        },
        /**
         * 跳转
         * @param  {[type]} url  [description]
         * @param  {[type]} code [description]
         * @return {[type]}      [description]
         */
        redirect: function(url, code){
            this.http.res.statusCode = code || 302;
            this.http.res.setHeader("Location", url);
            this.http.end();
        },
        /**
         * 赋值变量到模版
         * @param  {[type]} name  [description]
         * @param  {[type]} value [description]
         * @return {[type]}       [description]
         */
        assign: function(name, value){
            this.initView().assign(name, value);
            return this;
        },
        /**
         * 获取解析后的模版内容
         * @param  {[type]} templateFile [description]
         * @param  {[type]} content      [description]
         * @return {[type]}              [description]
         */
        fetch: function(templateFile, content){
            return this.initView().fetch(templateFile, content);
        },
        /**
         * 输出模版内容
         * @param  {[type]} templateFile [description]
         * @param  {[type]} charset      [description]
         * @param  {[type]} contentType  [description]
         * @param  {[type]} content      [description]
         * @return {[type]}              [description]
         */
        display: function(templateFile, charset, contentType, content){
            return this.initView().display(templateFile, charset, contentType, content);
        },
        /**
         * 输出错误
         * @param  {[type]} msg [description]
         * @return {[type]}     [description]
         */
        error: function(msg){
            throw_error(msg, this.http);
        },
        /**
         * 调用另一个controll里的aciton
         * 可以跨分组
         * A("Home/Test/index")
         * @param  {[type]} action [description]
         * @return {[type]}        [description]
         */
        action: function(action){
            A(action, this.http);
        },
        /**
         * json格式输出，并且支持jsonp的方式
         * @param  {[type]} data  [description]
         * @param  {[type]} jsonp [description]
         * @return {[type]}       [description]
         */
        json: function(data, jsonp){
            this.header("Content-Type", C("json_content_type") + ";charset=" + C("charset"));
            var callback = this.get(C("url_callback_name"));
            //过滤callback值里的非法字符
            callback = callback.replace(/[^\w\.]/g, "");
            if (jsonp && callback) {
                this.echo(callback + "(");
                this.echo(data);
                this.end(")");
            }else{
                this.end(data);
            }
        },
        /**
         * 输出内容
         * 自动JSON.stringify
         * 自定将数字等转化为字符串
         * @param  {[type]} obj [description]
         * @return {[type]}     [description]
         */
        echo: function(obj, encoding){
            //自动发送Content-Type的header
            if (C('auto_send_content_type') && !this.http.sendContentType) {
                this.header("Content-Type", C("tpl_content_type") + ";charset=" + C("charset"));
            };
            if (is_array(obj) || is_object(obj)) {
                obj = JSON.stringify(obj);
            };
            if (!is_string(obj) && !(obj instanceof Buffer)) {
                obj += "";
            };
            this.http.res.write(obj, encoding || C('encoding'));
        },
        /**
         * 结束输出，输出完成时一定要调用这个方法
         * @param  {[type]} obj [description]
         * @return {[type]}     [description]
         */
        end: function(obj){
            if (obj) {
                this.echo(obj);
            };
            this.http.end();
        },
        /**
         * 下载文件
         * @return {[type]} [description]
         */
        download: function(file, contentType){
            if (!contentType) {
                var mime = require('mime');
                contentType = mime.lookup(file);
            };
            var http = this.http;
            var fileStream = fs.createReadStream(file);
            http.setHeader("Content-Type", contentType);
            fileStream.pipe(http.res);
            fileStream.on("end", function(){
                http.end();
            })
        },
        /**
         * 校验一个值是否合法
         * @param  {[type]} data      [description]
         * @param  {[type]} validType [description]
         * @return {[type]}           [description]
         */
        valid: function(data, validType){
            //单个值检测，只返回是否正常
            if (validType !== undefined) {
                data = {
                    value: data,
                    valid: validType
                };
                var result = think_require("Valid").check(data);
                return result.length == 0;
            };
            return think_require("Valid").check(data);
        }
    }
});<|endoftext|>


<commit_before>'use strict';
const app = require('app');
const BrowserWindow = require('browser-window');
const path = require('path')
const fs = require('fs')

// report crashes to the Electron project
require('crash-reporter').start();

// adds debug features like hotkeys for triggering dev tools and reload
require('electron-debug')();

// WHITELABELING OPTIONS
var options = {
	page_title: 'Aufbau' // What do you want to display in the menu bar?
}

function createMainWindow () {
	const win = new BrowserWindow({
		width: 1280,
		height: 768,
		resizable: true,
		title: options.page_title
	});

	// Set the download directory to being off of the user's home folder
	var tilde_downloads = path.join(app.getHomeDir(), 'Downloads')
	win.webContents.session.setDownloadPath(tilde_downloads)

	// Whenever we finish loading a page, inject some javascript into it to add our back button
	// Don't do this if we're on the main page, though
	win.webContents.on('did-finish-load', function (webContents) {
		var page_title = webContents.sender.getTitle()
		var index_path
		var home_btn_css
		var home_btn_js
		if (page_title != 'index.html') {
			// Add css
			home_btn_css = fs.readFileSync(path.join(__dirname, 'home-btn.css'), 'utf-8')
			webContents.sender.insertCSS(home_btn_css)

			// Add home button
			index_path = path.join(__dirname, 'www', 'index.html')
			home_btn_js = fs.readFileSync(path.join(__dirname, 'home-btn.jst'), 'utf-8').replace('{{index_path}}', index_path)
			webContents.sender.executeJavaScript(home_btn_js)
		}
	})

	win.loadUrl(`file://${__dirname}/www/index.html`);
	win.on('closed', onClosed);

	return win;
}

function onClosed() {
	// deref the window
	// for multiple windows store them in an array
	mainWindow = null;
}

// prevent window being GC'd
let mainWindow;

app.on('window-all-closed', function () {
	if (process.platform !== 'darwin') {
		app.quit();
	}
});

app.on('activate-with-no-open-windows', function () {
	if (!mainWindow) {
		mainWindow = createMainWindow();
	}
});

app.on('ready', function () {
	var Menu = require('menu');
	var menu_template = require('./menus.js')(BrowserWindow)
	var menu = Menu.buildFromTemplate(menu_template);
	Menu.setApplicationMenu(menu);

	mainWindow = createMainWindow();
});
<commit_msg>allow for sending of app data<commit_after>'use strict';
const app = require('app');
const BrowserWindow = require('browser-window');
const path = require('path')
const fs = require('fs')
const ipc = require('ipc')

// report crashes to the Electron project
require('crash-reporter').start();

// adds debug features like hotkeys for triggering dev tools and reload
require('electron-debug')();

// WHITELABELING OPTIONS
var options = {
	page_title: 'Aufbau' // What do you want to display in the menu bar?
}

function createMainWindow () {
	const win = new BrowserWindow({
		width: 1280,
		height: 768,
		resizable: true,
		title: options.page_title
	});

	// Set the download directory to being off of the user's home folder
	var tilde_downloads = path.join(app.getHomeDir(), 'Downloads')
	win.webContents.session.setDownloadPath(tilde_downloads)

	// console.log(win.webContents)

	// Send the location of the user data folder to the client
	ipc.on('synchronous-message', function(event, arg) {
		console.log(arg);  // prints 'userData'
		event.returnValue = app.getPath(arg)
	});

	win.webContents.on('did-finish-load', function (webContents) {
		var page_title = webContents.sender.getTitle()
		var index_path
		var home_btn_css
		var home_btn_js
		if (page_title != 'index.html') {
			// Add css
			home_btn_css = fs.readFileSync(path.join(__dirname, 'home-btn.css'), 'utf-8')
			webContents.sender.insertCSS(home_btn_css)

			// Add home button
			index_path = path.join(__dirname, 'www', 'index.html')
			home_btn_js = fs.readFileSync(path.join(__dirname, 'home-btn.jst'), 'utf-8').replace('{{index_path}}', index_path)
			webContents.sender.executeJavaScript(home_btn_js)

		}
	})

	win.loadUrl(`file://${__dirname}/www/index.html`);
	win.on('closed', onClosed);

	return win;
}

function onClosed() {
	// deref the window
	// for multiple windows store them in an array
	mainWindow = null;
}

// prevent window being GC'd
let mainWindow;

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

app.on('activate-with-no-open-windows', function () {
	if (!mainWindow) {
		mainWindow = createMainWindow();
	}
});

app.on('ready', function () {
	var Menu = require('menu');
	var menu_template = require('./menus.js')(BrowserWindow)
	var menu = Menu.buildFromTemplate(menu_template);
	Menu.setApplicationMenu(menu);

	mainWindow = createMainWindow();
});
<|endoftext|>


<commit_before>import React, { PureComponent } from 'react'
import {
  StyleSheet,
  Dimensions,
  ScrollView,
  View,
} from 'react-native'
import Mirror, { scrollviewBootstrap } from 'react-native-mirror'

const VIEWPORT_WIDTH = Dimensions.get('window').width

class ViewPager extends PureComponent {

  static defaultProps = {
    thresholdPages: 1,
    pageWidth: VIEWPORT_WIDTH,
    pagingEnabled: true,
    contentContainerStyle: {},
    renderRow: () => {},
    onPan: () => {},
    onPageChange: () => {},
    onScroll: () => {},
    disablePan: false,
    data: [],
    experimentalMirroring: false,
    showNativeScrollIndicator: false,
  }

  constructor(props) {
    super(props)

    this._pageWithDelta = (VIEWPORT_WIDTH - this.props.pageWidth) / 2

    this.pages = []

    this.state = {
      dataSource: [...this._prepareData(this.props.data || [])],
    }
  }

  componentDidMount() {
    setTimeout(() => {
      this.scrollView.scrollTo({
        x: (VIEWPORT_WIDTH - this._pageWithDelta) * this.props.thresholdPages,
        animated: false,
      })
    }, 0)
  }

  _initializeData = (data) => {
    return data.map((data, index) => {
      return Object.assign({}, data, { _pageIndex: index + 1 })
    })
  }

  _prepareData = (data) => {

    const multiplicator = Math.ceil(this.props.thresholdPages / data.length)

    const initializedData = this._initializeData(data)

    let thresholdDataFront = []
    let thresholdDataEnd = []

    for (let i = 0; i < multiplicator; i++) {
      thresholdDataFront = [...thresholdDataFront, ...[...initializedData].reverse()]
      thresholdDataEnd = [...thresholdDataEnd, ...initializedData]
    }

    const thresholdFront = thresholdDataFront.slice(0, this.props.thresholdPages).reverse()

    const thresholdEnd = thresholdDataEnd.slice(0, this.props.thresholdPages)

    const preparedData = [...thresholdFront, ...initializedData, ...thresholdEnd]

    return [...preparedData]
  }

  _getPageNumberByIndex = index => {
    if (index === 0) return this.state.dataSource.length - 1
    if (index === this.state.dataSource.length - 1) return 1
    return index
  }

  _onScroll = (event) => {
    const offsetX = event.nativeEvent.contentOffset.x
    this.props.onScroll(offsetX)

    this.pageIndex = Math.ceil((offsetX / VIEWPORT_WIDTH) * 100) / 100

    if (this.pageIndex % 1 === 0) {
      if (this.pageIndex === 0) {

        this.scrollView.scrollTo({
          animated: false,
          x: VIEWPORT_WIDTH * (this.state.dataSource.length - 2),
        })

      } else if (this.pageIndex === this.state.dataSource.length - 1) {

        this.scrollView.scrollTo({
          animated: false,
          x: VIEWPORT_WIDTH,
        })

      } else {

        const pageNumber = this._getPageNumberByIndex(this.pageIndex)
        this.props.onPageChange(pageNumber)

      }
    }
  }

  scroll = dx => {
    this.scrollView.scrollTo({
      animated: false,
      x: dx / (VIEWPORT_WIDTH / (VIEWPORT_WIDTH / 2)) - this.props.pageWidth / 2 + (VIEWPORT_WIDTH / this.props.thresholdPages),
    })
  }

  scrollToPage = pageNumber => {
    this.scrollView.scrollTo({
      animated: true,
      x: (pageNumber + this.props.thresholdPages) * VIEWPORT_WIDTH,
    })
  }

  _renderRow = (item, index) => {

    let row = (
      <View
        key={index}
        style={[styles.rowContainer, {
          width: this.props.pageWidth,
        }]}
      >
        {this.props.renderRow({data: item, _pageIndex: item._pageIndex})}
      </View>
    )

    if (this.props.experimentalMirroring === true) {
      if (index <= this.props.thresholdPages) {
        row = (
          <Mirror
            key={index}
            connectionId={'mirror-' + index}
            containerStyle={styles.mirror}
            mirroredProps={[
              scrollviewBootstrap,
            ]}
          >
            {row}
          </Mirror>
        )
      }

      if (index >= this.state.dataSource.length - this.props.thresholdPages - 1) {
        const idIndex = index - (this.state.dataSource.length - this.props.thresholdPages - 1)
        row = (
          <Mirror
            key={index}
            connectionId={'mirror-' + idIndex}
            containerStyle={styles.mirror}
            mirroredProps={[
              scrollviewBootstrap,
            ]}
          >
            {row}
          </Mirror>
        )
      }
    }

    return row
  }

  render() {
    this.pages = []
    return (
      <View style={this.props.containerStyle}>
        <ScrollView
          ref={(scrollView) => {
            this.scrollView = scrollView
          }}
          horizontal={true}
          pagingEnabled={this.props.pagingEnabled}
          showsHorizontalScrollIndicator={this.props.showNativeScrollIndicator}
          showsVerticalScrollIndicator={this.props.showNativeScrollIndicator}
          onScroll={this._onScroll}
          contentContainerStyle={[styles.container, this.props.contentContainerStyle, {
            width: this.props.pageWidth * this.state.dataSource.length,
          }]}>

          {this.state.dataSource.map((item, index) => {
            return this._renderRow(item, index)
          })}
        </ScrollView>
      </View>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    flexDirection: 'row',
    /*
     * bug in react-native
     * overflow style has to be set
     * https://github.com/facebook/react-native/issues/12926
     */
    overflow: 'scroll',
  },
  rowContainer: {
    flexGrow: 1,
  },
  mirror: {
    flexGrow: 1,
  },
})

ViewPager.propTypes = {
  contentContainerStyle: React.PropTypes.any,
  containerStyle: React.PropTypes.any,
  data: React.PropTypes.arrayOf(
    React.PropTypes.object
  ),
  thresholdPages: React.PropTypes.number,
  pageWidth: React.PropTypes.number,
  disablePan: React.PropTypes.bool,
  pagingEnabled: React.PropTypes.bool,
  experimentalMirroring: React.PropTypes.bool,
  showNativeScrollIndicator: React.PropTypes.bool,

  renderRow: React.PropTypes.func,
  onPageChange: React.PropTypes.func,
  onPan: React.PropTypes.func,
  onShouldSwitchToPage: React.PropTypes.func,
  onScroll: React.PropTypes.func,
}

export default ViewPager<commit_msg>implemented componentWillReceiveProps in <ViewPager /><commit_after>import React, { PureComponent } from 'react'
import {
  StyleSheet,
  Dimensions,
  ScrollView,
  View,
} from 'react-native'
import Mirror, { scrollviewBootstrap } from 'react-native-mirror'

const VIEWPORT_WIDTH = Dimensions.get('window').width

class ViewPager extends PureComponent {

  static defaultProps = {
    thresholdPages: 1,
    pageWidth: VIEWPORT_WIDTH,
    pagingEnabled: true,
    contentContainerStyle: {},
    renderRow: () => {},
    onPan: () => {},
    onPageChange: () => {},
    onScroll: () => {},
    disablePan: false,
    data: [],
    experimentalMirroring: false,
    showNativeScrollIndicator: false,
  }

  constructor(props) {
    super(props)

    this._pageWithDelta = (VIEWPORT_WIDTH - this.props.pageWidth) / 2

    this.pages = []

    this.state = {
      dataSource: [...this._prepareData(this.props.data || [])],
    }
  }

  componentDidMount() {
    setTimeout(() => {
      this.scrollView.scrollTo({
        x: (VIEWPORT_WIDTH - this._pageWithDelta) * this.props.thresholdPages,
        animated: false,
      })
    }, 0)
  }

  componentWillReceiveProps(nextProps) {
    this.setState({
      dataSource: [...this._prepareData(nextProps.data || [])],
    })
  }

  _initializeData = (data) => {
    return data.map((data, index) => {
      return Object.assign({}, data, { _pageIndex: index + 1 })
    })
  }

  _prepareData = (data) => {

    const multiplicator = Math.ceil(this.props.thresholdPages / data.length)

    const initializedData = this._initializeData(data)

    let thresholdDataFront = []
    let thresholdDataEnd = []

    for (let i = 0; i < multiplicator; i++) {
      thresholdDataFront = [...thresholdDataFront, ...[...initializedData].reverse()]
      thresholdDataEnd = [...thresholdDataEnd, ...initializedData]
    }

    const thresholdFront = thresholdDataFront.slice(0, this.props.thresholdPages).reverse()

    const thresholdEnd = thresholdDataEnd.slice(0, this.props.thresholdPages)

    const preparedData = [...thresholdFront, ...initializedData, ...thresholdEnd]

    return [...preparedData]
  }

  _getPageNumberByIndex = index => {
    if (index === 0) return this.state.dataSource.length - 1
    if (index === this.state.dataSource.length - 1) return 1
    return index
  }

  _onScroll = (event) => {
    const offsetX = event.nativeEvent.contentOffset.x
    this.props.onScroll(offsetX)

    this.pageIndex = Math.ceil((offsetX / VIEWPORT_WIDTH) * 100) / 100

    if (this.pageIndex % 1 === 0) {
      if (this.pageIndex === 0) {

        this.scrollView.scrollTo({
          animated: false,
          x: VIEWPORT_WIDTH * (this.state.dataSource.length - 2),
        })

      } else if (this.pageIndex === this.state.dataSource.length - 1) {

        this.scrollView.scrollTo({
          animated: false,
          x: VIEWPORT_WIDTH,
        })

      } else {

        const pageNumber = this._getPageNumberByIndex(this.pageIndex)
        this.props.onPageChange(pageNumber)

      }
    }
  }

  scroll = dx => {
    this.scrollView.scrollTo({
      animated: false,
      x: dx / (VIEWPORT_WIDTH / (VIEWPORT_WIDTH / 2)) - this.props.pageWidth / 2 + (VIEWPORT_WIDTH / this.props.thresholdPages),
    })
  }

  scrollToPage = pageNumber => {
    this.scrollView.scrollTo({
      animated: true,
      x: (pageNumber + this.props.thresholdPages) * VIEWPORT_WIDTH,
    })
  }

  _renderRow = (item, index) => {

    let row = (
      <View
        key={index}
        style={[styles.rowContainer, {
          width: this.props.pageWidth,
        }]}
      >
        {this.props.renderRow({data: item, _pageIndex: item._pageIndex})}
      </View>
    )

    if (this.props.experimentalMirroring === true) {
      if (index <= this.props.thresholdPages) {
        row = (
          <Mirror
            key={index}
            connectionId={'mirror-' + index}
            containerStyle={styles.mirror}
            mirroredProps={[
              scrollviewBootstrap,
            ]}
          >
            {row}
          </Mirror>
        )
      }

      if (index >= this.state.dataSource.length - this.props.thresholdPages - 1) {
        const idIndex = index - (this.state.dataSource.length - this.props.thresholdPages - 1)
        row = (
          <Mirror
            key={index}
            connectionId={'mirror-' + idIndex}
            containerStyle={styles.mirror}
            mirroredProps={[
              scrollviewBootstrap,
            ]}
          >
            {row}
          </Mirror>
        )
      }
    }

    return row
  }

  render() {
    this.pages = []
    return (
      <View style={this.props.containerStyle}>
        <ScrollView
          ref={(scrollView) => {
            this.scrollView = scrollView
          }}
          horizontal={true}
          pagingEnabled={this.props.pagingEnabled}
          showsHorizontalScrollIndicator={this.props.showNativeScrollIndicator}
          showsVerticalScrollIndicator={this.props.showNativeScrollIndicator}
          onScroll={this._onScroll}
          contentContainerStyle={[styles.container, this.props.contentContainerStyle, {
            width: this.props.pageWidth * this.state.dataSource.length,
          }]}>

          {this.state.dataSource.map((item, index) => {
            return this._renderRow(item, index)
          })}
        </ScrollView>
      </View>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    flexDirection: 'row',
    /*
     * bug in react-native
     * overflow style has to be set
     * https://github.com/facebook/react-native/issues/12926
     */
    overflow: 'scroll',
  },
  rowContainer: {
    flexGrow: 1,
  },
  mirror: {
    flexGrow: 1,
  },
})

ViewPager.propTypes = {
  contentContainerStyle: React.PropTypes.any,
  containerStyle: React.PropTypes.any,
  data: React.PropTypes.arrayOf(
    React.PropTypes.object
  ),
  thresholdPages: React.PropTypes.number,
  pageWidth: React.PropTypes.number,
  disablePan: React.PropTypes.bool,
  pagingEnabled: React.PropTypes.bool,
  experimentalMirroring: React.PropTypes.bool,
  showNativeScrollIndicator: React.PropTypes.bool,

  renderRow: React.PropTypes.func,
  onPageChange: React.PropTypes.func,
  onPan: React.PropTypes.func,
  onShouldSwitchToPage: React.PropTypes.func,
  onScroll: React.PropTypes.func,
}

export default ViewPager<|endoftext|>


<commit_before>var events = require('events');
var fs = require('fs');
var path = require('path'), basename = path.basename;
var util = require('util');
var camelcase = require('cli-util').camelcase;

var mutators = {
  cmd: {
    options: false,
    commands: false,
    names: false,
    key: true,
    name: true,
    description: true,
    action: true,
    last: true
  },
  arg: {
    names: false,
    key: true,
    name: true,
    optional: true,
    multiple: true,
    value: true,
    converter: true,
    extra: true,
    description: true,
    action: true
  },
  prg: {
    converter: true
  }
}

var k, keys;
var re = {
  delimiter: function(){return /[ ,|]+/;},
  required: function(){return /^=?</;},
  multiple: function(){return /\.\.\./;},
  extra: function(){return /^([^=\[<]*)((=|\[|<).*)/;},
  no: function(){return /(\[no-?\]-?)/;}
}

function initialize(options, properties) {
  for(var z in options) {
    if(~properties.indexOf(z) && options[z]) this[z](options[z]);
  }
}

/**
 *  Retrieve the key for an option.
 *
 *  Scope is the option. Alternatively you may pass a
 *  string of the raw name passed when instantiating the options.
 *
 *  @param names Array of names or raw string name (optional).
 */
function getKey(names, name) {
  var k, names = names || this._names;
  name = name || this._name;
  if(typeof names == 'string') {
    name = names;
    names = names.split(re.delimiter());
  }
  names = names.slice(0);
  if(this._extra) {
    var j = names.length -1;
    var nm = names[j];
    while(re.extra().test(nm) || re.multiple().test(nm)) {
      // allow for flush extra values
      if(/^-+/.test(nm)) {
        names[j] = nm.replace(re.extra(), "$1");
      }else{
        names.pop();
      }
      nm = names[--j];
    }
    this._names = sortNames(names);
  }
  var k = names.reduce(
    function (a, b) { return a.length > b.length ? a : b; });
  k = k.replace(/^-+/, '');
  return camelcase(k.toLowerCase());
}

function sortNames(names) {
  // sort short options before long options
  return names.sort(function(a, b) {
    var re = /^-[^-]/;
    return re.test(a) ? -1 : re.test(b) ? 1 : 0;
  });
}

/**
 *  Retrieve the extra portion of the option name.
 *
 *  Note this also updates the names array to not include
 *  the extra portion.
 */
function getExtra() {
  if(re.no().test(this._name)) {
    this._extra = false;
    return;
  }
  if(!re.extra().test(this._name)) return;
  this._extra = this._name.replace(re.extra(), "$2");
  //console.log(this._extra);
  var name = this._name.replace(re.extra(), "$1");
  //console.log('name: %s', name);
  this._names = name.split(re.delimiter());
  if(!this._names[this._names.length - 1]) this._names.pop();
  this._names = sortNames(this._names);
}

var EventProxy = {
  setMaxListeners: function() {
    return this._emitter.setMaxListeners.apply(this, arguments);
  },
  emit: function() {
    return this._emitter.emit.apply(this, arguments);
  },
  addListener: function() {
    return this._emitter.addListener.apply(this, arguments);
  },
  on: function() {
    return this._emitter.on.apply(this, arguments);
  },
  once: function() {
    return this._emitter.once.apply(this, arguments);
  },
  removeListener: function() {
    return this._emitter.removeListener.apply(this, arguments);
  },
  removeAllListeners: function() {
    return this._emitter.removeAllListeners.apply(this, arguments);
  },
  listeners: function() {
    return this._emitter.listeners.apply(this, arguments);
  }
}

var enumerable = process.env.CLI_TOOLKIT_DEBUG ? true : false;

function define(obj, name, value, writable) {
  writable = writable || false;
  Object.defineProperty(obj, name,
    {
      enumerable: enumerable,
      configurable: false,
      writable: writable,
      value: value
    }
  );
}

/**
 *  Abstract super class.
 *
 *  @param name The argument name.
 *  @param description The argument description.
 *  @param options The argument options or conversion function.
 */
var Argument = function(name, description, options) {
  if(typeof name == 'object') options = name;
  define(this, '_name', name, true);
  define(this, '_description', description || '', true);
  define(this, '_key', '', true);
  define(this, '_optional', true, true);
  define(this, '_multiple', false, true);
  define(this, '_value', undefined, true);
  define(this, '_converter', undefined, true);
  define(this, '_action', undefined, true);
  define(this, '_extra', undefined, true);
  define(this, '_names', undefined, true);

  // event emitter
  define(this, '_emitter', new events.EventEmitter(), false);
  define(this, '_events', undefined, true);
  define(this, '_maxListeners', undefined, true);
  define(this, 'domain', undefined, true);

  if(options === JSON) {
    this._converter = JSON;
  }else if(options && (typeof options == 'object') && !Array.isArray(options)) {
    initialize.call(this, options, Object.keys(mutators.arg));
  }else if((typeof options == 'function') || this.isFunctionArray(options)){
    this._converter = options;
    if(arguments.length > 3 && this._value === undefined) {
      this._value = arguments[3];
    }
  }else {
    this._value = options;
    if(arguments.length > 3
      && (typeof(arguments[3]) == 'function'
      || this.isFunctionArray(options))) {
      this._converter = arguments[3];
    }
  }

  if(!this._name || typeof this._name !== 'string') {
    throw new TypeError('Invalid argument name \'' + this._name + '\'');
  }

  // strip no prefixes
  var no = re.no();
  var name = '' + this._name;
  if((this instanceof Flag) && no.test(this._name)) {
    name = this._name.replace(no, '');
  }

  this._names = this._name.split(re.delimiter());
  //console.dir(this._names);
  getExtra.call(this);
  if(re.required().test(this._extra)) {
    this._optional = false;
  }
  if(re.multiple().test(this._extra)) {
    this._multiple = true;
  }
  this._key = getKey.call(this, name);
  //console.log('key', this._key);
}

for(k in EventProxy) {
  define(Argument.prototype, k, EventProxy[k], false);
}

function toString(delimiter, names) {
  if(!arguments.length) return Object.prototype.toString.call(this);
  names = names || this.names();
  var opt = typeof(this.extra) === 'function';
  delimiter = delimiter || ' | ';
  // TODO: sort commands correctly
  names = sortNames(names);
  return names.join(delimiter);
}
define(Argument.prototype, 'toString', toString, false);

/**
 *  Retrieve a standardized string to use when listing options.
 */
getOptionString = function(delimiter, assignment, names, extra) {
  assignment = assignment || '=';
  delimiter = delimiter || ', ';
  extra = extra || '';
  var opt = typeof(this.extra) === 'function';
  if(opt) {
    // use extracted extra data assigned to the option
    if(!extra) {
      extra = this.extra() || '';
      if(extra) {
        extra = extra.replace(/^(.?)=(.*)$/, "$1$2");
        extra = assignment + extra;
      }
    }else{
      // custom extra specified
      extra = assignment + extra;
    }
  }
  return this.toString(delimiter, names) + extra;
}
define(Argument.prototype, 'getOptionString', getOptionString, false);

/**
 *  Determines whether an array consists solely of functions
 *  allowing for the special case JSON.
 *
 *  @param arr The array candidate.
 */
Argument.prototype.isFunctionArray = function(arr) {
  if(!Array.isArray(arr)) return false;
  var i, item;
  for(i = 0;i < arr.length;i++) {
    item = arr[i];
    if(item !== JSON && !(typeof item == 'function')) return false;
  }
  return true;
}

keys = Object.keys(mutators.arg);
keys.forEach(function(name) {
  var read = function() {
    return this['_' + name];
  }
  var write = function(value) {
    var key = '_' + name;
    if(!arguments.length) return this[key];
    this[key] = value;
    return this;
  }
  define(Argument.prototype, name, mutators.arg[name] ? write : read, false);
})

/**
 *  Represents an option argument.
 */
var Option = function() {
  Argument.apply(this, arguments);
}

util.inherits(Option, Argument);

/**
 *  Represents a flag argument.
 */
var Flag = function() {
  Argument.apply(this, arguments);
  //console.log('Flag %s %s', this._name, this._description);
  //this._value = false;
}

util.inherits(Flag, Argument);

/**
 *  Represents a command argument.
 */
var Command = function(name, description, options) {
  //events.EventEmitter.call(this);
  if(typeof name == 'object') options = name;

  // private
  define(this, '_commands', {}, true);
  define(this, '_options', {}, true);
  define(this, '_name', name || '', true);
  define(this, '_description', description || '', true);
  define(this, '_key', '', true);
  define(this, '_action', undefined, true);
  define(this, '_names', undefined, true);
  define(this, '_last', undefined, true);
  //define(this, '_package', undefined, true);

  // event emitter
  define(this, '_emitter', new events.EventEmitter(), false);
  define(this, '_events', undefined, true);
  define(this, '_maxListeners', undefined, true);
  define(this, 'domain', undefined, true);

  if((typeof options == 'object')) {
    initialize.call(this, options, Object.keys(mutators.cmd));
  }

  if(!this._name || typeof this._name !== 'string') {
    throw new TypeError('Invalid command name \'' + this._name + '\'');
  }

  this._names = this._name.split(re.delimiter());
  this._key = getKey.call(this);
}

define(Command.prototype, 'getOptionString', getOptionString, false);
define(Command.prototype, 'toString', toString, false);

for(k in EventProxy) {
  define(Command.prototype, k, EventProxy[k], false);
}

keys = Object.keys(mutators.cmd);
keys.forEach(function(name) {
  var read = function() {
    return this['_' + name];
  }
  var write = function(value) {
    var key = '_' + name;
    if(value === undefined) return this[key];
    this[key] = value;
    return this;
  }
  define(Command.prototype, name, mutators.cmd[name] ? write : read, false);
})

/**
 *  Define a command argument.
 */
function command(name, description, options) {
  var opt = (name instanceof Command) ? name
    : new Command(name, description, options);
  this._commands[opt.key()] = opt;
  this._last = this._commands[opt.key()];
  return description ? this : opt;
}
define(Command.prototype, 'command', command, false);

/**
 *  Define an option argument.
 */
function option(name, description, options, coerce, value) {
  var clazz = Option;
  if(typeof name === 'string') {
    if(re.no().test(name) || !re.extra().test(name)) {
      clazz = Flag;
    }
  }
  var opt = (name instanceof Option) || (name instanceof Flag) ? name
    : new clazz(name, description, options, coerce, value);
  this._options[opt.key()] = opt;
  this._last = this._options[opt.key()];
  return this;
}
define(Command.prototype, 'option', option, false);

/**
 *  Define a flag argument explicitly.
 */
function flag(name, description, options, coerce, value) {
  var opt = (name instanceof Flag) ? name
    : new Flag(name, description, options, coerce, value);
  this._options[opt.key()] = opt;
  return this;
}
define(Command.prototype, 'flag', flag, false);

/**
 *  Represents the program.
 */
var Program = function() {
  Command.apply(this, arguments);
  define(this, '_version', '0.0.1', true);
  define(this, '_package', undefined, true);
  define(this, '_converter', undefined, true);
}

util.inherits(Program, Command);

keys = Object.keys(mutators.prg);
keys.forEach(function(name) {
  var write = function(value) {
    var key = '_' + name;
    if(!arguments.length) return this[key];
    this[key] = value;
    return this;
  }
  define(Program.prototype, name, write, false);
})

/**
 *  Set the program package descriptor.
 *
 *  @param path The path to the package descriptor or an existing
 *  package object.
 */
function package(path) {
  if(!arguments.length) return this._package;
  if(arguments.length === 1 && !path) {
    this._package = path;
    return this._package;
  }
  var pkg;
  if(path && typeof(path) === 'string' && fs.existsSync(path)) {
    try {
      pkg = this._package = require(path);
    }catch(e) {
      throw new Error(util.format(
        'package parse error %s (malformed json)', path));
    }
  }else if(path && typeof path === 'object') {
    pkg = this._package = path;
  }
  if(!pkg) {
    throw new Error(util.format(
      'package descriptor %s does not exist', path));
  }
  this._version = pkg.version;
  if(pkg.description) this._description = pkg.description;
  return this;
}
define(Program.prototype, 'package', package, false);

/**
 *  Initialize the program from a package.json
 *  project descriptor, optionally overriding
 *  the name, description and class to instantiate.
 *
 *  @param package The path to package.json.
 *  @param name A specific name for the root command (optional).
 *  @param description A specific description for the root command (optional).
 *  @param clazz A specific class to instantiate.
 */
function create(package, name, description, clazz) {
  clazz = clazz || Program;
  var program = new clazz(basename(process.argv[1]));
  program.package(package);
  if(name) program.name(name);
  if(description) program.description(description);
  return program;
}

module.exports = create;
module.exports.re = re;
module.exports.define = define;
module.exports.initialize = initialize;
module.exports.key = getKey;
module.exports.Program = Program;
module.exports.Command = Command;
module.exports.Option = Option;
module.exports.Flag = Flag;
<commit_msg>Expose mutators.<commit_after>var events = require('events');
var fs = require('fs');
var path = require('path'), basename = path.basename;
var util = require('util');
var camelcase = require('cli-util').camelcase;

var mutators = {
  cmd: {
    options: false,
    commands: false,
    names: false,
    key: true,
    name: true,
    description: true,
    action: true,
    last: true
  },
  arg: {
    names: false,
    key: true,
    name: true,
    optional: true,
    multiple: true,
    value: true,
    converter: true,
    extra: true,
    description: true,
    action: true
  },
  prg: {
    converter: true
  }
}

var k, keys;
var re = {
  delimiter: function(){return /[ ,|]+/;},
  required: function(){return /^=?</;},
  multiple: function(){return /\.\.\./;},
  extra: function(){return /^([^=\[<]*)((=|\[|<).*)/;},
  no: function(){return /(\[no-?\]-?)/;}
}

function initialize(options, properties) {
  for(var z in options) {
    if(~properties.indexOf(z) && options[z]) this[z](options[z]);
  }
}

/**
 *  Retrieve the key for an option.
 *
 *  Scope is the option. Alternatively you may pass a
 *  string of the raw name passed when instantiating the options.
 *
 *  @param names Array of names or raw string name (optional).
 */
function getKey(names, name) {
  var k, names = names || this._names;
  name = name || this._name;
  if(typeof names == 'string') {
    name = names;
    names = names.split(re.delimiter());
  }
  names = names.slice(0);
  if(this._extra) {
    var j = names.length -1;
    var nm = names[j];
    while(re.extra().test(nm) || re.multiple().test(nm)) {
      // allow for flush extra values
      if(/^-+/.test(nm)) {
        names[j] = nm.replace(re.extra(), "$1");
      }else{
        names.pop();
      }
      nm = names[--j];
    }
    this._names = sortNames(names);
  }
  var k = names.reduce(
    function (a, b) { return a.length > b.length ? a : b; });
  k = k.replace(/^-+/, '');
  return camelcase(k.toLowerCase());
}

function sortNames(names) {
  // sort short options before long options
  return names.sort(function(a, b) {
    var re = /^-[^-]/;
    return re.test(a) ? -1 : re.test(b) ? 1 : 0;
  });
}

/**
 *  Retrieve the extra portion of the option name.
 *
 *  Note this also updates the names array to not include
 *  the extra portion.
 */
function getExtra() {
  if(re.no().test(this._name)) {
    this._extra = false;
    return;
  }
  if(!re.extra().test(this._name)) return;
  this._extra = this._name.replace(re.extra(), "$2");
  //console.log(this._extra);
  var name = this._name.replace(re.extra(), "$1");
  //console.log('name: %s', name);
  this._names = name.split(re.delimiter());
  if(!this._names[this._names.length - 1]) this._names.pop();
  this._names = sortNames(this._names);
}

var EventProxy = {
  setMaxListeners: function() {
    return this._emitter.setMaxListeners.apply(this, arguments);
  },
  emit: function() {
    return this._emitter.emit.apply(this, arguments);
  },
  addListener: function() {
    return this._emitter.addListener.apply(this, arguments);
  },
  on: function() {
    return this._emitter.on.apply(this, arguments);
  },
  once: function() {
    return this._emitter.once.apply(this, arguments);
  },
  removeListener: function() {
    return this._emitter.removeListener.apply(this, arguments);
  },
  removeAllListeners: function() {
    return this._emitter.removeAllListeners.apply(this, arguments);
  },
  listeners: function() {
    return this._emitter.listeners.apply(this, arguments);
  }
}

var enumerable = process.env.CLI_TOOLKIT_DEBUG ? true : false;

function define(obj, name, value, writable) {
  writable = writable || false;
  Object.defineProperty(obj, name,
    {
      enumerable: enumerable,
      configurable: false,
      writable: writable,
      value: value
    }
  );
}

/**
 *  Abstract super class.
 *
 *  @param name The argument name.
 *  @param description The argument description.
 *  @param options The argument options or conversion function.
 */
var Argument = function(name, description, options) {
  if(typeof name == 'object') options = name;
  define(this, '_name', name, true);
  define(this, '_description', description || '', true);
  define(this, '_key', '', true);
  define(this, '_optional', true, true);
  define(this, '_multiple', false, true);
  define(this, '_value', undefined, true);
  define(this, '_converter', undefined, true);
  define(this, '_action', undefined, true);
  define(this, '_extra', undefined, true);
  define(this, '_names', undefined, true);

  // event emitter
  define(this, '_emitter', new events.EventEmitter(), false);
  define(this, '_events', undefined, true);
  define(this, '_maxListeners', undefined, true);
  define(this, 'domain', undefined, true);

  if(options === JSON) {
    this._converter = JSON;
  }else if(options && (typeof options == 'object') && !Array.isArray(options)) {
    initialize.call(this, options, Object.keys(mutators.arg));
  }else if((typeof options == 'function') || this.isFunctionArray(options)){
    this._converter = options;
    if(arguments.length > 3 && this._value === undefined) {
      this._value = arguments[3];
    }
  }else {
    this._value = options;
    if(arguments.length > 3
      && (typeof(arguments[3]) == 'function'
      || this.isFunctionArray(options))) {
      this._converter = arguments[3];
    }
  }

  if(!this._name || typeof this._name !== 'string') {
    throw new TypeError('Invalid argument name \'' + this._name + '\'');
  }

  // strip no prefixes
  var no = re.no();
  var name = '' + this._name;
  if((this instanceof Flag) && no.test(this._name)) {
    name = this._name.replace(no, '');
  }

  this._names = this._name.split(re.delimiter());
  //console.dir(this._names);
  getExtra.call(this);
  if(re.required().test(this._extra)) {
    this._optional = false;
  }
  if(re.multiple().test(this._extra)) {
    this._multiple = true;
  }
  this._key = getKey.call(this, name);
  //console.log('key', this._key);
}

for(k in EventProxy) {
  define(Argument.prototype, k, EventProxy[k], false);
}

function toString(delimiter, names) {
  if(!arguments.length) return Object.prototype.toString.call(this);
  names = names || this.names();
  var opt = typeof(this.extra) === 'function';
  delimiter = delimiter || ' | ';
  // TODO: sort commands correctly
  names = sortNames(names);
  return names.join(delimiter);
}
define(Argument.prototype, 'toString', toString, false);

/**
 *  Retrieve a standardized string to use when listing options.
 */
getOptionString = function(delimiter, assignment, names, extra) {
  assignment = assignment || '=';
  delimiter = delimiter || ', ';
  extra = extra || '';
  var opt = typeof(this.extra) === 'function';
  if(opt) {
    // use extracted extra data assigned to the option
    if(!extra) {
      extra = this.extra() || '';
      if(extra) {
        extra = extra.replace(/^(.?)=(.*)$/, "$1$2");
        extra = assignment + extra;
      }
    }else{
      // custom extra specified
      extra = assignment + extra;
    }
  }
  return this.toString(delimiter, names) + extra;
}
define(Argument.prototype, 'getOptionString', getOptionString, false);

/**
 *  Determines whether an array consists solely of functions
 *  allowing for the special case JSON.
 *
 *  @param arr The array candidate.
 */
Argument.prototype.isFunctionArray = function(arr) {
  if(!Array.isArray(arr)) return false;
  var i, item;
  for(i = 0;i < arr.length;i++) {
    item = arr[i];
    if(item !== JSON && !(typeof item == 'function')) return false;
  }
  return true;
}

keys = Object.keys(mutators.arg);
keys.forEach(function(name) {
  var read = function() {
    return this['_' + name];
  }
  var write = function(value) {
    var key = '_' + name;
    if(!arguments.length) return this[key];
    this[key] = value;
    return this;
  }
  define(Argument.prototype, name, mutators.arg[name] ? write : read, false);
})

/**
 *  Represents an option argument.
 */
var Option = function() {
  Argument.apply(this, arguments);
}

util.inherits(Option, Argument);

/**
 *  Represents a flag argument.
 */
var Flag = function() {
  Argument.apply(this, arguments);
  //console.log('Flag %s %s', this._name, this._description);
  //this._value = false;
}

util.inherits(Flag, Argument);

/**
 *  Represents a command argument.
 */
var Command = function(name, description, options) {
  //events.EventEmitter.call(this);
  if(typeof name == 'object') options = name;

  // private
  define(this, '_commands', {}, true);
  define(this, '_options', {}, true);
  define(this, '_name', name || '', true);
  define(this, '_description', description || '', true);
  define(this, '_key', '', true);
  define(this, '_action', undefined, true);
  define(this, '_names', undefined, true);
  define(this, '_last', undefined, true);
  //define(this, '_package', undefined, true);

  // event emitter
  define(this, '_emitter', new events.EventEmitter(), false);
  define(this, '_events', undefined, true);
  define(this, '_maxListeners', undefined, true);
  define(this, 'domain', undefined, true);

  if((typeof options == 'object')) {
    initialize.call(this, options, Object.keys(mutators.cmd));
  }

  if(!this._name || typeof this._name !== 'string') {
    throw new TypeError('Invalid command name \'' + this._name + '\'');
  }

  this._names = this._name.split(re.delimiter());
  this._key = getKey.call(this);
}

define(Command.prototype, 'getOptionString', getOptionString, false);
define(Command.prototype, 'toString', toString, false);

for(k in EventProxy) {
  define(Command.prototype, k, EventProxy[k], false);
}

keys = Object.keys(mutators.cmd);
keys.forEach(function(name) {
  var read = function() {
    return this['_' + name];
  }
  var write = function(value) {
    var key = '_' + name;
    if(value === undefined) return this[key];
    this[key] = value;
    return this;
  }
  define(Command.prototype, name, mutators.cmd[name] ? write : read, false);
})

/**
 *  Define a command argument.
 */
function command(name, description, options) {
  var opt = (name instanceof Command) ? name
    : new Command(name, description, options);
  this._commands[opt.key()] = opt;
  this._last = this._commands[opt.key()];
  return description ? this : opt;
}
define(Command.prototype, 'command', command, false);

/**
 *  Define an option argument.
 */
function option(name, description, options, coerce, value) {
  var clazz = Option;
  if(typeof name === 'string') {
    if(re.no().test(name) || !re.extra().test(name)) {
      clazz = Flag;
    }
  }
  var opt = (name instanceof Option) || (name instanceof Flag) ? name
    : new clazz(name, description, options, coerce, value);
  this._options[opt.key()] = opt;
  this._last = this._options[opt.key()];
  return this;
}
define(Command.prototype, 'option', option, false);

/**
 *  Define a flag argument explicitly.
 */
function flag(name, description, options, coerce, value) {
  var opt = (name instanceof Flag) ? name
    : new Flag(name, description, options, coerce, value);
  this._options[opt.key()] = opt;
  return this;
}
define(Command.prototype, 'flag', flag, false);

/**
 *  Represents the program.
 */
var Program = function() {
  Command.apply(this, arguments);
  define(this, '_version', '0.0.1', true);
  define(this, '_package', undefined, true);
  define(this, '_converter', undefined, true);
}

util.inherits(Program, Command);

keys = Object.keys(mutators.prg);
keys.forEach(function(name) {
  var write = function(value) {
    var key = '_' + name;
    if(!arguments.length) return this[key];
    this[key] = value;
    return this;
  }
  define(Program.prototype, name, write, false);
})

/**
 *  Set the program package descriptor.
 *
 *  @param path The path to the package descriptor or an existing
 *  package object.
 */
function package(path) {
  if(!arguments.length) return this._package;
  if(arguments.length === 1 && !path) {
    this._package = path;
    return this._package;
  }
  var pkg;
  if(path && typeof(path) === 'string' && fs.existsSync(path)) {
    try {
      pkg = this._package = require(path);
    }catch(e) {
      throw new Error(util.format(
        'package parse error %s (malformed json)', path));
    }
  }else if(path && typeof path === 'object') {
    pkg = this._package = path;
  }
  if(!pkg) {
    throw new Error(util.format(
      'package descriptor %s does not exist', path));
  }
  this._version = pkg.version;
  if(pkg.description) this._description = pkg.description;
  return this;
}
define(Program.prototype, 'package', package, false);

/**
 *  Initialize the program from a package.json
 *  project descriptor, optionally overriding
 *  the name, description and class to instantiate.
 *
 *  @param package The path to package.json.
 *  @param name A specific name for the root command (optional).
 *  @param description A specific description for the root command (optional).
 *  @param clazz A specific class to instantiate.
 */
function create(package, name, description, clazz) {
  clazz = clazz || Program;
  var program = new clazz(basename(process.argv[1]));
  program.package(package);
  if(name) program.name(name);
  if(description) program.description(description);
  return program;
}

module.exports = create;
module.exports.re = re;
module.exports.define = define;
module.exports.initialize = initialize;
module.exports.mutators = mutators;
module.exports.key = getKey;
module.exports.Program = Program;
module.exports.Command = Command;
module.exports.Option = Option;
module.exports.Flag = Flag;
<|endoftext|>


<commit_before>/*
===========================================================================
    Copyright 2015-2016 Sebastian Software GmbH, Germany
    Licensed under Apache-2.0
===========================================================================
*/

import IntlMessageFormat from "intl-messageformat"
import IntlRelativeFormat from "intl-relativeformat"
import areLocalesSupported from "intl-locales-supported"

import createFormatCache from "intl-format-cache"

import { kebabCase, isPlainObject, isString, isNumber, isDate, each, clamp } from "lodash"

// Be sure to import the Polyfill
// TODO: Figure out if there is a ES2015 way to conditional load this
import "intl"

// NodeJS by default to not offer full ICU support and therefor break the unit tests
if (!areLocalesSupported([ "en", "de", "fr", "es" ]))
{
  /* global IntlPolyfill */
  Intl.NumberFormat = IntlPolyfill.NumberFormat
  Intl.DateTimeFormat = IntlPolyfill.DateTimeFormat
}

const formats = IntlMessageFormat.formats

const getCachedNumberFormat = createFormatCache(Intl.NumberFormat)
const getCachedDateTimeFormat = createFormatCache(Intl.DateTimeFormat)
const getCachedMessageFormat = createFormatCache(IntlMessageFormat)
const getCachedRelativeFormat = createFormatCache(IntlRelativeFormat)

// A constant defined by the standard Intl.NumberFormat
const maximumFractionDigits = 20;

function install(Vue, options)
{
  var { language, currency, messages } = options
  var locale = language

  // =============================================
  //   FORMATTER FUNCTIONS
  // =============================================

  function formatDate(date, format)
  {
    let parsedDate = new Date(date)
    if (!isDate(parsedDate))
      throw new TypeError("A date or timestamp must be provided to {{formatDate}}")

    if (isString(format) && format in formats.date)
      format = formats.date[format]

    return getCachedDateTimeFormat(locale, format).format(parsedDate)
  }

  function formatTime(date, format)
  {
    let parsedDate = new Date(date)
    if (!isDate(date))
      throw new TypeError("A date or timestamp must be provided to {{formatTime}}")

    if (isString(format) && format in formats.time)
      format = formats.time[format]

    return getCachedDateTimeFormat(locale, format).format(parsedDate)
  }

  function formatNumber(num, format)
  {
    if (!isNumber(num))
      throw new TypeError("A number must be provided to {{formatNumber}}")

    if (isString(format))
    {
      if (format === "currency")
        format = { style: "currency", currency: currency }
      else if (format in formats.number)
        format = formats.number[format]
    }

    return getCachedNumberFormat(locale, format).format(num)
  }

  function formatRelative(date, format, now)
  {
    let parsedDate = new Date(date)
    if (!isDate(parsedDate))
      throw new TypeError("A date or timestamp must be provided to {{formatRelative}}")

    return getCachedRelativeFormat(locale, format).format(parsedDate, {
      now: now || new Date()
    })
  }

  function formatMessage(message, ...formatOptions)
  {
    // Read real message from DB
    if (message in messages)
      message = messages[message]

    if (typeof message === "string")
      message = getCachedMessageFormat(message, locale, {})

    // If there is a single map parameter, use that instead of the formatOptions array
    if (formatOptions.length === 1 && isPlainObject(formatOptions[0]))
      formatOptions = formatOptions[0]

    return message.format(formatOptions)
  }

  // =============================================
  //   PARSERS
  // =============================================

  // Figuring out whether the separator is either "," or "." (Are there any other possibilities at all?)
  var decimalTestNumber = 3.1
  var decimalSeparator = formatNumber(decimalTestNumber).charAt(1)

  function extractNumberParts(value)
  {
    var parsed = parseInt(value.replace(/[^0-9]/g, ""), 0)
    return isNaN(parsed) ? 0 : parsed
  }

  function parseToNumber(value)
  {
    if (value == null || value === "")
      return 0

    var splits = value.split(decimalSeparator).map(extractNumberParts)

    // Build up float number to let parseFloat convert it back into a number
    if (splits[1] > 0)
      return parseFloat(splits[0] + "." + splits[1])

    // Return plain integer
    return splits[0]
  }

  // =============================================
  //   REGISTER FILTERS
  // =============================================

  var helpers =
  {
    formatDate,
    formatTime,
    formatRelative,
    formatNumber,
    formatMessage
  }

  each(helpers, function(helper, name)
  {
    // Adding features as a VueJS filter for easily pass a string over (only numberic parameters though)
    Vue.filter(kebabCase(name), helper)

    // Support alternative full blown calling of methods with real options object
    Vue.prototype["$" + name] = helper
  })

  Vue.directive("i18n", function(id)
  {
    /* eslint no-invalid-this: 0 */
    if (id == null || isNaN(id))
      id = this.expression

    this.el.innerHTML = formatMessage(id)
  })

  Vue.component("text",
  {
    template: '{{ translated }}',
    props: {
      msg: {
        type: String,
        required: true
      }
    },
    computed: {
      translated: function(...formatOptions) {
        return formatMessage(this.msg, ...formatOptions);
      }
    }
  })

  // =============================================
  //   ADDITIONAL FILTERS
  // =============================================

  // Via: http://jsfiddle.net/6jjuoypf/2/
  Vue.filter("format-currency",
  {
    // model -> view: formats the value when updating the input element.
    read: function(val)
    {
      var numberOptions =
      {
        style: "currency",
        currency: currency,
        minimumFractionDigits: 0,
        maximumFractionDigits: 0
      }

      return formatNumber(val == null || val === "" || isNaN(val) ? 0 : val, numberOptions)
    },

    // view -> model: formats the value when writing to the data.
    write: function(val) {
      return parseToNumber(val)
    }
  })

  Vue.filter("format-currency-precise",
  {
    // model -> view: formats the value when updating the input element.
    read: function(val) {
      return formatNumber(val == null || val === "" || isNaN(val) ? 0 : val, "currency")
    },

    // view -> model: formats the value when writing to the data.
    write: function(val) {
      return parseToNumber(val)
    }
  })

  Vue.filter("format-percent",
  {
    // model -> view: formats the value when updating the input element.
    read: function(val, fractionDigits)
    {
      return formatNumber(val == null || val === "" ? 0 : clamp(val / 100, 0, 1),
      {
        style: "percent",
        minimumFractionDigits: fractionDigits == null ? 0 : fractionDigits,
        maximumFractionDigits: fractionDigits == null ? maximumFractionDigits : fractionDigits
      })
    },

    // view -> model: formats the value when writing to the data.
    write: function(val) {
      return parseToNumber(val)
    }
  })

  Vue.filter("format-number",
  {
    // model -> view: formats the value when updating the input element.
    read: function(val, fractionDigits)
    {
      return val == null || val === "" ? 0 : formatNumber(val,
      {
        minimumFractionDigits: fractionDigits == null ? 0 : fractionDigits,
        maximumFractionDigits: fractionDigits == null ? maximumFractionDigits : fractionDigits
      })
    },

    // view -> model: formats the value when writing to the data.
    write: function(val) {
      return parseToNumber(val)
    }
  })
}

var plugin = {
  install
}

export default plugin
<commit_msg>The text formatting is regarded as safe so that we can always allow html output<commit_after>/*
===========================================================================
    Copyright 2015-2016 Sebastian Software GmbH, Germany
    Licensed under Apache-2.0
===========================================================================
*/

import IntlMessageFormat from "intl-messageformat"
import IntlRelativeFormat from "intl-relativeformat"
import areLocalesSupported from "intl-locales-supported"

import createFormatCache from "intl-format-cache"

import { kebabCase, isPlainObject, isString, isNumber, isDate, each, clamp } from "lodash"

// Be sure to import the Polyfill
// TODO: Figure out if there is a ES2015 way to conditional load this
import "intl"

// NodeJS by default to not offer full ICU support and therefor break the unit tests
if (!areLocalesSupported([ "en", "de", "fr", "es" ]))
{
  /* global IntlPolyfill */
  Intl.NumberFormat = IntlPolyfill.NumberFormat
  Intl.DateTimeFormat = IntlPolyfill.DateTimeFormat
}

const formats = IntlMessageFormat.formats

const getCachedNumberFormat = createFormatCache(Intl.NumberFormat)
const getCachedDateTimeFormat = createFormatCache(Intl.DateTimeFormat)
const getCachedMessageFormat = createFormatCache(IntlMessageFormat)
const getCachedRelativeFormat = createFormatCache(IntlRelativeFormat)

// A constant defined by the standard Intl.NumberFormat
const maximumFractionDigits = 20;

function install(Vue, options)
{
  var { language, currency, messages } = options
  var locale = language

  // =============================================
  //   FORMATTER FUNCTIONS
  // =============================================

  function formatDate(date, format)
  {
    let parsedDate = new Date(date)
    if (!isDate(parsedDate))
      throw new TypeError("A date or timestamp must be provided to {{formatDate}}")

    if (isString(format) && format in formats.date)
      format = formats.date[format]

    return getCachedDateTimeFormat(locale, format).format(parsedDate)
  }

  function formatTime(date, format)
  {
    let parsedDate = new Date(date)
    if (!isDate(date))
      throw new TypeError("A date or timestamp must be provided to {{formatTime}}")

    if (isString(format) && format in formats.time)
      format = formats.time[format]

    return getCachedDateTimeFormat(locale, format).format(parsedDate)
  }

  function formatNumber(num, format)
  {
    if (!isNumber(num))
      throw new TypeError("A number must be provided to {{formatNumber}}")

    if (isString(format))
    {
      if (format === "currency")
        format = { style: "currency", currency: currency }
      else if (format in formats.number)
        format = formats.number[format]
    }

    return getCachedNumberFormat(locale, format).format(num)
  }

  function formatRelative(date, format, now)
  {
    let parsedDate = new Date(date)
    if (!isDate(parsedDate))
      throw new TypeError("A date or timestamp must be provided to {{formatRelative}}")

    return getCachedRelativeFormat(locale, format).format(parsedDate, {
      now: now || new Date()
    })
  }

  function formatMessage(message, ...formatOptions)
  {
    // Read real message from DB
    if (message in messages)
      message = messages[message]

    if (typeof message === "string")
      message = getCachedMessageFormat(message, locale, {})

    // If there is a single map parameter, use that instead of the formatOptions array
    if (formatOptions.length === 1 && isPlainObject(formatOptions[0]))
      formatOptions = formatOptions[0]

    return message.format(formatOptions)
  }

  // =============================================
  //   PARSERS
  // =============================================

  // Figuring out whether the separator is either "," or "." (Are there any other possibilities at all?)
  var decimalTestNumber = 3.1
  var decimalSeparator = formatNumber(decimalTestNumber).charAt(1)

  function extractNumberParts(value)
  {
    var parsed = parseInt(value.replace(/[^0-9]/g, ""), 0)
    return isNaN(parsed) ? 0 : parsed
  }

  function parseToNumber(value)
  {
    if (value == null || value === "")
      return 0

    var splits = value.split(decimalSeparator).map(extractNumberParts)

    // Build up float number to let parseFloat convert it back into a number
    if (splits[1] > 0)
      return parseFloat(splits[0] + "." + splits[1])

    // Return plain integer
    return splits[0]
  }

  // =============================================
  //   REGISTER FILTERS
  // =============================================

  var helpers =
  {
    formatDate,
    formatTime,
    formatRelative,
    formatNumber,
    formatMessage
  }

  each(helpers, function(helper, name)
  {
    // Adding features as a VueJS filter for easily pass a string over (only numberic parameters though)
    Vue.filter(kebabCase(name), helper)

    // Support alternative full blown calling of methods with real options object
    Vue.prototype["$" + name] = helper
  })

  Vue.directive("i18n", function(id)
  {
    /* eslint no-invalid-this: 0 */
    if (id == null || isNaN(id))
      id = this.expression

    this.el.innerHTML = formatMessage(id)
  })

  Vue.component("text",
  {
    template: '{{{ translated }}}',
    props: {
      msg: {
        type: String,
        required: true
      }
    },
    computed: {
      translated: function(...formatOptions) {
        return formatMessage(this.msg, ...formatOptions);
      }
    }
  })

  // =============================================
  //   ADDITIONAL FILTERS
  // =============================================

  // Via: http://jsfiddle.net/6jjuoypf/2/
  Vue.filter("format-currency",
  {
    // model -> view: formats the value when updating the input element.
    read: function(val)
    {
      var numberOptions =
      {
        style: "currency",
        currency: currency,
        minimumFractionDigits: 0,
        maximumFractionDigits: 0
      }

      return formatNumber(val == null || val === "" || isNaN(val) ? 0 : val, numberOptions)
    },

    // view -> model: formats the value when writing to the data.
    write: function(val) {
      return parseToNumber(val)
    }
  })

  Vue.filter("format-currency-precise",
  {
    // model -> view: formats the value when updating the input element.
    read: function(val) {
      return formatNumber(val == null || val === "" || isNaN(val) ? 0 : val, "currency")
    },

    // view -> model: formats the value when writing to the data.
    write: function(val) {
      return parseToNumber(val)
    }
  })

  Vue.filter("format-percent",
  {
    // model -> view: formats the value when updating the input element.
    read: function(val, fractionDigits)
    {
      return formatNumber(val == null || val === "" ? 0 : clamp(val / 100, 0, 1),
      {
        style: "percent",
        minimumFractionDigits: fractionDigits == null ? 0 : fractionDigits,
        maximumFractionDigits: fractionDigits == null ? maximumFractionDigits : fractionDigits
      })
    },

    // view -> model: formats the value when writing to the data.
    write: function(val) {
      return parseToNumber(val)
    }
  })

  Vue.filter("format-number",
  {
    // model -> view: formats the value when updating the input element.
    read: function(val, fractionDigits)
    {
      return val == null || val === "" ? 0 : formatNumber(val,
      {
        minimumFractionDigits: fractionDigits == null ? 0 : fractionDigits,
        maximumFractionDigits: fractionDigits == null ? maximumFractionDigits : fractionDigits
      })
    },

    // view -> model: formats the value when writing to the data.
    write: function(val) {
      return parseToNumber(val)
    }
  })
}

var plugin = {
  install
}

export default plugin
<|endoftext|>


<commit_before>'use strict'
const MongoClient = require('mongodb').MongoClient;

module.exports = function(config, routes) {
	const router = require('express').Router();
	let err = null;
	// check parameter
	if(routes === undefined ) {
		err = { message: 'Please provide routes!'}
	}
	else if(!(routes.constructor === Array)) {
		err = { message: 'Please provide an array of routes!'}
	}
	// abort if err
	if(err) {
		let errorOut = `Firestone Error: ${err.message}`;
		console.error(errorOut);
		router.use('/', (req, res) => {
			res.send(errorOut)
		})
		return router;
	}

	// create routes
	for(var i=0; i < routes.length; i += 1) {
		createRoute(router, routes[i], config);
	}
	return router;
};

function createRoute(router, definition, config) {
	router.route(definition.path)
		.get((req, res) => {
			MongoClient.connect(config.mongo.uri)
				.then((db) => {
					return db.collection(definition.coll).find({});
				})
				.then((cursor) => {
					return cursor.toArray();
				})
				.then((content) => {
					res.status(200).json(content);
					//console.log(JSON.stringify(content, null, 2));
				})
				.catch((err) => {
					res.json(err);
				})
		})
}<commit_msg>GET single items with :id<commit_after>'use strict'
const MongoClient = require('mongodb').MongoClient;
const ObjectId = require('mongodb').ObjectID;

module.exports = function(config, routes) {
	const router = require('express').Router();
	let err = null;
	// check parameter
	if(routes === undefined ) {
		err = { message: 'Please provide routes!'}
	}
	else if(!(routes.constructor === Array)) {
		err = { message: 'Please provide an array of routes!'}
	}
	// abort if err
	if(err) {
		let errorOut = `Firestone Error: ${err.message}`;
		console.error(errorOut);
		router.use('/', (req, res) => {
			res.send(errorOut)
		})
		return router;
	}

	// create routes
	for(var i=0; i < routes.length; i += 1) {
		createRoute(router, routes[i], config);
	}
	return router;
};

function createRoute(router, definition, config) {
	// path
	router.route(definition.path)
		// GET
		.get((req, res) => {
			MongoClient.connect(config.mongo.uri)
				.then((db) => {
					return db.collection(definition.coll).find({});
				})
				.then((cursor) => {
					return cursor.toArray();
				})
				.then((content) => {
					res.status(200).json(content);
				})
				.catch((err) => {
					res.json(err);
				})
		})
	// path/:id
	router.route(definition.path + '/:id')
		// GET
		.get((req, res) => {
			let id = req.params.id;
			MongoClient.connect(config.mongo.uri)
				.then((db) => {
					console.log("id:" + id);
					//return db.collection(definition.coll).findOne({_id: ObjectId(id)});
					return db.collection(definition.coll).findOne({_id:ObjectId.createFromHexString(id)})
				})
				.then((result) => {
					console.dir(result);
					res.json(result);
				})
				.catch((err) => {
					console.log(err);
					res.json(err);
				})
		})
}<|endoftext|>


<commit_before>/* MIT license */
var colorNames = require('color-name');
var swizzle = require('simple-swizzle');

var reverseNames = {};

// create a list of reverse color names
for (var name in colorNames) {
	if (colorNames.hasOwnProperty(name)) {
		reverseNames[colorNames[name]] = name;
	}
}

var cs = module.exports = {
	to: {}
};

cs.get = function (string) {
	var prefix = string.substring(0, 3).toLowerCase();
	var val;
	var model;
	switch (prefix) {
		case 'hsl':
			val = cs.get.hsl(string);
			model = 'hsl';
			break;
		case 'hwb':
			val = cs.get.hwb(string);
			model = 'hwb';
			break;
		default:
			val = cs.get.rgb(string);
			model = 'rgb';
			break;
	}

	if (!val) {
		return null;
	}

	return {model: model, value: val};
};

cs.get.rgb = function (string) {
	if (!string) {
		return null;
	}

	var abbr = /^#([a-f0-9]{3})([a-f0-9]{1})?$/i;
	var hex = /^#([a-f0-9]{6})([a-f0-9]{2})?$/i;
	var rgba = /^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/;
	var per = /^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/;
	var keyword = /(\D+)/;

	var rgb = [0, 0, 0, 1];
	var match;
	var i;
	var hexAlpha;

	if (match = string.match(abbr)) {
		hexAlpha = match[2];
		match = match[1];

		for (i = 0; i < 3; i++) {
			rgb[i] = parseInt(match[i] + match[i], 16);
		}

		if (hexAlpha) {
			rgb[3] = Math.round((parseInt(hexAlpha + hexAlpha, 16) / 255) * 100) / 100;
		}
	} else if (match = string.match(hex)) {
		hexAlpha = match[2];
		match = match[1];

		for (i = 0; i < 3; i++) {
			// https://jsperf.com/slice-vs-substr-vs-substring-methods-long-string/19
			var i2 = i * 2;
			rgb[i] = parseInt(match.slice(i2, i2 + 2), 16);
		}

		if (hexAlpha) {
			rgb[3] = Math.round((parseInt(hexAlpha, 16) / 255) * 100) / 100;
		}
	} else if (match = string.match(rgba)) {
		for (i = 0; i < 3; i++) {
			rgb[i] = parseInt(match[i + 1], 0);
		}

		if (match[4]) {
			rgb[3] = parseFloat(match[4]);
		}
	} else if (match = string.match(per)) {
		for (i = 0; i < 3; i++) {
			rgb[i] = Math.round(parseFloat(match[i + 1]) * 2.55);
		}

		if (match[4]) {
			rgb[3] = parseFloat(match[4]);
		}
	} else if (match = string.match(keyword)) {
		if (match[1] === 'transparent') {
			return [0, 0, 0, 0];
		}

		rgb = colorNames[match[1]];

		if (!rgb) {
			return null;
		}

		rgb[3] = 1;

		return rgb;
	} else {
		return null;
	}

	for (i = 0; i < rgb.length; i++) {
		rgb[i] = clamp(rgb[i], 0, 255);
	}
	rgb[3] = clamp(rgb[3], 0, 1);

	return rgb;
};

cs.get.hsl = function (string) {
	if (!string) {
		return null;
	}

	var hsl = /^hsla?\(\s*([+-]?\d*[\.]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/;
	var match = string.match(hsl);

	if (match) {
		var alpha = parseFloat(match[4]);
		var h = ((parseFloat(match[1]) % 360) + 360) % 360;
		var s = clamp(parseFloat(match[2]), 0, 100);
		var l = clamp(parseFloat(match[3]), 0, 100);
		var a = clamp(isNaN(alpha) ? 1 : alpha, 0, 1);

		return [h, s, l, a];
	}

	return null;
};

cs.get.hwb = function (string) {
	if (!string) {
		return null;
	}

	var hwb = /^hwb\(\s*([+-]?\d*[\.]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/;
	var match = string.match(hwb);

	if (match) {
		var alpha = parseFloat(match[4]);
		var h = ((parseFloat(match[1]) % 360) + 360) % 360;
		var w = clamp(parseFloat(match[2]), 0, 100);
		var b = clamp(parseFloat(match[3]), 0, 100);
		var a = clamp(isNaN(alpha) ? 1 : alpha, 0, 1);
		return [h, w, b, a];
	}

	return null;
};

cs.to.hex = function () {
	var rgba = swizzle(arguments);

	return (
		'#' +
		hexDouble(rgba[0]) +
		hexDouble(rgba[1]) +
		hexDouble(rgba[2]) +
		(rgba[3] < 1
			? (hexDouble(Math.round(rgba[3] * 255)))
			: '')
	);
};

cs.to.rgb = function () {
	var rgba = swizzle(arguments);

	return rgba.length < 4 || rgba[3] === 1
		? 'rgb(' + Math.round(rgba[0]) + ', ' + Math.round(rgba[1]) + ', ' + Math.round(rgba[2]) + ')'
		: 'rgba(' + Math.round(rgba[0]) + ', ' + Math.round(rgba[1]) + ', ' + Math.round(rgba[2]) + ', ' + rgba[3] + ')';
};

cs.to.rgb.percent = function () {
	var rgba = swizzle(arguments);

	var r = Math.round(rgba[0] / 255 * 100);
	var g = Math.round(rgba[1] / 255 * 100);
	var b = Math.round(rgba[2] / 255 * 100);

	return rgba.length < 4 || rgba[3] === 1
		? 'rgb(' + r + '%, ' + g + '%, ' + b + '%)'
		: 'rgba(' + r + '%, ' + g + '%, ' + b + '%, ' + rgba[3] + ')';
};

cs.to.hsl = function () {
	var hsla = swizzle(arguments);
	return hsla.length < 4 || hsla[3] === 1
		? 'hsl(' + hsla[0] + ', ' + hsla[1] + '%, ' + hsla[2] + '%)'
		: 'hsla(' + hsla[0] + ', ' + hsla[1] + '%, ' + hsla[2] + '%, ' + hsla[3] + ')';
};

// hwb is a bit different than rgb(a) & hsl(a) since there is no alpha specific syntax
// (hwb have alpha optional & 1 is default value)
cs.to.hwb = function () {
	var hwba = swizzle(arguments);

	var a = '';
	if (hwba.length >= 4 && hwba[3] !== 1) {
		a = ', ' + hwba[3];
	}

	return 'hwb(' + hwba[0] + ', ' + hwba[1] + '%, ' + hwba[2] + '%' + a + ')';
};

cs.to.keyword = function (rgb) {
	return reverseNames[rgb.slice(0, 3)];
};

// helpers
function clamp(num, min, max) {
	return Math.min(Math.max(min, num), max);
}

function hexDouble(num) {
	var str = num.toString(16).toUpperCase();
	return (str.length < 2) ? '0' + str : str;
}
<commit_msg>several fixes to hex string parsing<commit_after>/* MIT license */
var colorNames = require('color-name');
var swizzle = require('simple-swizzle');

var reverseNames = {};

// create a list of reverse color names
for (var name in colorNames) {
	if (colorNames.hasOwnProperty(name)) {
		reverseNames[colorNames[name]] = name;
	}
}

var cs = module.exports = {
	to: {}
};

cs.get = function (string) {
	var prefix = string.substring(0, 3).toLowerCase();
	var val;
	var model;
	switch (prefix) {
		case 'hsl':
			val = cs.get.hsl(string);
			model = 'hsl';
			break;
		case 'hwb':
			val = cs.get.hwb(string);
			model = 'hwb';
			break;
		default:
			val = cs.get.rgb(string);
			model = 'rgb';
			break;
	}

	if (!val) {
		return null;
	}

	return {model: model, value: val};
};

cs.get.rgb = function (string) {
	if (!string) {
		return null;
	}

	var abbr = /^#([a-f0-9]{3,4})$/i;
	var hex = /^#([a-f0-9]{6})([a-f0-9]{2})?$/i;
	var rgba = /^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/;
	var per = /^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/;
	var keyword = /(\D+)/;

	var rgb = [0, 0, 0, 1];
	var match;
	var i;
	var hexAlpha;

	if (match = string.match(hex)) {
		hexAlpha = match[2];
		match = match[1];

		for (i = 0; i < 3; i++) {
			// https://jsperf.com/slice-vs-substr-vs-substring-methods-long-string/19
			var i2 = i * 2;
			rgb[i] = parseInt(match.slice(i2, i2 + 2), 16);
		}

		if (hexAlpha) {
			rgb[3] = Math.round((parseInt(hexAlpha, 16) / 255) * 100) / 100;
		}
	} else if (match = string.match(abbr)) {
		match = match[1];
		hexAlpha = match[3];

		for (i = 0; i < 3; i++) {
			rgb[i] = parseInt(match[i] + match[i], 16);
		}

		if (hexAlpha) {
			rgb[3] = Math.round((parseInt(hexAlpha + hexAlpha, 16) / 255) * 100) / 100;
		}
	} else if (match = string.match(rgba)) {
		for (i = 0; i < 3; i++) {
			rgb[i] = parseInt(match[i + 1], 0);
		}

		if (match[4]) {
			rgb[3] = parseFloat(match[4]);
		}
	} else if (match = string.match(per)) {
		for (i = 0; i < 3; i++) {
			rgb[i] = Math.round(parseFloat(match[i + 1]) * 2.55);
		}

		if (match[4]) {
			rgb[3] = parseFloat(match[4]);
		}
	} else if (match = string.match(keyword)) {
		if (match[1] === 'transparent') {
			return [0, 0, 0, 0];
		}

		rgb = colorNames[match[1]];

		if (!rgb) {
			return null;
		}

		rgb[3] = 1;

		return rgb;
	} else {
		return null;
	}

	for (i = 0; i < 3; i++) {
		rgb[i] = clamp(rgb[i], 0, 255);
	}
	rgb[3] = clamp(rgb[3], 0, 1);

	return rgb;
};

cs.get.hsl = function (string) {
	if (!string) {
		return null;
	}

	var hsl = /^hsla?\(\s*([+-]?\d*[\.]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/;
	var match = string.match(hsl);

	if (match) {
		var alpha = parseFloat(match[4]);
		var h = ((parseFloat(match[1]) % 360) + 360) % 360;
		var s = clamp(parseFloat(match[2]), 0, 100);
		var l = clamp(parseFloat(match[3]), 0, 100);
		var a = clamp(isNaN(alpha) ? 1 : alpha, 0, 1);

		return [h, s, l, a];
	}

	return null;
};

cs.get.hwb = function (string) {
	if (!string) {
		return null;
	}

	var hwb = /^hwb\(\s*([+-]?\d*[\.]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/;
	var match = string.match(hwb);

	if (match) {
		var alpha = parseFloat(match[4]);
		var h = ((parseFloat(match[1]) % 360) + 360) % 360;
		var w = clamp(parseFloat(match[2]), 0, 100);
		var b = clamp(parseFloat(match[3]), 0, 100);
		var a = clamp(isNaN(alpha) ? 1 : alpha, 0, 1);
		return [h, w, b, a];
	}

	return null;
};

cs.to.hex = function () {
	var rgba = swizzle(arguments);

	return (
		'#' +
		hexDouble(rgba[0]) +
		hexDouble(rgba[1]) +
		hexDouble(rgba[2]) +
		(rgba[3] < 1
			? (hexDouble(Math.round(rgba[3] * 255)))
			: '')
	);
};

cs.to.rgb = function () {
	var rgba = swizzle(arguments);

	return rgba.length < 4 || rgba[3] === 1
		? 'rgb(' + Math.round(rgba[0]) + ', ' + Math.round(rgba[1]) + ', ' + Math.round(rgba[2]) + ')'
		: 'rgba(' + Math.round(rgba[0]) + ', ' + Math.round(rgba[1]) + ', ' + Math.round(rgba[2]) + ', ' + rgba[3] + ')';
};

cs.to.rgb.percent = function () {
	var rgba = swizzle(arguments);

	var r = Math.round(rgba[0] / 255 * 100);
	var g = Math.round(rgba[1] / 255 * 100);
	var b = Math.round(rgba[2] / 255 * 100);

	return rgba.length < 4 || rgba[3] === 1
		? 'rgb(' + r + '%, ' + g + '%, ' + b + '%)'
		: 'rgba(' + r + '%, ' + g + '%, ' + b + '%, ' + rgba[3] + ')';
};

cs.to.hsl = function () {
	var hsla = swizzle(arguments);
	return hsla.length < 4 || hsla[3] === 1
		? 'hsl(' + hsla[0] + ', ' + hsla[1] + '%, ' + hsla[2] + '%)'
		: 'hsla(' + hsla[0] + ', ' + hsla[1] + '%, ' + hsla[2] + '%, ' + hsla[3] + ')';
};

// hwb is a bit different than rgb(a) & hsl(a) since there is no alpha specific syntax
// (hwb have alpha optional & 1 is default value)
cs.to.hwb = function () {
	var hwba = swizzle(arguments);

	var a = '';
	if (hwba.length >= 4 && hwba[3] !== 1) {
		a = ', ' + hwba[3];
	}

	return 'hwb(' + hwba[0] + ', ' + hwba[1] + '%, ' + hwba[2] + '%' + a + ')';
};

cs.to.keyword = function (rgb) {
	return reverseNames[rgb.slice(0, 3)];
};

// helpers
function clamp(num, min, max) {
	return Math.min(Math.max(min, num), max);
}

function hexDouble(num) {
	var str = num.toString(16).toUpperCase();
	return (str.length < 2) ? '0' + str : str;
}
<|endoftext|>