<commit_before>import Clickoutside from 'xcui/src/utils/clickoutside';
import { formatDate, parseDate, getWeekNumber, equalDate, isDate } from '../util';
import Popper from 'xcui/src/utils/vue-popper';
import Emitter from 'xcui/src/utils/mixins/emitter';
import XInput from '../../../input';

const NewPopper = {
    props: {
        appendToBody: Popper.props.appendToBody,
        offset: Popper.props.offset,
        boundariesPadding: Popper.props.boundariesPadding
    },
    methods: Popper.methods,
    data: Popper.data,
    beforeDestroy: Popper.beforeDestroy
};

const DEFAULT_FORMATS = {
    date: 'yyyy-MM-dd',
    month: 'yyyy-MM',
    datetime: 'yyyy-MM-dd HH:mm:ss',
    time: 'HH:mm:ss',
    timerange: 'HH:mm:ss',
    daterange: 'yyyy-MM-dd',
    datetimerange: 'yyyy-MM-dd HH:mm:ss',
    year: 'yyyy'
};
const HAVE_TRIGGER_TYPES = [
    'date',
    'datetime',
    'time',
    'time-select',
    'week',
    'month',
    'year',
    'daterange',
    'timerange',
    'datetimerange'
];
const DATE_FORMATTER = function(value, format) {
    return formatDate(value, format);
};
const DATE_PARSER = function(text, format) {
    return parseDate(text, format);
};

const PLACEMENT_MAP = {
    left: 'bottom-start',
    center: 'bottom-center',
    right: 'bottom-end'
};

export default {
    mixins: [Emitter, NewPopper],

    props: {
        size: String,
        format: String,
        readonly: Boolean,
        placeholder: String,
        disabled: Boolean,
        clearable: {
            type: Boolean,
            default: true
        },
        popperClass: String,
        editable: {
            type: Boolean,
            default: true
        },
        align: {
            type: String,
            default: 'left',
            validator(value) {
                return ['right', 'left'].indexOf(value) >= 0;
            }
        },
        value: {},
        rangeSeparator: {
            default: ' - '
        },
        pickerOptions: {}
    },

    components: { XInput },

    directives: { Clickoutside },

    data() {
        return {
            pickerVisible: false,
            showClose: false,
            currentValue: '',
            pickerDateForTime: '',
            pickerValueForTimeRange: '',
            TYPE_VALUE_RESOLVER_MAP: {
                default: {
                    formatter(value) {
                        if (!value) {
                            return '';
                        }
                        return '' + value;
                    },
                    parser(text) {
                        if (text === undefined || text === '') {
                            return null;
                        }
                        return text;
                    }
                },
                week: {
                    formatter(value) {
                        if (value instanceof Date) {
                            const weekNumber = getWeekNumber(value);
                            return value.getFullYear() + 'w' + (weekNumber > 9 ? weekNumber : '0' + weekNumber);
                        }
                        return value;
                    },
                    parser(text) {
                        const array = (text || '').split('w');
                        if (array.length === 2) {
                            const year = Number(array[0]);
                            const month = Number(array[1]);

                            if (!isNaN(year) && !isNaN(month) && month < 54) {
                                return text;
                            }
                        }
                        return null;
                    }
                },
                date: {
                    formatter: DATE_FORMATTER,
                    parser: DATE_PARSER
                },
                datetime: {
                    formatter: DATE_FORMATTER,
                    parser: DATE_PARSER
                },
                daterange: {
                    formatter: this.RANGE_FORMATTER,
                    parser: this.RANGE_PARSER
                },
                datetimerange: {
                    formatter: this.RANGE_FORMATTER,
                    parser: this.RANGE_PARSER
                },
                timerange: {
                    formatter: this.RANGE_FORMATTER,
                    parser: this.RANGE_PARSER
                },
                time: {
                    formatter: DATE_FORMATTER,
                    parser: DATE_PARSER
                },
                month: {
                    formatter: DATE_FORMATTER,
                    parser: DATE_PARSER
                },
                year: {
                    formatter: DATE_FORMATTER,
                    parser: DATE_PARSER
                },
                number: {
                    formatter(value) {
                        if (!value) {
                            return '';
                        }
                        return '' + value;
                    },
                    parser(text) {
                        let result = Number(text);

                        if (!isNaN(text)) {
                            return result;
                        }
                        return null;
                    }
                }
            }
        };
    },

    watch: {
        pickerVisible(val) {
            if (!val) {
                this.dispatch('XFormItem', 'x.form.blur');
            }
            if (this.readonly || this.disabled) {
                return;
            }
            val ? this.showPicker() : this.hidePicker();
        },
        currentValue(val) {
            if (val) {
                return;
            }
            if (this.picker && typeof this.picker.handleClear === 'function') {
                this.picker.handleClear();
            } else {
                this.$emit('input');
            }
        },
        value: {
            immediate: true,
            handler(val) {
                this.currentValue = isDate(val) ? new Date(val) : val;
            }
        },
        displayValue(val) {
            this.$emit('change', val);
            this.dispatch('XFormItem', 'x.form.change');
        }
    },

    computed: {
        reference() {
            return this.$refs.reference.$el;
        },

        refInput() {
            if (this.reference) {
                return this.reference.querySelector('input');
            }
            return {};
        },

        valueIsEmpty() {
            const val = this.currentValue;
            if (Array.isArray(val)) {
                for (let i = 0, len = val.length; i < len; i++) {
                    if (val[i]) {
                        return false;
                    }
                }
            } else {
                if (val) {
                    return false;
                }
            }
            return true;
        },

        triggerClass() {
            return this.type.indexOf('time') !== -1 ? 'x-icon-clock' : 'x-icon-calendar';
        },

        selectionMode() {
            if (this.type === 'week') {
                return 'week';
            } else if (this.type === 'month') {
                return 'month';
            } else if (this.type === 'year') {
                return 'year';
            }

            return 'day';
        },

        haveTrigger() {
            if (typeof this.showTrigger !== 'undefined') {
                return this.showTrigger;
            }
            return HAVE_TRIGGER_TYPES.indexOf(this.type) !== -1;
        },

        displayValue: {
            get() {
                const value = this.currentValue;
                if (!value) {
                    return;
                }
                const formatter = (
                    this.TYPE_VALUE_RESOLVER_MAP[this.type] ||
                    this.TYPE_VALUE_RESOLVER_MAP.default
                ).formatter;
                const format = DEFAULT_FORMATS[this.type];

                return formatter(value, this.format || format);
            },

            set(value) {
                if (value) {
                    const type = this.type;
                    const parser = (
                        this.TYPE_VALUE_RESOLVER_MAP.type ||
                        this.TYPE_VALUE_RESOLVER_MAP.default
                    ).parser;
                    const parsedValue = parser(value, this.format || DEFAULT_FORMATS[type]);

                    if (parsedValue && this.picker) {
                        this.picker.value = parsedValue;
                    }
                } else {
                    this.picker.value = value;
                }
                this.$forceUpdate();
            }
        }
    },

    created() {
        this.popperOptions = {
            boundariesPadding: 0,
            gpuAcceleration: false
        };
        this.placement = PLACEMENT_MAP[this.align] || PLACEMENT_MAP.left;
    },

    methods: {
        handleMouseEnterIcon() {
            if (this.readonly || this.disabled) {
                return;
            }
            if (!this.valueIsEmpty && this.clearable) {
                this.showClose = true;
            }
        },

        handleClickIcon() {
            if (this.readonly || this.disabled) {
                return;
            }
            if (this.showClose) {
                this.currentValue = '';
                this.showClose = false;
            } else {
                this.pickerVisible = !this.pickerVisible;
            }
        },

        dateChanged(dateA, dateB) {
            if (Array.isArray(dateA)) {
                let len = dateA.length;
                if (!dateB) {
                    return true;
                }
                while (len--) {
                    if (!equalDate(dateA[len], dateB[len])) {
                        return true;
                    }
                }
            } else {
                if (!equalDate(dateA, dateB)) {
                    return true;
                }
            }

            return false;
        },

        handleClose() {
            this.pickerVisible = false;
        },

        handleFocus() {
            const type = this.type;

            if (HAVE_TRIGGER_TYPES.indexOf(type) !== -1 && !this.pickerVisible) {
                this.pickerVisible = true;
            }
            this.$emit('focus', this);
        },

        handleBlur() {
            this.$emit('blur', this);
        },

        handleKeydown(event) {
            const keyCode = event.keyCode;

            // tab
            if (keyCode === 9) {
                this.pickerVisible = false;
            }
        },

        hidePicker() {
            if (this.picker) {
                this.picker.resetView && this.picker.resetView();
                this.handleVisible(false);
                // this.pickerVisible = this.picker.visible = false;
                this.destroyPopper();
            }
        },

        showPicker() {
            if (!this.picker) {
                // this.panel.defaultValue = this.currentValue;
                // this.picker = new Vue(this.panel).$mount(document.createElement('div'));
                this.picker = this.$refs.picker;
                // this.picker.defaultValue = this.currentValue;
                this.picker.popperClass = this.popperClass;
                this.popperElm = this.picker.$el;
                this.picker.width = this.reference.getBoundingClientRect().width;
                this.picker.showTime = this.type === 'datetime' || this.type === 'datetimerange';
                this.picker.selectionMode = this.selectionMode;
                if (this.format) {
                    this.picker.format = this.format;
                }

                const updateOptions = () => {
                    const options = this.pickerOptions;

                    if (options && options.selectableRange) {
                        let ranges = options.selectableRange;
                        const parser = this.TYPE_VALUE_RESOLVER_MAP.datetimerange.parser;
                        const format = DEFAULT_FORMATS.timerange;

                        ranges = Array.isArray(ranges) ? ranges : [ranges];
                        this.picker.selectableRange = ranges.map(range => parser(range, format));
                    }

                    for (const option in options) {
                        if (options.hasOwnProperty(option) &&
                            option !== 'selectableRange') {
                            this.picker[option] = options[option];
                        }
                    }
                };
                updateOptions();
                this.$watch('pickerOptions', () => updateOptions(), { deep: true });

                // this.$el.appendChild(this.picker.$el);
                // this.pickerVisible = this.picker.visible = true;
                this.handleVisible(true);

                this.picker.resetView && this.picker.resetView();

                this.picker.$on('dodestroy', this.doDestroy);
                this.picker.$on('pick', (date, visible = false) => {

                    if (this.type === 'daterange' || this.type === 'datetimerange') {
                        const options = this.pickerOptions;
                        if (options.dateLimit) {
                            // handle endDate with dateLimit
                            const startDate = date[0];
                            if (Object.prototype.toString.call(startDate) === '[object Date]') {
                                let limitEndDate = new Date(startDate.getTime());
                                Object.keys(options.dateLimit).forEach(v => {
                                    const num = options.dateLimit[v];
                                    if (!Number.isInteger(parseInt(num, 10)) || parseInt(num, 10) < 0) {
                                        console.warn(`xcui warn: dateLimit (${v}) must be a Positive Int Number`);
                                        return false;
                                    }
                                    switch (v) {
                                        case 'year':
                                            limitEndDate = limitEndDate.setFullYear(limitEndDate.getFullYear() + num);
                                            break;
                                        case 'month':
                                            limitEndDate = limitEndDate.setMonth(limitEndDate.getMonth() + num);
                                            break;
                                        case 'day':
                                            limitEndDate = limitEndDate.setDate(limitEndDate.getDate() + num);
                                            break;
                                        case 'hour':
                                            limitEndDate = limitEndDate.setHours(limitEndDate.getHours() + num);
                                            break;
                                        case 'minute':
                                            limitEndDate = limitEndDate.setMinutes(limitEndDate.getMinutes() + num);
                                            break;
                                        case 'second':
                                            limitEndDate = limitEndDate.setSeconds(limitEndDate.getSeconds() + num);
                                            break;
                                        default:
                                            break;
                                    }
                                    limitEndDate = new Date(limitEndDate);
                                });
                                console.log('limitEndDate', limitEndDate);
                                const endDate = date[1];
                                if (endDate > limitEndDate) {
                                    date[1] = limitEndDate;
                                    this.$emit('over-limit', startDate, endDate, limitEndDate);
                                }
                            }
                        }
                    }

                    this.$emit('input', date);
                    this.handleVisible(visible);

                    // this.pickerVisible = this.picker.visible = visible;
                    this.picker.resetView && this.picker.resetView();
                });

                this.picker.$on('select-range', (start, end) => {
                    this.refInput.setSelectionRange(start, end);
                    this.refInput.focus();
                });
            } else {
                this.handleVisible(true);
                // this.pickerVisible = this.picker.visible = true;
            }

            this.updatePopper();

            if (this.currentValue instanceof Date) {
                // 增加对time, timerange的处理
                if (this.type === 'time') {
                    this.pickerDateForTime = new Date(this.currentValue.getTime());
                } else {
                    this.picker.date = new Date(this.currentValue.getTime());
                }
            } else {
                if (this.type === 'timerange') {
                    this.pickerValueForTimeRange = this.currentValue;
                } else {
                    this.picker.value = this.currentValue;
                }
            }
            this.picker.resetView && this.picker.resetView();

            this.$nextTick(() => {
                this.picker.ajustScrollTop && this.picker.ajustScrollTop();
            });
        },

        handleVisible(visible) {
            if (this.type === 'time') {
                this.pickerVisible = visible;
            } else {
                this.pickerVisible = this.picker.visible = visible;
            }
        },

        RANGE_FORMATTER: function(value, format) {
            if (Array.isArray(value) && value.length === 2) {
                const start = value[0];
                const end = value[1];

                if (start && end) {
                    return formatDate(start, format) + this.rangeSeparator + formatDate(end, format);
                }
            }
            return '';
        },
        RANGE_PARSER: function(text, format) {
            const array = text.split(this.rangeSeparator);
            if (array.length === 2) {
                const range1 = array[0];
                const range2 = array[1];

                return [parseDate(range1, format), parseDate(range2, format)];
            }
            return [];
        }
    }
};
<commit_msg>[datepicker] fix dateLimit bug (#162)<commit_after>import Clickoutside from 'xcui/src/utils/clickoutside';
import { formatDate, parseDate, getWeekNumber, equalDate, isDate } from '../util';
import Popper from 'xcui/src/utils/vue-popper';
import Emitter from 'xcui/src/utils/mixins/emitter';
import XInput from '../../../input';

const NewPopper = {
    props: {
        appendToBody: Popper.props.appendToBody,
        offset: Popper.props.offset,
        boundariesPadding: Popper.props.boundariesPadding
    },
    methods: Popper.methods,
    data: Popper.data,
    beforeDestroy: Popper.beforeDestroy
};

const DEFAULT_FORMATS = {
    date: 'yyyy-MM-dd',
    month: 'yyyy-MM',
    datetime: 'yyyy-MM-dd HH:mm:ss',
    time: 'HH:mm:ss',
    timerange: 'HH:mm:ss',
    daterange: 'yyyy-MM-dd',
    datetimerange: 'yyyy-MM-dd HH:mm:ss',
    year: 'yyyy'
};
const HAVE_TRIGGER_TYPES = [
    'date',
    'datetime',
    'time',
    'time-select',
    'week',
    'month',
    'year',
    'daterange',
    'timerange',
    'datetimerange'
];
const DATE_FORMATTER = function(value, format) {
    return formatDate(value, format);
};
const DATE_PARSER = function(text, format) {
    return parseDate(text, format);
};

const PLACEMENT_MAP = {
    left: 'bottom-start',
    center: 'bottom-center',
    right: 'bottom-end'
};

export default {
    mixins: [Emitter, NewPopper],

    props: {
        size: String,
        format: String,
        readonly: Boolean,
        placeholder: String,
        disabled: Boolean,
        clearable: {
            type: Boolean,
            default: true
        },
        popperClass: String,
        editable: {
            type: Boolean,
            default: true
        },
        align: {
            type: String,
            default: 'left',
            validator(value) {
                return ['right', 'left'].indexOf(value) >= 0;
            }
        },
        value: {},
        rangeSeparator: {
            default: ' - '
        },
        pickerOptions: {}
    },

    components: { XInput },

    directives: { Clickoutside },

    data() {
        return {
            pickerVisible: false,
            showClose: false,
            currentValue: '',
            pickerDateForTime: '',
            pickerValueForTimeRange: '',
            TYPE_VALUE_RESOLVER_MAP: {
                default: {
                    formatter(value) {
                        if (!value) {
                            return '';
                        }
                        return '' + value;
                    },
                    parser(text) {
                        if (text === undefined || text === '') {
                            return null;
                        }
                        return text;
                    }
                },
                week: {
                    formatter(value) {
                        if (value instanceof Date) {
                            const weekNumber = getWeekNumber(value);
                            return value.getFullYear() + 'w' + (weekNumber > 9 ? weekNumber : '0' + weekNumber);
                        }
                        return value;
                    },
                    parser(text) {
                        const array = (text || '').split('w');
                        if (array.length === 2) {
                            const year = Number(array[0]);
                            const month = Number(array[1]);

                            if (!isNaN(year) && !isNaN(month) && month < 54) {
                                return text;
                            }
                        }
                        return null;
                    }
                },
                date: {
                    formatter: DATE_FORMATTER,
                    parser: DATE_PARSER
                },
                datetime: {
                    formatter: DATE_FORMATTER,
                    parser: DATE_PARSER
                },
                daterange: {
                    formatter: this.RANGE_FORMATTER,
                    parser: this.RANGE_PARSER
                },
                datetimerange: {
                    formatter: this.RANGE_FORMATTER,
                    parser: this.RANGE_PARSER
                },
                timerange: {
                    formatter: this.RANGE_FORMATTER,
                    parser: this.RANGE_PARSER
                },
                time: {
                    formatter: DATE_FORMATTER,
                    parser: DATE_PARSER
                },
                month: {
                    formatter: DATE_FORMATTER,
                    parser: DATE_PARSER
                },
                year: {
                    formatter: DATE_FORMATTER,
                    parser: DATE_PARSER
                },
                number: {
                    formatter(value) {
                        if (!value) {
                            return '';
                        }
                        return '' + value;
                    },
                    parser(text) {
                        let result = Number(text);

                        if (!isNaN(text)) {
                            return result;
                        }
                        return null;
                    }
                }
            }
        };
    },

    watch: {
        pickerVisible(val) {
            if (!val) {
                this.dispatch('XFormItem', 'x.form.blur');
            }
            if (this.readonly || this.disabled) {
                return;
            }
            val ? this.showPicker() : this.hidePicker();
        },
        currentValue(val) {
            if (val) {
                return;
            }
            if (this.picker && typeof this.picker.handleClear === 'function') {
                this.picker.handleClear();
            } else {
                this.$emit('input');
            }
        },
        value: {
            immediate: true,
            handler(val) {
                this.currentValue = isDate(val) ? new Date(val) : val;
            }
        },
        displayValue(val) {
            this.$emit('change', val);
            this.dispatch('XFormItem', 'x.form.change');
        }
    },

    computed: {
        reference() {
            return this.$refs.reference.$el;
        },

        refInput() {
            if (this.reference) {
                return this.reference.querySelector('input');
            }
            return {};
        },

        valueIsEmpty() {
            const val = this.currentValue;
            if (Array.isArray(val)) {
                for (let i = 0, len = val.length; i < len; i++) {
                    if (val[i]) {
                        return false;
                    }
                }
            } else {
                if (val) {
                    return false;
                }
            }
            return true;
        },

        triggerClass() {
            return this.type.indexOf('time') !== -1 ? 'x-icon-clock' : 'x-icon-calendar';
        },

        selectionMode() {
            if (this.type === 'week') {
                return 'week';
            } else if (this.type === 'month') {
                return 'month';
            } else if (this.type === 'year') {
                return 'year';
            }

            return 'day';
        },

        haveTrigger() {
            if (typeof this.showTrigger !== 'undefined') {
                return this.showTrigger;
            }
            return HAVE_TRIGGER_TYPES.indexOf(this.type) !== -1;
        },

        displayValue: {
            get() {
                const value = this.currentValue;
                if (!value) {
                    return;
                }
                const formatter = (
                    this.TYPE_VALUE_RESOLVER_MAP[this.type] ||
                    this.TYPE_VALUE_RESOLVER_MAP.default
                ).formatter;
                const format = DEFAULT_FORMATS[this.type];

                return formatter(value, this.format || format);
            },

            set(value) {
                if (value) {
                    const type = this.type;
                    const parser = (
                        this.TYPE_VALUE_RESOLVER_MAP.type ||
                        this.TYPE_VALUE_RESOLVER_MAP.default
                    ).parser;
                    const parsedValue = parser(value, this.format || DEFAULT_FORMATS[type]);

                    if (parsedValue && this.picker) {
                        this.picker.value = parsedValue;
                    }
                } else {
                    this.picker.value = value;
                }
                this.$forceUpdate();
            }
        }
    },

    created() {
        this.popperOptions = {
            boundariesPadding: 0,
            gpuAcceleration: false
        };
        this.placement = PLACEMENT_MAP[this.align] || PLACEMENT_MAP.left;
    },

    methods: {
        handleMouseEnterIcon() {
            if (this.readonly || this.disabled) {
                return;
            }
            if (!this.valueIsEmpty && this.clearable) {
                this.showClose = true;
            }
        },

        handleClickIcon() {
            if (this.readonly || this.disabled) {
                return;
            }
            if (this.showClose) {
                this.currentValue = '';
                this.showClose = false;
            } else {
                this.pickerVisible = !this.pickerVisible;
            }
        },

        dateChanged(dateA, dateB) {
            if (Array.isArray(dateA)) {
                let len = dateA.length;
                if (!dateB) {
                    return true;
                }
                while (len--) {
                    if (!equalDate(dateA[len], dateB[len])) {
                        return true;
                    }
                }
            } else {
                if (!equalDate(dateA, dateB)) {
                    return true;
                }
            }

            return false;
        },

        handleClose() {
            this.pickerVisible = false;
        },

        handleFocus() {
            const type = this.type;

            if (HAVE_TRIGGER_TYPES.indexOf(type) !== -1 && !this.pickerVisible) {
                this.pickerVisible = true;
            }
            this.$emit('focus', this);
        },

        handleBlur() {
            this.$emit('blur', this);
        },

        handleKeydown(event) {
            const keyCode = event.keyCode;

            // tab
            if (keyCode === 9) {
                this.pickerVisible = false;
            }
        },

        hidePicker() {
            if (this.picker) {
                this.picker.resetView && this.picker.resetView();
                this.handleVisible(false);
                // this.pickerVisible = this.picker.visible = false;
                this.destroyPopper();
            }
        },

        showPicker() {
            if (!this.picker) {
                // this.panel.defaultValue = this.currentValue;
                // this.picker = new Vue(this.panel).$mount(document.createElement('div'));
                this.picker = this.$refs.picker;
                // this.picker.defaultValue = this.currentValue;
                this.picker.popperClass = this.popperClass;
                this.popperElm = this.picker.$el;
                this.picker.width = this.reference.getBoundingClientRect().width;
                this.picker.showTime = this.type === 'datetime' || this.type === 'datetimerange';
                this.picker.selectionMode = this.selectionMode;
                if (this.format) {
                    this.picker.format = this.format;
                }

                const updateOptions = () => {
                    const options = this.pickerOptions;

                    if (options && options.selectableRange) {
                        let ranges = options.selectableRange;
                        const parser = this.TYPE_VALUE_RESOLVER_MAP.datetimerange.parser;
                        const format = DEFAULT_FORMATS.timerange;

                        ranges = Array.isArray(ranges) ? ranges : [ranges];
                        this.picker.selectableRange = ranges.map(range => parser(range, format));
                    }

                    for (const option in options) {
                        if (options.hasOwnProperty(option) &&
                            option !== 'selectableRange') {
                            this.picker[option] = options[option];
                        }
                    }
                };
                updateOptions();
                this.$watch('pickerOptions', () => updateOptions(), { deep: true });

                // this.$el.appendChild(this.picker.$el);
                // this.pickerVisible = this.picker.visible = true;
                this.handleVisible(true);

                this.picker.resetView && this.picker.resetView();

                this.picker.$on('dodestroy', this.doDestroy);
                this.picker.$on('pick', (date, visible = false) => {

                    if (this.type === 'daterange' || this.type === 'datetimerange') {
                        const options = this.pickerOptions;
                        if (options && options.dateLimit) {
                            // handle endDate with dateLimit
                            const startDate = date[0];
                            if (Object.prototype.toString.call(startDate) === '[object Date]') {
                                let limitEndDate = new Date(startDate.getTime());
                                Object.keys(options.dateLimit).forEach(v => {
                                    const num = options.dateLimit[v];
                                    if (!Number.isInteger(parseInt(num, 10)) || parseInt(num, 10) < 0) {
                                        console.warn(`xcui warn: dateLimit (${v}) must be a Positive Int Number`);
                                        return false;
                                    }
                                    switch (v) {
                                        case 'year':
                                            limitEndDate = limitEndDate.setFullYear(limitEndDate.getFullYear() + num);
                                            break;
                                        case 'month':
                                            limitEndDate = limitEndDate.setMonth(limitEndDate.getMonth() + num);
                                            break;
                                        case 'day':
                                            limitEndDate = limitEndDate.setDate(limitEndDate.getDate() + num);
                                            break;
                                        case 'hour':
                                            limitEndDate = limitEndDate.setHours(limitEndDate.getHours() + num);
                                            break;
                                        case 'minute':
                                            limitEndDate = limitEndDate.setMinutes(limitEndDate.getMinutes() + num);
                                            break;
                                        case 'second':
                                            limitEndDate = limitEndDate.setSeconds(limitEndDate.getSeconds() + num);
                                            break;
                                        default:
                                            break;
                                    }
                                    limitEndDate = new Date(limitEndDate);
                                });
                                console.log('limitEndDate', limitEndDate);
                                const endDate = date[1];
                                if (endDate > limitEndDate) {
                                    date[1] = limitEndDate;
                                    this.$emit('over-limit', startDate, endDate, limitEndDate);
                                }
                            }
                        }
                    }

                    this.$emit('input', date);
                    this.handleVisible(visible);

                    // this.pickerVisible = this.picker.visible = visible;
                    this.picker.resetView && this.picker.resetView();
                });

                this.picker.$on('select-range', (start, end) => {
                    this.refInput.setSelectionRange(start, end);
                    this.refInput.focus();
                });
            } else {
                this.handleVisible(true);
                // this.pickerVisible = this.picker.visible = true;
            }

            this.updatePopper();

            if (this.currentValue instanceof Date) {
                // 增加对time, timerange的处理
                if (this.type === 'time') {
                    this.pickerDateForTime = new Date(this.currentValue.getTime());
                } else {
                    this.picker.date = new Date(this.currentValue.getTime());
                }
            } else {
                if (this.type === 'timerange') {
                    this.pickerValueForTimeRange = this.currentValue;
                } else {
                    this.picker.value = this.currentValue;
                }
            }
            this.picker.resetView && this.picker.resetView();

            this.$nextTick(() => {
                this.picker.ajustScrollTop && this.picker.ajustScrollTop();
            });
        },

        handleVisible(visible) {
            if (this.type === 'time') {
                this.pickerVisible = visible;
            } else {
                this.pickerVisible = this.picker.visible = visible;
            }
        },

        RANGE_FORMATTER: function(value, format) {
            if (Array.isArray(value) && value.length === 2) {
                const start = value[0];
                const end = value[1];

                if (start && end) {
                    return formatDate(start, format) + this.rangeSeparator + formatDate(end, format);
                }
            }
            return '';
        },
        RANGE_PARSER: function(text, format) {
            const array = text.split(this.rangeSeparator);
            if (array.length === 2) {
                const range1 = array[0];
                const range2 = array[1];

                return [parseDate(range1, format), parseDate(range2, format)];
            }
            return [];
        }
    }
};
<|endoftext|>


<commit_before>var multiParty = function() {};
(function(){

var publicKeys = {};
var sharedSecrets = {};
var fingerprints = {};
var sharedSecret = {};
var myPrivateKey;
var myPublicKey;

multiParty.requestRegEx = /^\?:3multiParty:3\?:keyRequest$/;
multiParty.publicKeyRegEx = /^\?:3multiParty:3\?:PublicKey:(\w|=)+$/;

// AES-CTR-256 encryption
// No padding, starting IV of 0
// Input: Latin1, Output: Base64
// Key input: hexademical
encryptAES = function (msg, c, iv) {
	var opts = {
		mode: CryptoJS.mode.CTR,
		iv: CryptoJS.enc.Latin1.parse(iv),
		padding: CryptoJS.pad.NoPadding
	}
	var aesctr = CryptoJS.AES.encrypt (
		CryptoJS.enc.Latin1.parse(msg),
		CryptoJS.enc.Hex.parse(c),
		opts
	)
	return aesctr.toString();
}

// AES-CTR-256 decryption
// No padding, starting IV of 0
// Input: Base64, Output: Latin1
// Key input: hexadecimal
decryptAES = function (msg, c, iv) {
	msg = CryptoJS.enc.Base64.parse(msg);
	var opts = {
		mode: CryptoJS.mode.CTR,
		iv: CryptoJS.enc.Latin1.parse(iv),
		padding: CryptoJS.pad.NoPadding
	}
	var aesctr = CryptoJS.AES.decrypt(
		CryptoJS.enc.Base64.stringify(msg),
		CryptoJS.enc.Hex.parse(c),
		opts
	)
	return aesctr.toString(CryptoJS.enc.Latin1);
}

// HMAC-SHA512
// Output: Base64
// Key input: Hexademical
HMAC = function (msg, key) {
	return CryptoJS.HmacSHA512(
		msg, CryptoJS.enc.Hex.parse(key)
	).toString(CryptoJS.enc.Base64);
}

// Check if received public key is within safe size parameters
checkSize = function(publicKey) {
	var z = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4096, 0];
	publicKey = BigInt.str2bigInt(publicKey, 64);
	if ((BigInt.equals(publicKey, Curve25519.p25519)
		|| BigInt.greater(publicKey, Curve25519.p25519)
		|| BigInt.greater(z, publicKey))) {
		console.log('multiParty: unsafe key size');
		return false;
	}
	else {
		return true;
	}
}

// Generate private key (32 byte random number)
// Represented in decimal
multiParty.genPrivateKey = function() {
	myPrivateKey = Cryptocat.randomString(32, 0, 0, 1);
	return myPrivateKey;
}

// Generate public key (Curve 25519 Diffie-Hellman with basePoint 9)
// Represented in Base64
multiParty.genPublicKey = function() {
	myPublicKey = BigInt.bigInt2str(Curve25519.ecDH(myPrivateKey), 64);
	return myPublicKey;
}

// Generate shared secret (SHA512(scalarMult(myPrivateKey, theirPublicKey)))
// First 256 bytes are for encryption, last 256 bytes are for HMAC.
// Represented in hexadecimal
multiParty.genSharedSecret = function(user) {
	sharedSecrets[user] = CryptoJS.SHA512(
		Curve25519.ecDH(
			myPrivateKey, BigInt.str2bigInt(
				publicKeys[user], 64
			)
		)
	).toString();
	var names = [];
	for (var i in sharedSecrets) {
		names.push(i);
	}
	names.sort();
	sharedSecret = '';
	for (var i in names) {
		sharedSecret += sharedSecrets[i];
	}
	sharedSecret = CryptoJS.SHA512(sharedSecret).toString();
	sharedSecret = {
		'message': sharedSecret.substring(0, 64),
		'hmac': sharedSecret.substring(64, 128)
	}
	console.log(sharedSecret);
}

multiParty.genFingerprint = function(user) {
	fingerprints[user] = CryptoJS.SHA512(user + publicKeys[user])
		.toString()
		.substring(0, 40)
		.toUpperCase();
	return fingerprints[user];
}

// Send public key request string.
multiParty.sendPublicKeyRequest = function(user) {
	var request = {};
	request[user] = {};
	request[user]['message'] = '?:3multiParty:3?:keyRequest';
	return JSON.stringify(request);
}

// Send my public key in response to a public key request.
multiParty.sendPublicKey = function(user) {
	var answer = {};
	answer[user] = {};
	answer[user]['message'] = '?:3multiParty:3?:PublicKey:' + myPublicKey;
	return JSON.stringify(answer);
}

// Send message.
multiParty.sendMessage = function(message) {
	var encrypted = {};
	encrypted['*'] = {};
	encrypted['*']['message'] = encryptAES(message, sharedSecret['message'], 0);
	encrypted['*']['hmac'] = HMAC(encrypted['*']['message'], sharedSecret['hmac']);
	return JSON.stringify(encrypted);
}

// Receive message. Detects requests/reception of public keys.
multiParty.receiveMessage = function(sender, myName, message) {
	message = JSON.parse(message);
	if (message[myName]) {
		// Detect public key reception, store public key and generate shared secret
		if (message[myName]['message'].match(multiParty.publicKeyRegEx)) {
			if (!publicKeys[sender]) {
				var publicKey = message[myName]['message'].substring(27);
				if (checkSize(publicKey)) {
					publicKeys[sender] = publicKey;
					multiParty.genFingerprint(sender);
					multiParty.genSharedSecret(sender);
				}
			}
			return false;
		}
		// Detect public key request and send public key
		else if (message[myName]['message'].match(multiParty.requestRegEx)) {
			multiParty.sendPublicKey(sender);
		}
	}
	else if (message['*']) {
		// Decrypt message
		if (message['*']['hmac'] === HMAC(message['*']['message'], sharedSecret['hmac'])) {
			message = decryptAES(message['*']['message'], sharedSecret['message'], 0);
			return message;
		}
		else {
			console.log('multiParty: HMAC failure');
			return false;
		}
	}
	return false;
}

// Remove user keys and information
multiParty.removeKeys = function(user) {
	delete publicKeys[user];
	delete sharedSecrets[user];
	delete fingerprints[user];
}

// Remove ALL user keys and information
multiParty.resetKeys = function() {
	publicKeys = {};
	sharedSecrets = {};
	fingerprints = {};
	sharedSecret = {};
}

})();//:3<commit_msg>Recalculate group key on user leave<commit_after>var multiParty = function() {};
(function(){

var publicKeys = {};
var sharedSecrets = {};
var fingerprints = {};
var groupKey = {};
var myPrivateKey;
var myPublicKey;

multiParty.requestRegEx = /^\?:3multiParty:3\?:keyRequest$/;
multiParty.publicKeyRegEx = /^\?:3multiParty:3\?:PublicKey:(\w|=)+$/;

// AES-CTR-256 encryption
// No padding, starting IV of 0
// Input: Latin1, Output: Base64
// Key input: hexademical
encryptAES = function (msg, c, iv) {
	var opts = {
		mode: CryptoJS.mode.CTR,
		iv: CryptoJS.enc.Latin1.parse(iv),
		padding: CryptoJS.pad.NoPadding
	}
	var aesctr = CryptoJS.AES.encrypt (
		CryptoJS.enc.Latin1.parse(msg),
		CryptoJS.enc.Hex.parse(c),
		opts
	)
	return aesctr.toString();
}

// AES-CTR-256 decryption
// No padding, starting IV of 0
// Input: Base64, Output: Latin1
// Key input: hexadecimal
decryptAES = function (msg, c, iv) {
	msg = CryptoJS.enc.Base64.parse(msg);
	var opts = {
		mode: CryptoJS.mode.CTR,
		iv: CryptoJS.enc.Latin1.parse(iv),
		padding: CryptoJS.pad.NoPadding
	}
	var aesctr = CryptoJS.AES.decrypt(
		CryptoJS.enc.Base64.stringify(msg),
		CryptoJS.enc.Hex.parse(c),
		opts
	)
	return aesctr.toString(CryptoJS.enc.Latin1);
}

// HMAC-SHA512
// Output: Base64
// Key input: Hexademical
HMAC = function (msg, key) {
	return CryptoJS.HmacSHA512(
		msg, CryptoJS.enc.Hex.parse(key)
	).toString(CryptoJS.enc.Base64);
}

// Check if received public key is within safe size parameters
checkSize = function(publicKey) {
	var z = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4096, 0];
	publicKey = BigInt.str2bigInt(publicKey, 64);
	if ((BigInt.equals(publicKey, Curve25519.p25519)
		|| BigInt.greater(publicKey, Curve25519.p25519)
		|| BigInt.greater(z, publicKey))) {
		console.log('multiParty: unsafe key size');
		return false;
	}
	else {
		return true;
	}
}

// Generate private key (32 byte random number)
// Represented in decimal
multiParty.genPrivateKey = function() {
	myPrivateKey = Cryptocat.randomString(32, 0, 0, 1);
	return myPrivateKey;
}

// Generate public key (Curve 25519 Diffie-Hellman with basePoint 9)
// Represented in Base64
multiParty.genPublicKey = function() {
	myPublicKey = BigInt.bigInt2str(Curve25519.ecDH(myPrivateKey), 64);
	return myPublicKey;
}

// Generate shared secrets and group key (DIS DA BIG ONE)
// First 256 bytes are for encryption, last 256 bytes are for HMAC.
// Represented in hexadecimal
multiParty.genSharedSecret = function(user) {
	sharedSecrets[user] = CryptoJS.SHA512(
		Curve25519.ecDH(
			myPrivateKey, BigInt.str2bigInt(
				publicKeys[user], 64
			)
		)
	).toString();
	var names = [];
	for (var i in sharedSecrets) {
		names.push(i);
	}
	names.sort();
	groupKey = '';
	for (var i in names) {
		groupKey += sharedSecrets[i];
	}
	groupKey = CryptoJS.SHA512(groupKey).toString();
	groupKey = {
		'message': groupKey.substring(0, 64),
		'hmac': groupKey.substring(64, 128)
	}
	console.log(groupKey);
}

multiParty.genFingerprint = function(user) {
	fingerprints[user] = CryptoJS.SHA512(user + publicKeys[user])
		.toString()
		.substring(0, 40)
		.toUpperCase();
	return fingerprints[user];
}

// Send public key request string.
multiParty.sendPublicKeyRequest = function(user) {
	var request = {};
	request[user] = {};
	request[user]['message'] = '?:3multiParty:3?:keyRequest';
	return JSON.stringify(request);
}

// Send my public key in response to a public key request.
multiParty.sendPublicKey = function(user) {
	var answer = {};
	answer[user] = {};
	answer[user]['message'] = '?:3multiParty:3?:PublicKey:' + myPublicKey;
	return JSON.stringify(answer);
}

// Send message.
multiParty.sendMessage = function(message) {
	var encrypted = {};
	encrypted['*'] = {};
	encrypted['*']['message'] = encryptAES(message, groupKey['message'], 0);
	encrypted['*']['hmac'] = HMAC(encrypted['*']['message'], groupKey['hmac']);
	return JSON.stringify(encrypted);
}

// Receive message. Detects requests/reception of public keys.
multiParty.receiveMessage = function(sender, myName, message) {
	message = JSON.parse(message);
	if (message[myName]) {
		// Detect public key reception, store public key and generate shared secret
		if (message[myName]['message'].match(multiParty.publicKeyRegEx)) {
			if (!publicKeys[sender]) {
				var publicKey = message[myName]['message'].substring(27);
				if (checkSize(publicKey)) {
					publicKeys[sender] = publicKey;
					multiParty.genFingerprint(sender);
					multiParty.genSharedSecret(sender);
				}
			}
			return false;
		}
		// Detect public key request and send public key
		else if (message[myName]['message'].match(multiParty.requestRegEx)) {
			multiParty.sendPublicKey(sender);
		}
	}
	else if (message['*']) {
		// Decrypt message
		if (message['*']['hmac'] === HMAC(message['*']['message'], groupKey['hmac'])) {
			message = decryptAES(message['*']['message'], groupKey['message'], 0);
			return message;
		}
		else {
			console.log('multiParty: HMAC failure');
			return false;
		}
	}
	return false;
}

// Remove user keys and information
multiParty.removeKeys = function(user) {
	delete publicKeys[user];
	delete sharedSecrets[user];
	delete fingerprints[user];
	multiParty.genSharedSecret();
}

// Remove ALL user keys and information
multiParty.resetKeys = function() {
	publicKeys = {};
	sharedSecrets = {};
	fingerprints = {};
	groupKey = {};
}

})();//:3<|endoftext|>


<commit_before>import React from 'react';
import styled from 'styled-components';
import {Link, TitleSection,FileStatus} from 'components';
import {size, palette, font} from 'styled-theme';
import {
  Card,
  CardActions,
  CardHeader,
  CardMedia,
  CardTitle,
  CardText
} from 'material-ui/Card';
import {Grid, Row, Col} from 'react-flexbox-grid';
import Paper from 'material-ui/Paper';
import FlatButton from 'material-ui/FlatButton';
import Badge from 'material-ui/Badge';
import Comment from 'material-ui/svg-icons/communication/comment';

const Wrapper = styled.div `
  .img-media{
    text-align: center;
    img{
      height: auto;
      max-width: 100%;
    }
  }
  .options{
    padding: 0px 20px 0px 0px;
  }

.card-title{
  font-size: ${font('xxs')} !important;
	color: ${palette('basescale', 2)} !important;
  font-weight: 500;
}

`

class FileCardHorizontal extends React.Component {

  constructor(props) {
    super(props);
  }

  render() {
    return (
      <Wrapper>
        <Link to={`/file/summary/${this.props.record.id}`}>
          <Paper>
            <Row>
              <Col xs={12} sm={4} md={4} lg={4} className="img-media">
                <img src={`https://s3.amazonaws.com/sib-resources/images/catalogo/miniatura/png/t-anfibios.png`}/>
              </Col>
              <Col xs={12} sm={8} md={8} lg={8} className="paper-padding-1">

                  <TitleSection className="padding-bottom-1 card-title">{this.props.record.name}</TitleSection>
                  <FlatButton className="btn-option align-left" fullWidth={true}>
                    <Comment/> {this.props.record.comment}
                  </FlatButton>

                    Lorem ipsum dolor sit amet, consectetur piscing elipiscing elipiscing eliadipiscing elit. Morbi luctus leo non sapien tempus, ac cursus lectus tristique. Donec vitae mattis ante. Donec vitae mattis ante

                  <FileStatus />

              </Col>
            </Row>
          </Paper>
        </Link>
      </Wrapper>
    )
  }
}

export default FileCardHorizontal;
<commit_msg>update HorizontalCard responsive<commit_after>import React from 'react';
import styled from 'styled-components';
import {Link, TitleSection,FileStatus} from 'components';
import {size, palette, font} from 'styled-theme';
import {
  Card,
  CardActions,
  CardHeader,
  CardMedia,
  CardTitle,
  CardText
} from 'material-ui/Card';
import {Grid, Row, Col} from 'react-flexbox-grid';
import Paper from 'material-ui/Paper';
import FlatButton from 'material-ui/FlatButton';
import Badge from 'material-ui/Badge';
import Comment from 'material-ui/svg-icons/communication/comment';

const Wrapper = styled.div `
  .img-media{
    text-align: center;
    img{
      height: auto;
      max-width: 100%;
    }
  }
  .options{
    padding: 15px 20px 20px 20px;

  }

.card-title{
  text-overflow: ellipsis;
  white-space: nowrap;
  font-style: italic;
}
.card-subtitle{
  font-size: 12px !important;
}
.card-right{
  width: 100% !important;
  padding: 10px !important;
}
.card-footer{
  margin: 0 !important;
  font-size: 13px !important;
  background:  ${palette('basescale', 10)} !important;;
  padding: 0 12px !important;
  height: 30px !important;
  line-height: 30px !important;
  color:white !important;
  border-radius: 0px !important;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

`

class FileCardHorizontal extends React.Component {

  constructor(props) {
    super(props);
  }

  title(text){
    return text.split(' ').slice(0,2).join(' ');
  }
  subtitle(text){
    return text.split(' ').slice(2).join(' ');
  }

  render() {
    return (
      <Wrapper>
        <Link to={`/file/summary/${this.props.record.id}`}>
          <Paper>

            <Row>
              <Col xs={12} sm={4} md={4} lg={4} className="img-media">
                <img src={`https://s3.amazonaws.com/sib-resources/images/catalogo/miniatura/png/t-anfibios.png`}/>
              </Col>
              <Col xs={12} sm={8} md={8} lg={8} className="card-right">

                  <FileStatus title="EN"/>
                  <TitleSection className="padding-bottom-1 card-title">{this.title(this.props.record.scientificNameSimple)}</TitleSection>
                  <TitleSection className="card-subtitle">{this.subtitle(this.props.record.scientificNameSimple)}</TitleSection>

                    Lorem ipsum dolor sit amet, consectetur piscing elipiscing elipiscing eliadipiscing elit. Morbi luctus leo non sapien tempus, ac cursus lectus tristique. Donec vitae mattis ante. Donec vitae mattis ante

                    {this.props.record.creation_date}

              </Col>
            </Row>
          </Paper>
        </Link>
      </Wrapper>
    )
  }
}

export default FileCardHorizontal;
<|endoftext|>


<commit_before>angular
  .module('radioDemo2', ['ngMaterial'])
  .controller('ContactController', function($scope, $filter) {
    var self = this;

    self.contacts = [{
      'id': 1,
      'fullName': 'Maria Guadalupe',
      'lastName': 'Guadalupe',
      'title': "CEO, Found"
    }, {
      'id': 2,
      'fullName': 'Gabriel García Marquéz',
      'lastName': 'Marquéz',
      'title': "VP Sales & Marketing"
    }, {
      'id': 3,
      'fullName': 'Miguel de Cervantes',
      'lastName': 'Cervantes',
      'title': "Manager, Operations"
    }, {
      'id': 4,
      'fullName': 'Pacorro de Castel',
      'lastName': 'Castel',
      'title': "Security"
    }];
    self.selectedId = 2;
    self.selectedUser = function() {
      return $filter('filter')(self.contacts, { id: self.selectedId })[0].lastName;
    };
  });
<commit_msg>docs(radiobutton): correct two misspellings on demo (#11667)<commit_after>angular
  .module('radioDemo2', ['ngMaterial'])
  .controller('ContactController', function($scope, $filter) {
    var self = this;

    self.contacts = [{
      'id': 1,
      'fullName': 'María Guadalupe',
      'lastName': 'Guadalupe',
      'title': "CEO, Found"
    }, {
      'id': 2,
      'fullName': 'Gabriel García Márquez',
      'lastName': 'Márquez',
      'title': "VP Sales & Marketing"
    }, {
      'id': 3,
      'fullName': 'Miguel de Cervantes',
      'lastName': 'Cervantes',
      'title': "Manager, Operations"
    }, {
      'id': 4,
      'fullName': 'Pacorro de Castel',
      'lastName': 'Castel',
      'title': "Security"
    }];
    self.selectedId = 2;
    self.selectedUser = function() {
      return $filter('filter')(self.contacts, { id: self.selectedId })[0].lastName;
    };
  });
<|endoftext|>


<commit_before>const newBudgetFlag = true;

function getOldBudgetHistory(obj, args, context) {
  console.log('I am in the old budget');
  const logger = context.logger;
  const pool = context.pool;
  return pool.query(
    'SELECT * from coagis.v_budget_proposed_plus_history where year >= 2015'
  )
  .then((result) => {
    if (result.rows.length === 0) return null;
    const p = result.rows;
    return p;
  })
  .catch((err) => {
    if (err) {
      logger.error(`Got an error in property: ${err}`);
    }
  });
}

function newBudgetSummary(obj, args, context) {
  const logger = context.logger;
  const pool = context.pool;
  const which = args.breakdown;
  let categoryColumn = 'department_name';
  let view = 'amd.budget_summary_by_dept_view';
  let maxCategories = 10;
  if ('maxCategories' in args) maxCategories = args.maxCategories + 0;
  if (which === 'use') {
    categoryColumn = 'category_name';
    view = 'amd.budget_summary_by_use_view';
  }
  return pool.query('SELECT * from amd.budget_parameters_view')
  .then(bp => {
    if (bp.rows.length === 0) return null;
    const inBudgetSeason = bp.rows[0].in_budget_season === 'true';
    const defaultYear = bp.rows[0].defaultyear;
    const currentYear = bp.rows[0].currentyear;
    const isProposed = inBudgetSeason && currentYear === defaultYear;
    console.log(`inBudgetSeason = ${inBudgetSeason}, defaultYear = ${defaultYear}, current = ${currentYear}`);
    let endYear = currentYear;
    if ((inBudgetSeason && currentYear === defaultYear) ||
        (defaultYear > currentYear)) endYear = currentYear + 1;
    const startYear = inBudgetSeason ? currentYear - 2 : defaultYear - 3;
    console.log(`Start year is ${startYear}, end year is ${endYear}`);

    const query = `
      SELECT  account_type, year, total_proposed_budget, total_adopted_budget, total_actual,
              ${categoryColumn} AS category_name
      FROM ${view}
      WHERE year >= ${startYear} and year <= ${endYear}
      ORDER BY year desc, account_type
    `;
    return pool.query(query)
    .then((result) => {
      if (result.rows.length === 0) return null;
      return result.rows.map(itm => {
        const year = parseInt(itm.year, 10);
        // let useActual = true;
        // if (year > currentYear || year === defaultYear) {
        //   useActual = false;
        // }
        let derivedBudget = itm.total_adopted_budget;
        if (isProposed && year === endYear) derivedBudget = itm.total_proposed_budget;
        console.log(`${year}: ${itm.category_name} - actual: ${itm.total_actual}, budget: ${derivedBudget}`);
        return {
          account_type: itm.account_type,
          category_name: itm.category_name,
          year,
          total_budget: derivedBudget,
          total_actual: itm.total_actual,
        };
      });
    })
    .catch((err) => {
      if (err) {
        logger.error(`Got an error in property: ${err}`);
      }
    });
  });
}
// type SimpleBudgetSummary {
//   account_type: String,
//   category_name: String,
//   year: Int,
//   total_budget: Float,
//   total_actual: Float
// }

const resolvers = {
  Query: {
    budgetSummary(obj, args, context) {
      const logger = context.logger;
      const pool = context.pool;
      const which = args.breakdown;
      if (newBudgetFlag) {
        return newBudgetSummary(obj, args, context);
      }
      let categoryColumn = 'department_name';
      let view = 'coagis.v_budget_summary_by_dept';
      if (which === 'use') {
        categoryColumn = 'category_name';
        view = 'coagis.v_budget_summary_by_use';
      }

      let maxCategories = 10;
      if ('maxCategories' in args) maxCategories = args.maxCategories + 0;

      const query = `
        SELECT account_type, category_name, year, SUM(total_budget) as total_budget,
          SUM(total_actual) AS total_actual
        FROM (
          select
            account_type, year, total_budget, total_actual, row,
            case
              when row > ${maxCategories} or ${categoryColumn} = 'Non-Departmental Department'
              then 'Other'
              else ${categoryColumn}
            end AS category_name
          from ${view}
          where year >= 2015 and year <= 2018
        ) as ii
        GROUP BY account_type, category_name, year
        ORDER BY year desc, account_type, total_budget desc
      `;
      return pool.query(query)
      .then((result) => {
        if (result.rows.length === 0) return null;
        const p = result.rows;
        return p;
      })
      .catch((err) => {
        if (err) {
          logger.error(`Got an error in property: ${err}`);
        }
      });
    },
    budgetParameters(obj, args, context) {
      const pool = context.pool;
      return pool.query('SELECT * from amd.budget_parameters_view')
      .then(bp => {
        if (bp.rows.length === 0) return null;
        const inBudgetSeason = bp.rows[0].in_budget_season === 'true';
        const defaultYear = bp.rows[0].defaultyear;
        const currentYear = bp.rows[0].currentyear;
        let endYear = currentYear;
        if ((inBudgetSeason && currentYear === defaultYear) ||
            (defaultYear > currentYear)) endYear = currentYear + 1;
        const startYear = inBudgetSeason ? currentYear - 2 : defaultYear - 3;
        return {
          start_year: startYear,
          end_year: endYear,
          in_budget_season: (inBudgetSeason && currentYear === defaultYear),
        };
      });
    },
    budgetHistory(obj, args, context) {
      if (!newBudgetFlag) return getOldBudgetHistory(obj, args, context);
      const logger = context.logger;
      const pool = context.pool;
      return pool.query('SELECT * from amd.budget_parameters_view')
      .then(bp => {
        if (bp.rows.length === 0) return null;
        const inBudgetSeason = bp.rows[0].in_budget_season === 'true';
        const defaultYear = bp.rows[0].defaultyear;
        const currentYear = bp.rows[0].currentyear;
        const isProposed = inBudgetSeason && currentYear === defaultYear;
        console.log(`inBudgetSeason = ${inBudgetSeason}, defaultYear = ${defaultYear}, current = ${currentYear}`);
        let endYear = currentYear;
        if ((inBudgetSeason && currentYear === defaultYear) ||
            (defaultYear > currentYear)) endYear = currentYear + 1;
        const startYear = inBudgetSeason ? currentYear - 2 : defaultYear - 3;
        console.log(`Start year is ${startYear}, end year is ${endYear}`);
        const bhQuery = `SELECT * from amd.v_gl_5yr_plus_budget_mapped where year >= ${startYear} AND year <= ${endYear}`;
        console.log(`BHQUERY: ${bhQuery}`);
        return pool.query(bhQuery)
        .then((result) => {
          if (result.rows.length === 0) return null;
          return result.rows.map((itm) => {
            const year = parseInt(itm.year, 10);
            let useActual = true;
            if (year > currentYear || year === defaultYear) {
              useActual = false;
            }
            let derivedBudget = itm.adopted_budget;
            if (isProposed && year === endYear) derivedBudget = itm.proposed_budget;
            // Set isProposed on each line, so it only applies to new budget year
            return {
              account_type: itm.account_type,
              account_name: itm.object_name,
              fund_name: itm.fund_name,
              department_name: itm.department_name,
              division_name: itm.division_name,
              costcenter_name: itm.costcenter_name,
              function_name: itm.function_name,
              charcode_name: null,
              organization_name: itm.organization_name,
              category_name: itm.category_name,
              budget_section_name: itm.budget_section_name,
              object_name: itm.object_name,
              year: itm.year,
              budget: derivedBudget,
              actual: itm.actual,
              full_account_id: null,
              org_id: itm.organization_id,
              obj_id: itm.object_id,
              fund_id: itm.fund_id,
              dept_id: itm.department_id,
              div_id: itm.division_id,
              cost_id: itm.costcenter_id,
              func_id: itm.function_id,
              charcode: null,
              category_id: itm.category_name,
              budget_section_id: itm.budget_section_name,
              proj_id: itm.project_id,
              is_proposed: isProposed && itm.year === endYear,
              use_actual: useActual,
            };
          });
        })
        .catch((err) => {
          if (err) {
            logger.error(`Got an error in budget history: ${err}`);
          }
        });
      });
    },
    budgetCashFlow(obj, args, context) {
      const logger = context.logger;
      const pool = context.pool;
      let query = `
        SELECT account_type, department_name, dept_id, fund_id, fund_name,
          SUM(budget) as budget, NULL as category_name, NULL as category_id, year
        FROM coagis.v_budget_proposed_plus_history
        WHERE account_type = 'E' and year = 2018 and budget <> 0
        GROUP BY account_type, year, fund_id, fund_name, dept_id,
        department_name, category_id, category_name
      `;
      if (args.accountType === 'R') {
        query = `
        SELECT account_type, category_name, category_id, year, SUM(budget) as budget,
          fund_name, fund_id, NULL as dept_id, NULL as department_name
        FROM coagis.v_budget_proposed_plus_history
        WHERE account_Type = 'R' and year = 2018 and budget <> 0
        GROUP BY category_id, category_name, account_type, year, fund_id,
        fund_name, dept_id, department_name
      `;
      }
      return pool.query(query)
      .then((result) => {
        if (result.rows.length === 0) return null;
        const p = result.rows;
        return p;
      })
      .catch((err) => {
        if (err) {
          logger.error(`Got an error in property: ${err}`);
        }
      });
    },
  },
};

module.exports = resolvers;
<commit_msg>Updated budgetCashFlow resolver<commit_after>const newBudgetFlag = true;

function getOldBudgetHistory(obj, args, context) {
  console.log('I am in the old budget');
  const logger = context.logger;
  const pool = context.pool;
  return pool.query(
    'SELECT * from coagis.v_budget_proposed_plus_history where year >= 2015'
  )
  .then((result) => {
    if (result.rows.length === 0) return null;
    const p = result.rows;
    return p;
  })
  .catch((err) => {
    if (err) {
      logger.error(`Got an error in property: ${err}`);
    }
  });
}

const resolvers = {
  Query: {
    budgetSummary(obj, args, context) {
      const logger = context.logger;
      const pool = context.pool;
      const which = args.breakdown;
      let categoryColumn = 'department_name';
      let view = 'amd.budget_summary_by_dept_view';
      if (which === 'use') {
        categoryColumn = 'category_name';
        view = 'amd.budget_summary_by_use_view';
      }
      return pool.query('SELECT * from amd.budget_parameters_view')
      .then(bp => {
        if (bp.rows.length === 0) return null;
        const inBudgetSeason = bp.rows[0].in_budget_season === 'true';
        const defaultYear = bp.rows[0].defaultyear;
        const currentYear = bp.rows[0].currentyear;
        const isProposed = inBudgetSeason && currentYear === defaultYear;
        console.log(`inBudgetSeason = ${inBudgetSeason}, defaultYear = ${defaultYear}, current = ${currentYear}`);
        let endYear = currentYear;
        if ((inBudgetSeason && currentYear === defaultYear) ||
            (defaultYear > currentYear)) endYear = currentYear + 1;
        const startYear = inBudgetSeason ? currentYear - 2 : defaultYear - 3;

        const query = `
          SELECT  account_type, year, total_proposed_budget, total_adopted_budget, total_actual,
                  ${categoryColumn} AS category_name
          FROM ${view}
          WHERE year >= ${startYear} and year <= ${endYear}
          ORDER BY year desc, account_type
        `;
        return pool.query(query)
        .then((result) => {
          if (result.rows.length === 0) return null;
          const p = result.rows.map(itm => {
            const year = parseInt(itm.year, 10);
            let derivedBudget = itm.total_adopted_budget;
            if (isProposed && year === endYear) derivedBudget = itm.total_proposed_budget;
            return {
              account_type: itm.account_type,
              category_name: itm.category_name,
              year,
              total_budget: derivedBudget,
              total_actual: itm.total_actual,
            };
          });
          return p;
        })
        .catch((err) => {
          if (err) {
            logger.error(`Got an error in budgetSumary: ${err}`);
          }
        });
      });
    },
    budgetParameters(obj, args, context) {
      const pool = context.pool;
      return pool.query('SELECT * from amd.budget_parameters_view')
      .then(bp => {
        if (bp.rows.length === 0) return null;
        const inBudgetSeason = bp.rows[0].in_budget_season === 'true';
        const defaultYear = bp.rows[0].defaultyear;
        const currentYear = bp.rows[0].currentyear;
        let endYear = currentYear;
        if ((inBudgetSeason && currentYear === defaultYear) ||
            (defaultYear > currentYear)) endYear = currentYear + 1;
        const startYear = inBudgetSeason ? currentYear - 2 : defaultYear - 3;
        return {
          start_year: startYear,
          end_year: endYear,
          in_budget_season: (inBudgetSeason && currentYear === defaultYear),
        };
      });
    },
    budgetHistory(obj, args, context) {
      if (!newBudgetFlag) return getOldBudgetHistory(obj, args, context);
      const logger = context.logger;
      const pool = context.pool;
      return pool.query('SELECT * from amd.budget_parameters_view')
      .then(bp => {
        if (bp.rows.length === 0) return null;
        const inBudgetSeason = bp.rows[0].in_budget_season === 'true';
        const defaultYear = bp.rows[0].defaultyear;
        const currentYear = bp.rows[0].currentyear;
        const isProposed = inBudgetSeason && currentYear === defaultYear;
        console.log(`inBudgetSeason = ${inBudgetSeason}, defaultYear = ${defaultYear}, current = ${currentYear}`);
        let endYear = currentYear;
        if ((inBudgetSeason && currentYear === defaultYear) ||
            (defaultYear > currentYear)) endYear = currentYear + 1;
        const startYear = inBudgetSeason ? currentYear - 2 : defaultYear - 3;
        console.log(`Start year is ${startYear}, end year is ${endYear}`);
        const bhQuery = `SELECT * from amd.v_gl_5yr_plus_budget_mapped where year >= ${startYear} AND year <= ${endYear}`;
        console.log(`BHQUERY: ${bhQuery}`);
        return pool.query(bhQuery)
        .then((result) => {
          if (result.rows.length === 0) return null;
          return result.rows.map((itm) => {
            const year = parseInt(itm.year, 10);
            let useActual = true;
            if (year > currentYear || year === defaultYear) {
              useActual = false;
            }
            let derivedBudget = itm.adopted_budget;
            if (isProposed && year === endYear) derivedBudget = itm.proposed_budget;
            // Set isProposed on each line, so it only applies to new budget year
            return {
              account_type: itm.account_type,
              account_name: itm.object_name,
              fund_name: itm.fund_name,
              department_name: itm.department_name,
              division_name: itm.division_name,
              costcenter_name: itm.costcenter_name,
              function_name: itm.function_name,
              charcode_name: null,
              organization_name: itm.organization_name,
              category_name: itm.category_name,
              budget_section_name: itm.budget_section_name,
              object_name: itm.object_name,
              year: itm.year,
              budget: derivedBudget,
              actual: itm.actual,
              full_account_id: null,
              org_id: itm.organization_id,
              obj_id: itm.object_id,
              fund_id: itm.fund_id,
              dept_id: itm.department_id,
              div_id: itm.division_id,
              cost_id: itm.costcenter_id,
              func_id: itm.function_id,
              charcode: null,
              category_id: itm.category_name,
              budget_section_id: itm.budget_section_name,
              proj_id: itm.project_id,
              is_proposed: isProposed && itm.year === endYear,
              use_actual: useActual,
            };
          });
        })
        .catch((err) => {
          if (err) {
            logger.error(`Got an error in budget history: ${err}`);
          }
        });
      });
    },
    budgetCashFlow(obj, args, context) {
      const logger = context.logger;
      const pool = context.pool;
      return pool.query('SELECT * from amd.budget_parameters_view')
      .then(bp => {
        if (bp.rows.length === 0) return null;
        const inBudgetSeason = bp.rows[0].in_budget_season === 'true';
        const defaultYear = bp.rows[0].defaultyear;
        const currentYear = bp.rows[0].currentyear;
        const isProposed = inBudgetSeason && currentYear === defaultYear;
        console.log(`inBudgetSeason = ${inBudgetSeason}, defaultYear = ${defaultYear}, current = ${currentYear}`);
        let endYear = currentYear;
        if ((inBudgetSeason && currentYear === defaultYear) ||
            (defaultYear > currentYear)) endYear = currentYear + 1;
        const startYear = inBudgetSeason ? currentYear - 2 : defaultYear - 3;
        console.log(`Start year is ${startYear}, end year is ${endYear}`);

        let query = `
          SELECT account_type, department_name, department_name as dept_id, fund_id, fund_name,
            SUM(adopted_budget) as adopted_budget, SUM(proposed_budget) as proposed_budget,
            NULL as category_name, NULL as category_id, year
          FROM amd.v_gl_5yr_plus_budget_mapped
          WHERE account_type = 'E' and year = ${endYear}
          GROUP BY account_type, year, fund_id, fund_name, dept_id,
          department_name, category_id, category_name
        `;
        if (args.accountType === 'R') {
          query = `
          SELECT account_type, category_name, category_name as category_id, year,
            SUM(adopted_budget) as adopted_budget, SUM(proposed_budget) as proposed_budget,
            fund_name, fund_id, NULL as dept_id, NULL as department_name
          FROM amd.v_gl_5yr_plus_budget_mapped
          WHERE account_Type = 'R' and year = ${endYear}
          GROUP BY category_id, category_name, account_type, year, fund_id,
          fund_name, dept_id, department_name
        `;
        }
        return pool.query(query)
        .then((result) => {
          if (result.rows.length === 0) return null;
          const p = result.rows.map(itm => {
            const year = parseInt(itm.year, 10);
            let derivedBudget = itm.adopted_budget;
            if (isProposed && year === endYear) derivedBudget = itm.proposed_budget;
            return {
              account_type: itm.account_type,
              category_name: itm.category_name,
              category_id: itm.category_id,
              department_name: itm.department_name,
              dept_id: itm.dept_id,
              fund_id: itm.fund_id,
              fund_name: itm.fund_name,
              budget: derivedBudget,
              year: itm.year,
            };
          })
          .filter(itm => {
            return (itm.budget !== null && itm.budget !== 0.0);
          })
          .map(itm => {
            // console.log(itm);
            return itm;
          });
          return p;
        })
        .catch((err) => {
          if (err) {
            logger.error(`Got an error in property: ${err}`);
          }
        });
      });
    },
  },
};

module.exports = resolvers;
<|endoftext|>


<commit_before>/**
 * @copyright 2016-present, Prometheus Research, LLC
 * @flow
 */

import * as React from 'react';
import {wrapWithStylesheet} from './stylesheet';
import {chooseValue} from './Utils';
import * as theme from './theme';

type Props = {
  inline?: boolean;
  noWrap?: boolean;
  position?: 'relative' | 'absolute' | 'fixed',
  width?: number;
  height?: number;
  top?: number;
  left?: number;
  bottom?: number;
  right?: number;
  padding?: string | number;
  paddingV?: string | number;
  paddingH?: string | number;
  paddingLeft?: string | number;
  paddingRight?: string | number;
  paddingTop?: string | number;
  paddingBottom?: string | number;
  margin?: string | number;
  marginV?: string | number;
  marginH?: string | number;
  marginLeft?: string | number;
  marginRight?: string | number;
  marginTop?: string | number;
  marginBottom?: string | number;
  textAlign?: 'left' | 'right' | 'center',
  verticalAlign?: string;
  style?: Object;
};

export default function Block({
  inline,
  noWrap,
  position = 'relative',
  width, height, top, left, bottom, right,
  padding,
  paddingV, paddingH,
  paddingLeft, paddingRight, paddingTop, paddingBottom,
  margin,
  marginV, marginH,
  marginLeft, marginRight, marginTop, marginBottom,
  textAlign,
  verticalAlign,
  style,
  ...props
}: Props) {

  style = {
    paddingLeft: chooseValue(theme.padding, paddingLeft, paddingH, padding),
    paddingRight: chooseValue(theme.padding, paddingRight, paddingH, padding),
    paddingTop: chooseValue(theme.padding, paddingTop, paddingV, padding),
    paddingBottom: chooseValue(theme.padding, paddingBottom, paddingV, padding),
    marginLeft: chooseValue(theme.margin, marginLeft, marginH, margin),
    marginRight: chooseValue(theme.margin, marginRight, marginH, margin),
    marginTop: chooseValue(theme.margin, marginTop, marginV, margin),
    marginBottom: chooseValue(theme.margin, marginBottom, marginV, margin),
    display: inline ? 'inline-block' : 'block',
    whiteSpace: noWrap ? 'nowrap' : undefined,
    position,
    width, height, top, left, bottom, right,
    textAlign,
    verticalAlign,
    ...style,
  };
  return <div {...props} style={style} />;
}

Block.style = function style(stylesheet, displayName) {
  return wrapWithStylesheet(Block, stylesheet, displayName || 'Block');
};
<commit_msg>fix(block): do not override display prop<commit_after>/**
 * @copyright 2016-present, Prometheus Research, LLC
 * @flow
 */

import * as React from 'react';
import {wrapWithStylesheet} from './stylesheet';
import {chooseValue} from './Utils';
import * as theme from './theme';

type Props = {
  inline?: boolean;
  noWrap?: boolean;
  position?: 'relative' | 'absolute' | 'fixed',
  width?: number;
  height?: number;
  top?: number;
  left?: number;
  bottom?: number;
  right?: number;
  padding?: string | number;
  paddingV?: string | number;
  paddingH?: string | number;
  paddingLeft?: string | number;
  paddingRight?: string | number;
  paddingTop?: string | number;
  paddingBottom?: string | number;
  margin?: string | number;
  marginV?: string | number;
  marginH?: string | number;
  marginLeft?: string | number;
  marginRight?: string | number;
  marginTop?: string | number;
  marginBottom?: string | number;
  textAlign?: 'left' | 'right' | 'center',
  verticalAlign?: string;
  style?: Object;
};

export default function Block({
  inline,
  noWrap,
  position = 'relative',
  width, height, top, left, bottom, right,
  padding,
  paddingV, paddingH,
  paddingLeft, paddingRight, paddingTop, paddingBottom,
  margin,
  marginV, marginH,
  marginLeft, marginRight, marginTop, marginBottom,
  textAlign,
  verticalAlign,
  style,
  ...props
}: Props) {

  style = {
    paddingLeft: chooseValue(theme.padding, paddingLeft, paddingH, padding),
    paddingRight: chooseValue(theme.padding, paddingRight, paddingH, padding),
    paddingTop: chooseValue(theme.padding, paddingTop, paddingV, padding),
    paddingBottom: chooseValue(theme.padding, paddingBottom, paddingV, padding),
    marginLeft: chooseValue(theme.margin, marginLeft, marginH, margin),
    marginRight: chooseValue(theme.margin, marginRight, marginH, margin),
    marginTop: chooseValue(theme.margin, marginTop, marginV, margin),
    marginBottom: chooseValue(theme.margin, marginBottom, marginV, margin),
    display: inline ? 'inline-block' : undefined,
    whiteSpace: noWrap ? 'nowrap' : undefined,
    position,
    width, height, top, left, bottom, right,
    textAlign,
    verticalAlign,
    ...style,
  };
  return <div {...props} style={style} />;
}

Block.style = function style(stylesheet, displayName) {
  return wrapWithStylesheet(Block, stylesheet, displayName || 'Block');
};
<|endoftext|>


<commit_before>#!/usr/bin/env node
/* content/dev/misc/dnsresolvd/js/dnsresolvd.js
 * ============================================================================
 * DNS Resolver Daemon (dnsresolvd). Version 0.1
 * ============================================================================
 * A Node.js-boosted daemon for performing DNS lookups.
 * ============================================================================
 * Copyright (C) 2017 Radislav (Radicchio) Golubtsov
 *
 * (See the LICENSE file at the top of the source tree.)
 */

"use strict";

var path = require("path");
var http = require("http");
var url  = require("url");
var dns  = require("dns");

var __DNSRESOLVD_H = require("./dnsresolvd.h");

var aux = new __DNSRESOLVD_H();

/**
 * Performs DNS lookup action for the given hostname,
 * i.e. (in this case) IP address retrieval by hostname.
 *
 * It first prepares and runs the server instance, then does all the rest.
 *
 * @param _ret        The status code passed in from the caller.
 * @param port_number The server port number to listen on.
 * @param daemon_name The daemon name (executable/script name).
 *
 * @return The status code indicating the daemon overall execution outcome.
 */
var dns_lookup = function(_ret, port_number, daemon_name) {
    var ret = _ret;

    /*
     * Creating, configuring, and starting the server.
     *
     * @param req  The HTTP request object.
     * @param resp The HTTP response object.
     *
     * @return The HTTP server object.
     */
    var daemon = http.createServer(function(req, resp) {
        // Parsing and validating query params.
        var query = url.parse(req.url, true).query;

        // http://localhost:<port_number>/?h=<hostname>
        //                                 |
        var hostname = query.h; // <-------+

        if (!hostname) {
            hostname = aux._DEF_HOSTNAME;
        }

        /*
         * Performing DNS lookup for the given hostname
         * and writing the response.
         *
         * @param e    The Error object (if any error occurs).
         * @param addr The IP address retrieved.
         * @param ver  The IP version (family) used to look up to.
         */
        dns.lookup(hostname, function(e, addr, ver) {
            resp.writeHead(200, {
                "Content-Type" : aux._HDR_CONTENT_TYPE
            });

            resp.write("<!DOCTYPE html>" + aux._NEW_LINE
+ ""    + aux._NEW_LINE + ""              + aux._NEW_LINE
+ "<meta http-equiv=\"Content-Type\"    content=\"text/html; charset=UTF-8\" />" + aux._NEW_LINE
+ "<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\" />"         + aux._NEW_LINE
+ ""     + aux._NEW_LINE
+ "<meta http-equiv=\"Cache-Control\"   content=\"no-cache, no-store, must-revalidate\" /> " + aux._NEW_LINE
+ "<meta http-equiv=\"Expires\"         content=\"Thu, 01 Dec 1994 16:00:00 GMT\"       /> " + aux._NEW_LINE
+ "<meta http-equiv=\"Pragma\"          content=\"no-cache\"                            /> " + aux._NEW_LINE
+ "<meta       name=\"viewport\"        content=\"width=device-width,initial-scale=1\" />"                       + aux._NEW_LINE
            + "<title>DNS Resolver Daemon (dnsresolvd)</title>"      + aux._NEW_LINE
            + "" + aux._NEW_LINE + "" + aux._NEW_LINE
            + "
"     +      hostname + " ==> ");

            if (e) {
                resp.write(aux._ERR_PREFIX + aux._COLON_SPACE_SEP
                         + aux._ERR_COULD_NOT_LOOKUP);
            } else {
                resp.write(addr + " (IPv" + ver + ")");
            }

            resp.write("
" + aux._NEW_LINE
                  + "" + aux._NEW_LINE
                  + "" + aux._NEW_LINE);

            resp.end();
        });
    }).listen(port_number);

    daemon.on(aux._EVE_ERROR, function(e) {
        ret = aux._EXIT_FAILURE;

        if (e.code === aux._ERR_EADDRINUSE) {
            console.error(daemon_name + aux._ERR_CANNOT_START_SERVER
                                      + aux._ERR_SRV_PORT_IS_IN_USE
                                      + aux._NEW_LINE);
        } else {
            console.error(daemon_name + aux._ERR_CANNOT_START_SERVER
                                      + aux._ERR_SRV_UNKNOWN_REASON
                                      + aux._NEW_LINE);
        }

        return ret;
    });

    daemon.on(aux._EVE_LISTENING, function(e) {
        console.log(aux._MSG_SERVER_STARTED_1 + port_number + aux._NEW_LINE
                  + aux._MSG_SERVER_STARTED_2);
    });

    return ret;
};

/* Helper function. Draws a horizontal separator banner. */
var _separator_draw = function(banner_text) {
    var i = banner_text.length;

    do { process.stdout.write('='); i--; } while (i); console.log();
};

/** The daemon entry point. */
var main = function(argc, argv) {
    var ret = aux._EXIT_SUCCESS;

    var daemon_name = path.basename(argv[1]);
    var port_number = parseInt(argv[2], 10);

    _separator_draw(aux._DMN_DESCRIPTION);

    console.log(aux._DMN_NAME + aux._COMMA_SPACE_SEP  + aux._DMN_VERSION_S__
      + aux._ONE_SPACE_STRING + aux._DMN_VERSION      + aux._NEW_LINE
      + aux._DMN_DESCRIPTION                          + aux._NEW_LINE
      + aux._DMN_COPYRIGHT__  + aux._ONE_SPACE_STRING + aux._DMN_AUTHOR);

    _separator_draw(aux._DMN_DESCRIPTION);

    // Checking for args presence.
    if (argc !== 3) {
        ret = aux._EXIT_FAILURE;

        console.error(daemon_name + aux._ERR_MUST_BE_THE_ONLY_ARG_1
                     + (argc - 2) + aux._ERR_MUST_BE_THE_ONLY_ARG_2
                     + aux._NEW_LINE);

        console.error(aux._MSG_USAGE_TEMPLATE_1 + daemon_name
                    + aux._MSG_USAGE_TEMPLATE_2 + aux._NEW_LINE);

        return ret;
    }

    // Checking for port correctness.
    if (isNaN(port_number) || (port_number < aux._MIN_PORT)
                           || (port_number > aux._MAX_PORT)) {

        ret = aux._EXIT_FAILURE;

        console.error(daemon_name + aux._ERR_PORT_MUST_BE_POSITIVE_INT
                    + aux._NEW_LINE);

        console.error(aux._MSG_USAGE_TEMPLATE_1 + daemon_name
                    + aux._MSG_USAGE_TEMPLATE_2 + aux._NEW_LINE);

        return ret;
    }

    ret = dns_lookup(ret, port_number, daemon_name);

    return ret;
};

var argv = process.argv;
var argc = argv.length;

// Starting up the daemon.
var ret = main(argc, argv);

process.exitCode = ret;

// vim:set nu:et:ts=4:sw=4:
<commit_msg>(A mug of): dnsresolvd (Node.js): Add HTTP headers to the response.<commit_after>#!/usr/bin/env node
/* content/dev/misc/dnsresolvd/js/dnsresolvd.js
 * ============================================================================
 * DNS Resolver Daemon (dnsresolvd). Version 0.1
 * ============================================================================
 * A Node.js-boosted daemon for performing DNS lookups.
 * ============================================================================
 * Copyright (C) 2017 Radislav (Radicchio) Golubtsov
 *
 * (See the LICENSE file at the top of the source tree.)
 */

"use strict";

var path = require("path");
var http = require("http");
var url  = require("url");
var dns  = require("dns");

var __DNSRESOLVD_H = require("./dnsresolvd.h");

var aux = new __DNSRESOLVD_H();

/**
 * Performs DNS lookup action for the given hostname,
 * i.e. (in this case) IP address retrieval by hostname.
 *
 * It first prepares and runs the server instance, then does all the rest.
 *
 * @param _ret        The status code passed in from the caller.
 * @param port_number The server port number to listen on.
 * @param daemon_name The daemon name (executable/script name).
 *
 * @return The status code indicating the daemon overall execution outcome.
 */
var dns_lookup = function(_ret, port_number, daemon_name) {
    var ret = _ret;

    /*
     * Creating, configuring, and starting the server.
     *
     * @param req  The HTTP request object.
     * @param resp The HTTP response object.
     *
     * @return The HTTP server object.
     */
    var daemon = http.createServer(function(req, resp) {
        // Parsing and validating query params.
        var query = url.parse(req.url, true).query;

        // http://localhost:<port_number>/?h=<hostname>
        //                                 |
        var hostname = query.h; // <-------+

        if (!hostname) {
            hostname = aux._DEF_HOSTNAME;
        }

        /*
         * Performing DNS lookup for the given hostname
         * and writing the response.
         *
         * @param e    The Error object (if any error occurs).
         * @param addr The IP address retrieved.
         * @param ver  The IP version (family) used to look up to.
         */
        dns.lookup(hostname, function(e, addr, ver) {
            // Adding headers to the response.
            resp.writeHead(aux._RSC_HTTP_200_OK, {
                "Content-Type"  : aux._HDR_CONTENT_TYPE,
                "Cache-Control" : aux._HDR_CACHE_CONTROL,
                "Expires"       : aux._HDR_EXPIRES,
                "Pragma"        : aux._HDR_PRAGMA
            });

            resp.write("<!DOCTYPE html>" + aux._NEW_LINE
+ ""    + aux._NEW_LINE + ""              + aux._NEW_LINE
+ "<meta http-equiv=\"Content-Type\"    content=\"text/html; charset=UTF-8\" />" + aux._NEW_LINE
+ "<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\" />"         + aux._NEW_LINE
+ ""     + aux._NEW_LINE
+ "<meta http-equiv=\"Cache-Control\"   content=\"no-cache, no-store, must-revalidate\" /> " + aux._NEW_LINE
+ "<meta http-equiv=\"Expires\"         content=\"Thu, 01 Dec 1994 16:00:00 GMT\"       /> " + aux._NEW_LINE
+ "<meta http-equiv=\"Pragma\"          content=\"no-cache\"                            /> " + aux._NEW_LINE
+ "<meta       name=\"viewport\"        content=\"width=device-width,initial-scale=1\" />"                       + aux._NEW_LINE
            + "<title>DNS Resolver Daemon (dnsresolvd)</title>"      + aux._NEW_LINE
            + "" + aux._NEW_LINE + "" + aux._NEW_LINE
            + "
"     +      hostname + " ==> ");

            if (e) {
                resp.write(aux._ERR_PREFIX + aux._COLON_SPACE_SEP
                         + aux._ERR_COULD_NOT_LOOKUP);
            } else {
                resp.write(addr + " (IPv" + ver + ")");
            }

            resp.write("
" + aux._NEW_LINE
                  + "" + aux._NEW_LINE
                  + "" + aux._NEW_LINE);

            resp.end();
        });
    }).listen(port_number);

    daemon.on(aux._EVE_ERROR, function(e) {
        ret = aux._EXIT_FAILURE;

        if (e.code === aux._ERR_EADDRINUSE) {
            console.error(daemon_name + aux._ERR_CANNOT_START_SERVER
                                      + aux._ERR_SRV_PORT_IS_IN_USE
                                      + aux._NEW_LINE);
        } else {
            console.error(daemon_name + aux._ERR_CANNOT_START_SERVER
                                      + aux._ERR_SRV_UNKNOWN_REASON
                                      + aux._NEW_LINE);
        }

        return ret;
    });

    daemon.on(aux._EVE_LISTENING, function(e) {
        console.log(aux._MSG_SERVER_STARTED_1 + port_number + aux._NEW_LINE
                  + aux._MSG_SERVER_STARTED_2);
    });

    return ret;
};

/* Helper function. Draws a horizontal separator banner. */
var _separator_draw = function(banner_text) {
    var i = banner_text.length;

    do { process.stdout.write('='); i--; } while (i); console.log();
};

/** The daemon entry point. */
var main = function(argc, argv) {
    var ret = aux._EXIT_SUCCESS;

    var daemon_name = path.basename(argv[1]);
    var port_number = parseInt(argv[2], 10);

    _separator_draw(aux._DMN_DESCRIPTION);

    console.log(aux._DMN_NAME + aux._COMMA_SPACE_SEP  + aux._DMN_VERSION_S__
      + aux._ONE_SPACE_STRING + aux._DMN_VERSION      + aux._NEW_LINE
      + aux._DMN_DESCRIPTION                          + aux._NEW_LINE
      + aux._DMN_COPYRIGHT__  + aux._ONE_SPACE_STRING + aux._DMN_AUTHOR);

    _separator_draw(aux._DMN_DESCRIPTION);

    // Checking for args presence.
    if (argc !== 3) {
        ret = aux._EXIT_FAILURE;

        console.error(daemon_name + aux._ERR_MUST_BE_THE_ONLY_ARG_1
                     + (argc - 2) + aux._ERR_MUST_BE_THE_ONLY_ARG_2
                     + aux._NEW_LINE);

        console.error(aux._MSG_USAGE_TEMPLATE_1 + daemon_name
                    + aux._MSG_USAGE_TEMPLATE_2 + aux._NEW_LINE);

        return ret;
    }

    // Checking for port correctness.
    if (isNaN(port_number) || (port_number < aux._MIN_PORT)
                           || (port_number > aux._MAX_PORT)) {

        ret = aux._EXIT_FAILURE;

        console.error(daemon_name + aux._ERR_PORT_MUST_BE_POSITIVE_INT
                    + aux._NEW_LINE);

        console.error(aux._MSG_USAGE_TEMPLATE_1 + daemon_name
                    + aux._MSG_USAGE_TEMPLATE_2 + aux._NEW_LINE);

        return ret;
    }

    ret = dns_lookup(ret, port_number, daemon_name);

    return ret;
};

var argv = process.argv;
var argc = argv.length;

// Starting up the daemon.
var ret = main(argc, argv);

process.exitCode = ret;

// vim:set nu:et:ts=4:sw=4:
<|endoftext|>