<commit_before>/*
 * vim: ts=4:sw=4:expandtab
 */
(function () {
    'use strict';
    window.Whisper = window.Whisper || {};

    Whisper.FileSizeToast = Whisper.ToastView.extend({
        template: $('#file-size-modal').html()
    });

    Whisper.FileInputView = Backbone.View.extend({
        tagName: 'span',
        className: 'file-input',
        initialize: function(options) {
            this.$input = this.$('input[type=file]');
            this.thumb = new Whisper.AttachmentPreviewView();
            this.$el.addClass('file-input');
            this.window = options.window;
        },

        events: {
            'change': 'previewImages',
            'click .close': 'deleteFiles',
            'click .choose-file': 'open'
        },

        open: function() {
            // hack
            if (this.window && this.window.chrome && this.window.chrome.fileSystem) {
                this.window.chrome.fileSystem.chooseEntry({type: 'openFile'}, function(entry) {
                    if (!entry) {
                        return;
                    }
                    entry.file(function(file) {
                        this.file = file;
                        this.previewImages();
                    }.bind(this));
                }.bind(this));
            } else {
                this.$input.click();
            }
        },

        addThumb: function(src) {
            this.$('.avatar').hide();
            this.thumb.src = src;
            this.$('.attachment-previews').append(this.thumb.render().el);
            this.thumb.$('img')[0].onload = function() {
                this.$el.trigger('force-resize');
            }.bind(this);
        },

        autoScale: function(file) {
            if (file.type.split('/')[0] !== 'image' || file.type === 'image/gif') {
                // nothing to do
                return Promise.resolve(file);
            }

            return new Promise(function(resolve, reject) {
                var url = URL.createObjectURL(file);
                var img = document.createElement('img');
                img.onerror = reject;
                img.onload = function () {
                    URL.revokeObjectURL(url);

                    var maxSize = 420 * 1024;
                    var maxHeight = 1280;
                    var maxWidth = 1280;
                    if (img.width <= maxWidth && img.height <= maxHeight &&
                        file.size <= maxSize) {
                        resolve(file);
                        return;
                    }

                    // loadImage.scale -> components/blueimp-load-image
                    var canvas = loadImage.scale(img, {
                        canvas: true, maxWidth: maxWidth, maxHeight: maxHeight
                    });

                    var quality = 0.95;
                    var i = 4;
                    var blob;
                    do {
                        i = i - 1;
                        // dataURLtoBlob -> components/blueimp-canvas-to-blob
                        blob = dataURLtoBlob(
                            canvas.toDataURL('image/jpeg', quality)
                        );
                        quality = quality * maxSize / blob.size;
                        if (quality < 50) {
                            quality = 50;
                        }
                    } while (i > 0 && blob.size > maxSize);

                    resolve(blob);
                };
                img.src = url;
            });
        },

        previewImages: function() {
            this.clearForm();
            var file = this.file || this.$input.prop('files')[0];
            if (!file) { return; }

            var type = file.type.split('/')[0];
            switch (type) {
                case 'audio': this.addThumb('/images/audio.png'); break;
                case 'video': this.addThumb('/images/video.png'); break;
                case 'image':
                    this.oUrl = URL.createObjectURL(file);
                    this.addThumb(this.oUrl);
                    break;
            }

            this.autoScale(file).then(function(blob) {
                var limitKb = 1000000;
                var blobType = file.type === 'image/gif' ? 'gif' : type;
                switch (blobType) {
                    case 'image':
                        limitKb = 420; break;
                    case 'gif':
                        limitKb = 5000; break;
                    case 'audio':
                        limitKb = 100000; break;
                    case 'video':
                        limitKb = 100000; break;
                }
                if ((blob.size/1024).toFixed(4) >= limitKb) {
                    var units = ['kB','MB','GB'];
                    var u = -1;
                    var limit = limitKb * 1000;
                    do {
                      limit /= 1000;
                      ++u;
                    } while (limit >= 1000 && u < units.length - 1);
                    var toast = new Whisper.FileSizeToast({
                        model: {limit: limit, units: units[u]}
                    });
                    toast.$el.insertAfter(this.$el);
                    toast.render();
                    this.deleteFiles();
                }
            }.bind(this));
        },

        hasFiles: function() {
            var files = this.file ? [this.file] : this.$input.prop('files');
            return files && files.length && files.length > 0;
        },

        getFiles: function() {
            var promises = [];
            var files = this.file ? [this.file] : this.$input.prop('files');
            for (var i = 0; i < files.length; i++) {
                promises.push(this.getFile(files[i]));
            }
            this.clearForm();
            return Promise.all(promises);
        },

        getFile: function(file) {
            file = file || this.file || this.$input.prop('files')[0];
            if (file === undefined) { return Promise.resolve(); }
            return this.autoScale(file).then(this.readFile);
        },

        getThumbnail: function() {
            // Scale and crop an image to 256px square
            var size = 256;
            var file = this.file || this.$input.prop('files')[0];
            if (file === undefined || file.type.split('/')[0] !== 'image' || file.type === 'image/gif') {
                // nothing to do
                return Promise.resolve();
            }

            return new Promise(function(resolve, reject) {
                var url = URL.createObjectURL(file);
                var img = document.createElement('img');
                img.onerror = reject;
                img.onload = function () {
                    URL.revokeObjectURL(url);
                    // loadImage.scale -> components/blueimp-load-image
                    // scale, then crop.
                    var canvas = loadImage.scale(img, {
                        canvas: true, maxWidth: size, maxHeight: size,
                        cover: true, minWidth: size, minHeight: size
                    });
                    canvas = loadImage.scale(canvas, {
                        canvas: true, maxWidth: size, maxHeight: size,
                        crop: true, minWidth: size, minHeight: size
                    });

                    // dataURLtoBlob -> components/blueimp-canvas-to-blob
                    var blob = dataURLtoBlob(canvas.toDataURL('image/png'));

                    resolve(blob);
                };
                img.src = url;
            }).then(this.readFile);
        },

        readFile: function(file) {
            var contentType = file.type;
            return new Promise(function(resolve, reject) {
                var FR = new FileReader();
                FR.onload = function(e) {
                    resolve({data: e.target.result, contentType: contentType});
                };
                FR.readAsArrayBuffer(file);
            });
        },

        clearForm: function() {
            if (this.oUrl) {
                URL.revokeObjectURL(this.oUrl);
                this.oUrl = null;
            }
            this.thumb.remove();
            this.$('.avatar').show();
            this.$el.trigger('force-resize');
        },

        deleteFiles: function(e) {
            if (e) { e.stopPropagation(); }
            this.clearForm();
            this.$input.wrap('<form>').parent('form').trigger('reset');
            this.$input.unwrap();
            this.file = null;
        }
    });
})();
<commit_msg>Add drag and drop for attachments<commit_after>/*
 * vim: ts=4:sw=4:expandtab
 */
(function () {
    'use strict';
    window.Whisper = window.Whisper || {};

    Whisper.FileSizeToast = Whisper.ToastView.extend({
        template: $('#file-size-modal').html()
    });

    Whisper.FileInputView = Backbone.View.extend({
        tagName: 'span',
        className: 'file-input',
        initialize: function(options) {
            this.$input = this.$('input[type=file]');
            this.thumb = new Whisper.AttachmentPreviewView();
            this.$el.addClass('file-input');
            this.window = options.window;
        },

        events: {
            'change': 'previewImages',
            'click .close': 'deleteFiles',
            'click .choose-file': 'open',
            'drop': 'openDropped',
            'dragover': 'showArea',
            'dragleave': 'hideArea'
        },

        open: function() {
            // hack
            if (this.window && this.window.chrome && this.window.chrome.fileSystem) {
                this.window.chrome.fileSystem.chooseEntry({type: 'openFile'}, function(entry) {
                    if (!entry) {
                        return;
                    }
                    entry.file(function(file) {
                        this.file = file;
                        this.previewImages();
                    }.bind(this));
                }.bind(this));
            } else {
                this.$input.click();
            }
        },

        addThumb: function(src) {
            this.$('.avatar').hide();
            this.thumb.src = src;
            this.$('.attachment-previews').append(this.thumb.render().el);
            this.thumb.$('img')[0].onload = function() {
                this.$el.trigger('force-resize');
            }.bind(this);
        },

        autoScale: function(file) {
            if (file.type.split('/')[0] !== 'image' || file.type === 'image/gif') {
                // nothing to do
                return Promise.resolve(file);
            }

            return new Promise(function(resolve, reject) {
                var url = URL.createObjectURL(file);
                var img = document.createElement('img');
                img.onerror = reject;
                img.onload = function () {
                    URL.revokeObjectURL(url);

                    var maxSize = 420 * 1024;
                    var maxHeight = 1280;
                    var maxWidth = 1280;
                    if (img.width <= maxWidth && img.height <= maxHeight &&
                        file.size <= maxSize) {
                        resolve(file);
                        return;
                    }

                    // loadImage.scale -> components/blueimp-load-image
                    var canvas = loadImage.scale(img, {
                        canvas: true, maxWidth: maxWidth, maxHeight: maxHeight
                    });

                    var quality = 0.95;
                    var i = 4;
                    var blob;
                    do {
                        i = i - 1;
                        // dataURLtoBlob -> components/blueimp-canvas-to-blob
                        blob = dataURLtoBlob(
                            canvas.toDataURL('image/jpeg', quality)
                        );
                        quality = quality * maxSize / blob.size;
                        if (quality < 50) {
                            quality = 50;
                        }
                    } while (i > 0 && blob.size > maxSize);

                    resolve(blob);
                };
                img.src = url;
            });
        },

        previewImages: function() {
            this.clearForm();
            var file = this.file || this.$input.prop('files')[0];
            if (!file) { return; }

            var type = file.type.split('/')[0];
            switch (type) {
                case 'audio': this.addThumb('/images/audio.png'); break;
                case 'video': this.addThumb('/images/video.png'); break;
                case 'image':
                    this.oUrl = URL.createObjectURL(file);
                    this.addThumb(this.oUrl);
                    break;
            }

            this.autoScale(file).then(function(blob) {
                var limitKb = 1000000;
                var blobType = file.type === 'image/gif' ? 'gif' : type;
                switch (blobType) {
                    case 'image':
                        limitKb = 420; break;
                    case 'gif':
                        limitKb = 5000; break;
                    case 'audio':
                        limitKb = 100000; break;
                    case 'video':
                        limitKb = 100000; break;
                }
                if ((blob.size/1024).toFixed(4) >= limitKb) {
                    var units = ['kB','MB','GB'];
                    var u = -1;
                    var limit = limitKb * 1000;
                    do {
                      limit /= 1000;
                      ++u;
                    } while (limit >= 1000 && u < units.length - 1);
                    var toast = new Whisper.FileSizeToast({
                        model: {limit: limit, units: units[u]}
                    });
                    toast.$el.insertAfter(this.$el);
                    toast.render();
                    this.deleteFiles();
                }
            }.bind(this));
        },

        hasFiles: function() {
            var files = this.file ? [this.file] : this.$input.prop('files');
            return files && files.length && files.length > 0;
        },

        getFiles: function() {
            var promises = [];
            var files = this.file ? [this.file] : this.$input.prop('files');
            for (var i = 0; i < files.length; i++) {
                promises.push(this.getFile(files[i]));
            }
            this.clearForm();
            return Promise.all(promises);
        },

        getFile: function(file) {
            file = file || this.file || this.$input.prop('files')[0];
            if (file === undefined) { return Promise.resolve(); }
            return this.autoScale(file).then(this.readFile);
        },

        getThumbnail: function() {
            // Scale and crop an image to 256px square
            var size = 256;
            var file = this.file || this.$input.prop('files')[0];
            if (file === undefined || file.type.split('/')[0] !== 'image' || file.type === 'image/gif') {
                // nothing to do
                return Promise.resolve();
            }

            return new Promise(function(resolve, reject) {
                var url = URL.createObjectURL(file);
                var img = document.createElement('img');
                img.onerror = reject;
                img.onload = function () {
                    URL.revokeObjectURL(url);
                    // loadImage.scale -> components/blueimp-load-image
                    // scale, then crop.
                    var canvas = loadImage.scale(img, {
                        canvas: true, maxWidth: size, maxHeight: size,
                        cover: true, minWidth: size, minHeight: size
                    });
                    canvas = loadImage.scale(canvas, {
                        canvas: true, maxWidth: size, maxHeight: size,
                        crop: true, minWidth: size, minHeight: size
                    });

                    // dataURLtoBlob -> components/blueimp-canvas-to-blob
                    var blob = dataURLtoBlob(canvas.toDataURL('image/png'));

                    resolve(blob);
                };
                img.src = url;
            }).then(this.readFile);
        },

        readFile: function(file) {
            var contentType = file.type;
            return new Promise(function(resolve, reject) {
                var FR = new FileReader();
                FR.onload = function(e) {
                    resolve({data: e.target.result, contentType: contentType});
                };
                FR.readAsArrayBuffer(file);
            });
        },

        clearForm: function() {
            if (this.oUrl) {
                URL.revokeObjectURL(this.oUrl);
                this.oUrl = null;
            }
            this.thumb.remove();
            this.$('.avatar').show();
            this.$el.trigger('force-resize');
        },

        deleteFiles: function(e) {
            if (e) { e.stopPropagation(); }
            this.clearForm();
            this.$input.wrap('<form>').parent('form').trigger('reset');
            this.$input.unwrap();
            this.file = null;
        },

        openDropped: function(e) {
            e.stopPropagation();
            e.preventDefault();
            this.file = e.originalEvent.dataTransfer.files[0];
            this.previewImages();
            this.$el.removeClass("dropoff");
        },

        showArea: function(e) {
            e.stopPropagation();
            e.preventDefault();
            this.$el.addClass("dropoff");
        },

        hideArea: function(e) {
            e.stopPropagation();
            e.preventDefault();
            this.$el.removeClass("dropoff");
        }
    });
})();
<|endoftext|>


<commit_before>(function () {
	var root = this;

	var timer = function () {

	};

	var Datetime = function () {

	};

	Datetime.dhmsRegex = /^(?:(\d+)d)?(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?$/i;

	Datetime.isDhms = function (s) {
		return Datetime.dhmsRegex.test(s);
	};

	Datetime.parseDhms = function (s) {
		var res = Datetime.dhmsRegex.exec(s);

		if (null === res) {
			return null;
		} else {
			return {
				day: res[1] ? +res[1] : 0,
				hour: res[2] ? +res[2] : 0,
				minute: res[3] ? +res[3] : 0,
				second: res[4] ? +res[4] : 0
			}
		}
	};

	var monthMapping = {
		'jan': 0,
		'feb': 1,
		'mar': 2,
		'apr': 3,
		'may': 4,
		'jun': 5,
		'jul': 6,
		'aug': 7,
		'sep': 8,
		'oct': 9,
		'nov': 10,
		'dev': 11
	};

	Datetime.dtRegex = /^(10|11|12|[0-9])([0-5][0-9])?([0-5][0-9])?([ap]m)(?:(\d{1,2})(jan|january|feb|feb|february|mar|march|apr|april|may|jun|june|jul|july|aug|august|sep|september|oct|october|nov|november|dec|december)(\d{4})?)?$/i;

	Datetime.isDt = function (s) {
		var res = Datetime.dtRegex.exec(s);

		if (null === res) {
			return false;
		} else {
			var now = new Date(),
				hour = +res[1] + ('pm' === res[4] ? 12 : 0),
				minute = res[2] ? +res[2] : 0,
				second = res[3] ? +res[3] : 0,
				day = res[5] ? +res[5] : now.getDate(),
				month = res[6] ? monthMapping[res[6].substring(0, 3).toLowerCase()] : now.getMonth(),
				year = res[7] ? +res[7] : now.getFullYear(),
				testDate = new Date(year, month, day, hour, minute, second);

			if (!(testDate.getFullYear() === year && testDate.getMonth() === month && testDate.getDate())) {
				return false;
			} else {
				return true;
			}
		}

	};

	Datetime.parseDt = function (s) {

		if (!Datetime.isDt(s)) {
			return null;
		} else {
			var res = Datetime.dtRegex.exec(s);

			return {
				hour: +res[1] + ('pm' === res[4] ? 12 : 0),
				minute: res[2] ? +res[2] : 0,
				second: res[3] ? +res[3] : 0,
				day: res[5] ? +res[5] : null,
				month: res[6] ? monthMapping[res[6].substring(0, 3).toLowerCase()] : null,
				year: res[7] ? +res[7] : null
			};
		}
	}

	Datetime.countRegex = /^(\d+)$/;

	Datetime.isCount = function (s) {
		return Datetime.countRegex.test(s);
	};

	Datetime.parseCount = function (s) {
		var res = Datetime.countRegex.exec(s);

		if (null === res) {
			return null;
		} else {
			return +res[1];
		}
	};

	Datetime.isParsable = function (s) {
		return Datetime.isDhms(s) || Datetime.isDt(s) || Datetime.isCount(s);
	};

	Datetime.makeDatetime = function (s) {
		if (!Datetime.isParsable(s)) {
			return null;
		}

		if (Datetime.isCount(s)) {
			return new Date(60 * Datetime.parseCount(s));
		} else if (Datetime.isDhms(s)) {
			var dhms = Datetime.parseDhms(s);

			return new Date((86400 * dhms.day + 3600 * dhms.hour + 60 * dhms.minute + dhms.second) * 1000);
		} else if (Datetime.isDt(s)) {
			var dt = Datetime.parseDt(s),
				now = new Date();

			if (!dt.year) {
				dt.year = now.getFullYear();
			}

			if (!dt.day) {
				var testDate = new Date();
				testDate.setHours(dt.hour);
				testDate.setMinutes(dt.minute);
				testDate.setSeconds(dt.second);
				if (testDate < now) {
					dt.day = now.getDate() + 1;
				}
				dt.month = now.getMonth();
			}

			return new Date(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second);
		} else {
			return null;
		}
	};

	timer.Datetime = Datetime;

	// TODO: export to module.exports for node.js compatibility
	root.timer = timer;
}.call(this));
<commit_msg>delete redundant<commit_after>(function () {
	var root = this;

	var timer = function () {

	};

	var Datetime = function () {

	};

	Datetime.dhmsRegex = /^(?:(\d+)d)?(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?$/i;

	Datetime.isDhms = function (s) {
		return Datetime.dhmsRegex.test(s);
	};

	Datetime.parseDhms = function (s) {
		var res = Datetime.dhmsRegex.exec(s);

		if (null === res) {
			return null;
		} else {
			return {
				day: res[1] ? +res[1] : 0,
				hour: res[2] ? +res[2] : 0,
				minute: res[3] ? +res[3] : 0,
				second: res[4] ? +res[4] : 0
			}
		}
	};

	var monthMapping = {
		'jan': 0,
		'feb': 1,
		'mar': 2,
		'apr': 3,
		'may': 4,
		'jun': 5,
		'jul': 6,
		'aug': 7,
		'sep': 8,
		'oct': 9,
		'nov': 10,
		'dev': 11
	};

	Datetime.dtRegex = /^(10|11|12|[0-9])([0-5][0-9])?([0-5][0-9])?([ap]m)(?:(\d{1,2})(jan|january|feb|feb|february|mar|march|apr|april|may|jun|june|jul|july|aug|august|sep|september|oct|october|nov|november|dec|december)(\d{4})?)?$/i;

	Datetime.isDt = function (s) {
		var res = Datetime.dtRegex.exec(s);

		if (null === res) {
			return false;
		} else {
			var now = new Date(),
				hour = +res[1] + ('pm' === res[4] ? 12 : 0),
				minute = res[2] ? +res[2] : 0,
				second = res[3] ? +res[3] : 0,
				day = res[5] ? +res[5] : now.getDate(),
				month = res[6] ? monthMapping[res[6].substring(0, 3).toLowerCase()] : now.getMonth(),
				year = res[7] ? +res[7] : now.getFullYear(),
				testDate = new Date(year, month, day, hour, minute, second);

			if (!(testDate.getFullYear() === year && testDate.getMonth() === month && testDate.getDate())) {
				return false;
			} else {
				return true;
			}
		}

	};

	Datetime.parseDt = function (s) {

		if (!Datetime.isDt(s)) {
			return null;
		} else {
			var res = Datetime.dtRegex.exec(s);

			return {
				hour: +res[1] + ('pm' === res[4] ? 12 : 0),
				minute: res[2] ? +res[2] : 0,
				second: res[3] ? +res[3] : 0,
				day: res[5] ? +res[5] : null,
				month: res[6] ? monthMapping[res[6].substring(0, 3).toLowerCase()] : null,
				year: res[7] ? +res[7] : null
			};
		}
	}

	Datetime.countRegex = /^(\d+)$/;

	Datetime.isCount = function (s) {
		return Datetime.countRegex.test(s);
	};

	Datetime.parseCount = function (s) {
		var res = Datetime.countRegex.exec(s);

		if (null === res) {
			return null;
		} else {
			return +res[1];
		}
	};

	Datetime.isParsable = function (s) {
		return Datetime.isDhms(s) || Datetime.isDt(s) || Datetime.isCount(s);
	};

	Datetime.makeDatetime = function (s) {

		if (Datetime.isCount(s)) {
			return new Date(60 * Datetime.parseCount(s));
		} else if (Datetime.isDhms(s)) {
			var dhms = Datetime.parseDhms(s);

			return new Date((86400 * dhms.day + 3600 * dhms.hour + 60 * dhms.minute + dhms.second) * 1000);
		} else if (Datetime.isDt(s)) {
			var dt = Datetime.parseDt(s),
				now = new Date();

			if (!dt.year) {
				dt.year = now.getFullYear();
			}

			if (!dt.day) {
				var testDate = new Date();
				testDate.setHours(dt.hour);
				testDate.setMinutes(dt.minute);
				testDate.setSeconds(dt.second);
				if (testDate < now) {
					dt.day = now.getDate() + 1;
				}
				dt.month = now.getMonth();
			}

			return new Date(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second);
		} else {
			return null;
		}
	};

	timer.Datetime = Datetime;

	// TODO: export to module.exports for node.js compatibility
	root.timer = timer;
}.call(this));
<|endoftext|>


<commit_before>import React from 'react';
import Component from 'react-pure-render/component';
import './app.scss';
import Row from './atoms/Row.jsx';
import Col from './atoms/Col.jsx';
import Icon from './atoms/Icon.jsx';
import Counter from './temp/Counter.jsx';
import Event, {
  EventName, RoundBadge, Badge, SquareBadge
} from './calendar/Event.jsx';
import Colors from './styles/colors';
import DebugGrid from './temp/DebugGrid.jsx';
import WeekExample from './temp/WeekExample.jsx';
import classNames from 'classnames';

//TODO bc: remove these components
const S = ({width}) => (<span style={{width: `${width}px`}}>);
const S5 = () => (<S width={5}/>);
const S10 = () => (<S width={10}/>);

export class App extends Component {
  constructor(props) {
    super(props);
    this.state = {appLevelClasses: 'debug-baseline debug-container'};
  }
  render() {
    const setAppStateClasses = classesToSet => {
      this.setState({
        appLevelClasses: classNames('', classesToSet)
      });
    };

    return (

        <DebugGrid setDebugClasses={setAppStateClasses}/>

EVENT COMPONENTS

            <Row>
              <Col sm={2}>
Name:
</Col>
              <Col sm={3}><EventName className="debug">John C. Schlesinger Memorial Circuit Race and Team Time Trial</EventName></Col>
            </Row>
            <Row className="margin-top">
              <Col sm={2}>
Round Badges:
</Col>
              <Col sm={12} className="display-flex">
                <RoundBadge size={2}>8</RoundBadge>
                <RoundBadge size={1}>8</RoundBadge>
                <RoundBadge size={2}><Icon name="car"/></RoundBadge>
                <RoundBadge size={1}><Icon name="car"/></RoundBadge>
                <RoundBadge size={2}>RR</RoundBadge>
                <RoundBadge size={1}>RR</RoundBadge>
                <RoundBadge size={2}>TT</RoundBadge>
                <RoundBadge size={1}>TT</RoundBadge><S5/>
                <RoundBadge size={2} className="Inverted">RR</RoundBadge><S5/>
                <RoundBadge size={2} className="Inverted">8</RoundBadge><S5/>
                <RoundBadge size={1} className="Inverted">8</RoundBadge><S5/>
                <RoundBadge size={2} className="Inverted"><Icon name="car"/></RoundBadge><S5/>
                <RoundBadge size={1} className="Inverted"><Icon name="car"/></RoundBadge>
              </Col>
            </Row>
            <Row>
              <Col sm={2}>
Not so Round Badges:
</Col>
              <Col sm={12} className="display-flex">
                <Badge>120mi</Badge><S5/>
                <Badge>8</Badge><S5/>
                <Badge><Icon name="trophy"/></Badge><S5/>
                <Badge><Icon name="sun-o"/></Badge><S5/>
                <Badge><Icon name="map-marker"/><S5/>Monterey, CA</Badge><S5/>
                <Badge className="Inverted"><Icon name="map-marker"/><S5/>Monterey, CA</Badge>
              </Col>
            </Row>
            <Row>
              <Col sm={2}>
Square Badges:
</Col>
              <Col sm={12} className="display-flex">
                <SquareBadge>120mi</SquareBadge><S5/>
                <SquareBadge>8</SquareBadge><S5/>
                <SquareBadge><Icon name="trophy"/></SquareBadge><S5/>
                <SquareBadge><Icon name="sun-o"/></SquareBadge><S5/>
                <SquareBadge><Icon name="map-marker"/><S5/>Monterey, CA</SquareBadge>
              </Col>
            </Row>
            <Row>
              <Col sm={2}>
Square Badges (Inverted):
</Col>
              <Col sm={12} className="display-flex">
                <SquareBadge className="Inverted">120mi</SquareBadge><S5/>
                <SquareBadge className="Inverted">8</SquareBadge><S5/>
                <SquareBadge className="Inverted"><Icon name="trophy"/></SquareBadge><S5/>
                <SquareBadge className="Inverted"><Icon name="sun-o"/></SquareBadge><S5/>
                <SquareBadge className="Inverted"><Icon name="map-marker"/><S5/>Monterey, CA</SquareBadge>
              </Col>
            </Row>
            <Row>
              <Col sm={2}>
Elevation:
</Col>
              <Col sm={12} className="display-flex">
                <Icon name="arrow-up" color={Colors.grey500}/>1200ft<S10/>
                <Icon name="long-arrow-up" color={Colors.grey500}/>1200ft<S10/>
                <Badge><Icon name="arrow-up"/>1200ft<S10/></Badge><S5/>
                <Badge><Icon name="long-arrow-up" />1200ft<S10/></Badge>
              </Col>
            </Row>
            <Row>
              <Col sm={2}>
Distance:
</Col>
              <Col sm={12} className="display-flex">
                <Icon name="bicycle" color={Colors.grey500}/>20mi<S10/>
                <Badge><Icon name="bicycle"/>20mi</Badge><S10/>
                <Badge className="Inverted"><Icon name="bicycle"/>20mi</Badge><S10/>
                44mi 60mi 120mi
              </Col>
            </Row>
            <Row>
              <Col sm={2}>
Duration:
</Col>
              <Col sm={12} className="display-flex">
                <Icon name="hourglass-start" color={Colors.grey500}/>60min
                <S10/>
                <Badge><Icon name="hourglass-start"/>60min</Badge><S5/>
                <Icon name="hourglass-o" color={Colors.grey500}/>60min<S10/>
                <Icon name="hourglass" color={Colors.grey500} />60min<S10/>
                <Icon name="hourglass-half" color={Colors.grey500}/>60min<S10/>
              </Col>
            </Row>

          <Row className="margin-top">
            <Col sm={1} smOffset={1}><Event width={56} name="Dh"/></Col>
            <Col sm={1}><Event width={56} name="Rk"/></Col>
            <Col sm={1}><Event width={56} name="Co"/></Col>
          </Row>
          <Row className="margin-top">
            <Col sm={2} smOffset={1}>
              <Event width={125} name="Dunnigan Hills Road Race"/>
            </Col>
            <Col sm={2}>
              <Event width={125} name="RED KITE OMNIUM EVENT #1 - THE BUMP CIRCUIT RACE (WINTER)"/>
            </Col>
            <Col sm={2}>
              <Event width={125} name="John C. Schlesinger Memorial Circuit Race and Team Time Trial"/>
            </Col>
            <Col sm={2}>
              <Event width={125} name="Salinas Criterium"/>
            </Col>
          </Row>
          <Row className="margin-top">
            <Col sm={3} smOffset={1}>
              <Event width={197.5} name="Dunnigan Hills Road Race"/>
            </Col>
            <Col sm={3}>
              <Event width={197.5} name="RED KITE OMNIUM EVENT #1 - THE BUMP CIRCUIT RACE (WINTER)"/>
            </Col>
            <Col sm={3}>
              <Event width={197.5} name="John C. Schlesinger Memorial Circuit Race and Team Time Trial"/>
            </Col>
            <Col sm={3}>
              <Event width={197.5} name="Salinas Criterium"/>
            </Col>
          </Row>
          <Row className="margin-top">
            <Col sm={4} smOffset={1}>
              <Event width={270} name="Dunnigan Hills Road Race"/>
            </Col>
            <Col sm={4}>
              <Event width={270} name="RED KITE OMNIUM EVENT #1 - THE BUMP CIRCUIT RACE (WINTER)"/>
            </Col>
            <Col sm={4}>
              <Event width={270} name="John C. Schlesinger Memorial Circuit Race and Team Time Trial"/>
            </Col>
          </Row>

Road Races in CA, 100mi range

          {/* 16 col examples
          <WeekExample days={[1, 1, 1, 2, 3, 4, 4]}/>
          <WeekExample days={[1, 1, 1, 1, 4, 4, 4]}/>
          <WeekExample days={[1, 1, 2, 3, 3, 3, 3]}/>
          <WeekExample days={[1, 2, 2, 2, 3, 3, 3]}/>
          <WeekExample days={[2, 2, 2, 2, 2, 3, 3]}/>
          <WeekExample days={[2, 2, 2, 2, 2, 2, 2]} allSameSize/>
          <WeekExample days={[2, 2, 2, 2, 2, 3, 3]}/>
          <WeekExample days={[1, 1, 1, 1, 3, 4, 4]}/>
          <WeekExample days={[1, 1, 1, 1, 2, 5, 5]}/>
          */}

          <WeekExample days={[1, 1, 1, 2, 2, 3, 4]}/>

          <WeekExample days={[1, 1, 1, 1, 2, 4, 4]}/>
          <WeekExample days={[1, 1, 1, 1, 3, 3, 4]}/>
          <WeekExample days={[1, 1, 1, 2, 2, 3, 4]}/>
          <WeekExample days={[1, 1, 2, 2, 2, 2, 4]}/>

          <WeekExample days={[1, 1, 1, 2, 3, 3, 3]}/>
          <WeekExample days={[1, 1, 2, 2, 2, 3, 3]}/>
          <WeekExample days={[1, 2, 2, 2, 2, 2, 3]}/>
          <WeekExample days={[2, 2, 2, 2, 2, 2, 2]} allSameSize/>
          <WeekExample days={[2, 2, 2, 2, 2, 2, 2]}/>

          <Counter increment={1} color="silver" marginTop="20px" />

    );
  }
}
<commit_msg>added more font examples<commit_after>import React from 'react';
import Component from 'react-pure-render/component';
import './app.scss';
import Row from './atoms/Row.jsx';
import Col from './atoms/Col.jsx';
import Icon from './atoms/Icon.jsx';
import Counter from './temp/Counter.jsx';
import Event, {
  EventName, RoundBadge, Badge, SquareBadge
} from './calendar/Event.jsx';
import Colors from './styles/colors';
import DebugGrid from './temp/DebugGrid.jsx';
import WeekExample from './temp/WeekExample.jsx';
import classNames from 'classnames';

//TODO bc: remove these components
const S = ({width}) => (<span style={{width: `${width}px`}}>);
const S5 = () => (<S width={5}/>);
const S10 = () => (<S width={10}/>);

export class App extends Component {
  constructor(props) {
    super(props);
    this.state = {appLevelClasses: 'debug-baseline debug-container'};
  }
  render() {
    const setAppStateClasses = classesToSet => {
      this.setState({
        appLevelClasses: classNames('', classesToSet)
      });
    };

    return (

        <DebugGrid setDebugClasses={setAppStateClasses}/>

EVENT COMPONENTS

9px John C. Schlesinger Memorial Circuit Race and Team Time Trial

10px John C. Schlesinger Memorial Circuit Race and Team Time Trial

11px John C. Schlesinger Memorial Circuit Race and Team Time Trial

12px John C. Schlesinger Memorial Circuit Race and Team Time Trial

14px John C. Schlesinger Memorial Circuit Race and Team Time Trial

16px John C. Schlesinger Memorial Circuit Race and Team Time Trial

18px John C. Schlesinger Memorial Circuit Race and Team Time Trial

            <Row>
              <Col sm={2}>
Name:
</Col>
              <Col sm={3}><EventName className="debug">John C. Schlesinger Memorial Circuit Race and Team Time Trial</EventName></Col>
            </Row>
            <Row className="margin-top">
              <Col sm={2}>
Round Badges:
</Col>
              <Col sm={12} className="display-flex">
                <RoundBadge size={2}>8</RoundBadge>
                <RoundBadge size={1}>8</RoundBadge>
                <RoundBadge size={2}><Icon name="car"/></RoundBadge>
                <RoundBadge size={1}><Icon name="car"/></RoundBadge>
                <RoundBadge size={2}>RR</RoundBadge>
                <RoundBadge size={1}>RR</RoundBadge>
                <RoundBadge size={2}>TT</RoundBadge>
                <RoundBadge size={1}>TT</RoundBadge><S5/>
                <RoundBadge size={2} className="Inverted">RR</RoundBadge><S5/>
                <RoundBadge size={2} className="Inverted">8</RoundBadge><S5/>
                <RoundBadge size={1} className="Inverted">8</RoundBadge><S5/>
                <RoundBadge size={2} className="Inverted"><Icon name="car"/></RoundBadge><S5/>
                <RoundBadge size={1} className="Inverted"><Icon name="car"/></RoundBadge>
              </Col>
            </Row>
            <Row>
              <Col sm={2}>
Not so Round Badges:
</Col>
              <Col sm={12} className="display-flex">
                <Badge>120mi</Badge><S5/>
                <Badge>8</Badge><S5/>
                <Badge><Icon name="trophy"/></Badge><S5/>
                <Badge><Icon name="sun-o"/></Badge><S5/>
                <Badge><Icon name="map-marker"/><S5/>Monterey, CA</Badge><S5/>
                <Badge className="Inverted"><Icon name="map-marker"/><S5/>Monterey, CA</Badge>
              </Col>
            </Row>
            <Row>
              <Col sm={2}>
Square Badges:
</Col>
              <Col sm={12} className="display-flex">
                <SquareBadge>120mi</SquareBadge><S5/>
                <SquareBadge>8</SquareBadge><S5/>
                <SquareBadge><Icon name="trophy"/></SquareBadge><S5/>
                <SquareBadge><Icon name="sun-o"/></SquareBadge><S5/>
                <SquareBadge><Icon name="map-marker"/><S5/>Monterey, CA</SquareBadge>
              </Col>
            </Row>
            <Row>
              <Col sm={2}>
Square Badges (Inverted):
</Col>
              <Col sm={12} className="display-flex">
                <SquareBadge className="Inverted">120mi</SquareBadge><S5/>
                <SquareBadge className="Inverted">8</SquareBadge><S5/>
                <SquareBadge className="Inverted"><Icon name="trophy"/></SquareBadge><S5/>
                <SquareBadge className="Inverted"><Icon name="sun-o"/></SquareBadge><S5/>
                <SquareBadge className="Inverted"><Icon name="map-marker"/><S5/>Monterey, CA</SquareBadge>
              </Col>
            </Row>
            <Row>
              <Col sm={2}>
Elevation:
</Col>
              <Col sm={12} className="display-flex">
                <Icon name="arrow-up" color={Colors.grey500}/>1200ft<S10/>
                <Icon name="long-arrow-up" color={Colors.grey500}/>1200ft<S10/>
                <Badge><Icon name="arrow-up"/>1200ft<S10/></Badge><S5/>
                <Badge><Icon name="long-arrow-up" />1200ft<S10/></Badge>
              </Col>
            </Row>
            <Row>
              <Col sm={2}>
Distance:
</Col>
              <Col sm={12} className="display-flex">
                <Icon name="bicycle" color={Colors.grey500}/>20mi<S10/>
                <Badge><Icon name="bicycle"/>20mi</Badge><S10/>
                <Badge className="Inverted"><Icon name="bicycle"/>20mi</Badge><S10/>
                44mi 60mi 120mi
              </Col>
            </Row>
            <Row>
              <Col sm={2}>
Duration:
</Col>
              <Col sm={12} className="display-flex">
                <Icon name="hourglass-start" color={Colors.grey500}/>60min
                <S10/>
                <Badge><Icon name="hourglass-start"/>60min</Badge><S5/>
                <Icon name="hourglass-o" color={Colors.grey500}/>60min<S10/>
                <Icon name="hourglass" color={Colors.grey500} />60min<S10/>
                <Icon name="hourglass-half" color={Colors.grey500}/>60min<S10/>
              </Col>
            </Row>

          <Row className="margin-top">
            <Col sm={1} smOffset={1}><Event width={56} name="Dh"/></Col>
            <Col sm={1}><Event width={56} name="Rk"/></Col>
            <Col sm={1}><Event width={56} name="Co"/></Col>
          </Row>
          <Row className="margin-top">
            <Col sm={2} smOffset={1}>
              <Event width={125} name="Dunnigan Hills Road Race"/>
            </Col>
            <Col sm={2}>
              <Event width={125} name="RED KITE OMNIUM EVENT #1 - THE BUMP CIRCUIT RACE (WINTER)"/>
            </Col>
            <Col sm={2}>
              <Event width={125} name="John C. Schlesinger Memorial Circuit Race and Team Time Trial"/>
            </Col>
            <Col sm={2}>
              <Event width={125} name="Salinas Criterium"/>
            </Col>
          </Row>
          <Row className="margin-top">
            <Col sm={3} smOffset={1}>
              <Event width={197.5} name="Dunnigan Hills Road Race"/>
            </Col>
            <Col sm={3}>
              <Event width={197.5} name="RED KITE OMNIUM EVENT #1 - THE BUMP CIRCUIT RACE (WINTER)"/>
            </Col>
            <Col sm={3}>
              <Event width={197.5} name="John C. Schlesinger Memorial Circuit Race and Team Time Trial"/>
            </Col>
            <Col sm={3}>
              <Event width={197.5} name="Salinas Criterium"/>
            </Col>
          </Row>
          <Row className="margin-top">
            <Col sm={4} smOffset={1}>
              <Event width={270} name="Dunnigan Hills Road Race"/>
            </Col>
            <Col sm={4}>
              <Event width={270} name="RED KITE OMNIUM EVENT #1 - THE BUMP CIRCUIT RACE (WINTER)"/>
            </Col>
            <Col sm={4}>
              <Event width={270} name="John C. Schlesinger Memorial Circuit Race and Team Time Trial"/>
            </Col>
          </Row>

Road Races in CA, 100mi range

          {/* 16 col examples
          <WeekExample days={[1, 1, 1, 2, 3, 4, 4]}/>
          <WeekExample days={[1, 1, 1, 1, 4, 4, 4]}/>
          <WeekExample days={[1, 1, 2, 3, 3, 3, 3]}/>
          <WeekExample days={[1, 2, 2, 2, 3, 3, 3]}/>
          <WeekExample days={[2, 2, 2, 2, 2, 3, 3]}/>
          <WeekExample days={[2, 2, 2, 2, 2, 2, 2]} allSameSize/>
          <WeekExample days={[2, 2, 2, 2, 2, 3, 3]}/>
          <WeekExample days={[1, 1, 1, 1, 3, 4, 4]}/>
          <WeekExample days={[1, 1, 1, 1, 2, 5, 5]}/>
          */}

          <WeekExample days={[1, 1, 1, 2, 2, 3, 4]}/>

          <WeekExample days={[1, 1, 1, 1, 2, 4, 4]}/>
          <WeekExample days={[1, 1, 1, 1, 3, 3, 4]}/>
          <WeekExample days={[1, 1, 1, 2, 2, 3, 4]}/>
          <WeekExample days={[1, 1, 2, 2, 2, 2, 4]}/>

          <WeekExample days={[1, 1, 1, 2, 3, 3, 3]}/>
          <WeekExample days={[1, 1, 2, 2, 2, 3, 3]}/>
          <WeekExample days={[1, 2, 2, 2, 2, 2, 3]}/>
          <WeekExample days={[2, 2, 2, 2, 2, 2, 2]} allSameSize/>
          <WeekExample days={[2, 2, 2, 2, 2, 2, 2]}/>

          <Counter increment={1} color="silver" marginTop="20px" />

    );
  }
}
<|endoftext|>


<commit_before>var clock = new FlipClock($('.your-clock'), {
  clockFace: 'MinuteCounter',
  autoStart: false,
  countdown: true, //SET THIS TO FALSE FOR A STOP WATCH

  onStart: function() {
    console.log("function loads when the clock starts")
  },

  //CUSTOM CHECK VALUES (NOT KEYWORDS)
  startVal: false,
  timeSet: false
});

//START AND STOP THE TIMER
$(".timer").click(function() {

  //SET TIME FOR COUNTDOWN
  if (!clock.timeSet) {
    var time = $(".settime").val();
    if (Number.isInteger(Number(time)) && Number(time) > 0) {
      clock.timeSet = true;
      clock.setTime(Number(time));
    } else {
      alert("Insert a number");
    }

  //START AND STOP THE TIMER
  } else {
    console.log('in click event');
    //IF STOPPED, START THE TIMER
    if (clock.startVal) {
      $(".timer").text("Start");
      clock.stop();
      clock.startVal = false;
    //IF RUNNING, STOP THE TIMER
    } else {
      $(".timer").text("Stop");
      clock.start();
      clock.startVal = true;
    }
  }
});

<commit_msg>Removed extra timer.js<commit_after><|endoftext|>


<commit_before>(function (ng, _) {
  var SEATHREEURL   = 'http://localhost:8888/tweets-for-many',
      FETCHINTERVAL = 30000,
      List,
      defaultLists,
      defaultUsers,
      findUser;

  List = function (name, usernames) {
    this.name = name;
    this.usernames = usernames;
    this.selected = false;
    this.tweets = [];
  };

  findUser = function (users, username) {
    return _(users).find(function (user) {
      return user.username === username;
    });
  };

  defaultUsers = [{
    username: 'GobiernoDF',
    src: 'es',
    tgt: 'en',
    tweets: []
  }, {
    username: 'VertigoPolitico',
    src: 'es',
    tgt: 'en',
    tweets: []
  }, {
    username: 'bennnyv',
    src: 'en',
    tgt: 'es',
    tweets: []
  }, {
    username: 'nate_smith',
    src:'en',
    tgt:'es',
    tweets: []
  }];

  defaultLists = [
    new List('Mexico', ['GobiernoDF', 'VertigoPolitico']),
    new List('United States', ['nate_smith', 'bennnyv']),
    new List('Organizations', ['VertigoPolitico']),
    new List('My List', [])
  ];

  defaultLists.unshift(new List('All',
                                _.chain(defaultLists)
                                .pluck('usernames')
                                .flatten()
                                .unique()
                                .value()));

  ng.module('SeaThree', ['ngSanitize'])
  .controller('TweetsCtrl', function ($scope, $http, $interval) {
    var fetch,
        addUserAt;

    $scope.lists = defaultLists;

    $scope.users = defaultUsers;

    $scope.addUserModalShown = false;

    $scope.isSelected = function (list) {return list.selected;};
    $scope.toggleList = function (list) {
      list.selected = !list.selected;
    };
    $scope.addUserAt = function (list) {
      // TODO nasty hack; since there is now only one custom list we
      // can just save a reference in scope. When there are multiple
      // custom lists, the list being added to will have to be exposed
      // to the modal. It might be fine to just have a "currentlist"
      // model but that gives me the willies
      $scope.mylist = list;
      $scope.addUserModalShown = true;
    };

    fetch = function () {
      var data = _($scope.users).map(function (user) {
                   return _(user).pick('username', 'src', 'tgt');
                 });
      $http.get(SEATHREEURL + '?data=' + JSON.stringify(data)).success(function (users) {
        $scope.users = users;
      });
    };

    $scope.$watch('users', function () {
      // When users is updated, we must update the lists.
      _($scope.lists).each(function (list) {
        var tweets = _(list.usernames).map(function (username) {
          return findUser($scope.users, username).tweets;
        });
        list.tweets = _(_(tweets).flatten()).sortBy('id').reverse();
      });
    });

    // Start polling.
    fetch();
    $interval(fetch, FETCHINTERVAL);
  })
  .controller('AddUserCtrl', function ($scope) {
    $scope.langs = [{code:'en', display:'English'},
                    {code:'es', display:'Spanish'}];
    $scope.addUser = function () {
      $scope.users.push({
        username: $scope.username,
        src: $scope.src,
        tgt: $scope.tgt
      });
      $scope.mylist.usernames.push($scope.username);
      $scope.lists[0].usernames.push($scope.username)
      // TweetsCtrl >> Modal >> AddUserCtrl
      $scope.$parent.$parent.addUserModalShown = false;
    };
  })
  .directive('modal', function() {
    return {
      restrict: 'E',
      scope: {
        show: '='
      },
      replace: true,
      transclude: true,
      link: function (scope, element, attrs) {
        scope.hideModal = function () {
          scope.show = false;
        };
      },
      template:
      '
'
        + '

'
        + '
'
        + '
×
'
          + '

'
        + '

'
    };
  })
  .controller('LanguageCtrl', function ($scope) {
    // TODO
  });

})(angular, _);
<commit_msg>Reset username when modal closes<commit_after>(function (ng, _) {
  var SEATHREEURL   = 'http://localhost:8888/tweets-for-many',
      FETCHINTERVAL = 30000,
      List,
      defaultLists,
      defaultUsers,
      findUser;

  List = function (name, usernames) {
    this.name = name;
    this.usernames = usernames;
    this.selected = false;
    this.tweets = [];
  };

  findUser = function (users, username) {
    return _(users).find(function (user) {
      return user.username === username;
    });
  };

  defaultUsers = [{
    username: 'GobiernoDF',
    src: 'es',
    tgt: 'en',
    tweets: []
  }, {
    username: 'VertigoPolitico',
    src: 'es',
    tgt: 'en',
    tweets: []
  }, {
    username: 'bennnyv',
    src: 'en',
    tgt: 'es',
    tweets: []
  }, {
    username: 'nate_smith',
    src:'en',
    tgt:'es',
    tweets: []
  }];

  defaultLists = [
    new List('Mexico', ['GobiernoDF', 'VertigoPolitico']),
    new List('United States', ['nate_smith', 'bennnyv']),
    new List('Organizations', ['VertigoPolitico']),
    new List('My List', [])
  ];

  defaultLists.unshift(new List('All',
                                _.chain(defaultLists)
                                .pluck('usernames')
                                .flatten()
                                .unique()
                                .value()));

  ng.module('SeaThree', ['ngSanitize'])
  .controller('TweetsCtrl', function ($scope, $http, $interval) {
    var fetch,
        addUserAt;

    $scope.lists = defaultLists;

    $scope.users = defaultUsers;

    $scope.addUserModalShown = false;

    $scope.isSelected = function (list) {return list.selected;};
    $scope.toggleList = function (list) {
      list.selected = !list.selected;
    };
    $scope.addUserAt = function (list) {
      // TODO nasty hack; since there is now only one custom list we
      // can just save a reference in scope. When there are multiple
      // custom lists, the list being added to will have to be exposed
      // to the modal. It might be fine to just have a "currentlist"
      // model but that gives me the willies
      $scope.mylist = list;
      $scope.addUserModalShown = true;
    };

    fetch = function () {
      var data = _($scope.users).map(function (user) {
                   return _(user).pick('username', 'src', 'tgt');
                 });
      $http.get(SEATHREEURL + '?data=' + JSON.stringify(data)).success(function (users) {
        $scope.users = users;
      });
    };

    $scope.$watch('users', function () {
      // When users is updated, we must update the lists.
      _($scope.lists).each(function (list) {
        var tweets = _(list.usernames).map(function (username) {
          return findUser($scope.users, username).tweets;
        });
        list.tweets = _(_(tweets).flatten()).sortBy('id').reverse();
      });
    });

    // Start polling.
    fetch();
    $interval(fetch, FETCHINTERVAL);
  })
  .controller('AddUserCtrl', function ($scope) {
    $scope.langs = [{code:'en', display:'English'},
                    {code:'es', display:'Spanish'}];
    $scope.addUser = function () {
      $scope.users.push({
        username: $scope.username,
        src: $scope.src,
        tgt: $scope.tgt
      });
      $scope.mylist.usernames.push($scope.username);
      $scope.lists[0].usernames.push($scope.username)
      // TweetsCtrl >> Modal >> AddUserCtrl
      $scope.username = '';
      $scope.$parent.$parent.addUserModalShown = false;
    };
  })
  .directive('modal', function() {
    return {
      restrict: 'E',
      scope: {
        show: '='
      },
      replace: true,
      transclude: true,
      link: function (scope, element, attrs) {
        scope.hideModal = function () {
          scope.show = false;
        };
      },
      template:
      '
'
        + '

'
        + '
'
        + '
×
'
          + '

'
        + '

'
    };
  })
  .controller('LanguageCtrl', function ($scope) {
    // TODO
  });

})(angular, _);
<|endoftext|>


<commit_before>// LICENSE : MIT
"use strict";
const Promise = require("bluebird");
const createFormatter = require("textlint-formatter");
const path = require("path");
import TextLintCore from "./textlint-core";
import RuleSet from "./engine/rule-set";
import Config from "./config/config";
import {findFiles} from "./util/find-util";
import TextLintModuleLoader from "./engine/textlint-module-loader";
export default class TextLintEngine {
    /**
     * Process files are wanted to lint.
     * TextLintEngine is a wrapper of textlint.js.
     * Aim to be called from cli with cli options.
     * @param {TextLintConfig} options the options is command line options or Config object.
     * @constructor
     */
    constructor(options) {
        /**
         * @type {Config}
         */
        this.config = null;
        if (options instanceof Config) {
            // Almost internal use-case
            this.config = options;
        } else {
            this.config = Config.initWithAutoLoading(options);
        }

        /**
         * @type {TextLintCore}
         */
        this.textLint = new TextLintCore(this.config);

        /**
         * @type {RuleSet} ruleSet is used for linting/fixer
         */
        this.ruleSet = new RuleSet();
        this.moduleLoader = new TextLintModuleLoader(this.config);
        this.moduleLoader.on(TextLintModuleLoader.Event.rule, ([ruleName, ruleCreator]) => {
            this.ruleSet.defineRule(ruleName, ruleCreator);
        });
        this.moduleLoader.on(TextLintModuleLoader.Event.processor, (Processor) => {
            this.textLint.addProcessor(Processor);
        });
        // load rule/plugin/processor
        this.moduleLoader.loadFromConfig(this.config);
        // execute files that are filtered by availableExtensions.
        this.availableExtensions = this.textLint.processors.reduce((availableExtensions, processor) => {
            const Processor = processor.constructor;
            return availableExtensions.concat(Processor.availableExtensions());
        }, this.config.extensions);
        // set settings to textlint core
        this._setupRules();
    }

    /**
     * @deprecated remove this method
     */
    setRulesBaseDirectory() {
        throw new Error(`Should not use setRulesBaseDirectory(), insteadof use
new TextLintEngine({
 rulesBaseDirectory: directory
})
        `);
    }

    /**
     * load plugin manually
     * Note: it high cost, please use config
     * @param {string} pluginName
     */
    loadPlugin(pluginName) {
        this.moduleLoader.loadPlugin(pluginName);
        this._setupRules();
    }

    /**
     * load plugin manually
     * Note: it high cost, please use config
     * @param {string} presetName
     */
    loadPreset(presetName) {
        this.moduleLoader.loadPreset(presetName);
        this._setupRules();
    }

    /**
     * load plugin manually
     * Note: it high cost, please use config
     * @param {string} ruleName
     */
    loadRule(ruleName) {
        this.moduleLoader.loadRule(ruleName);
        this._setupRules();
    }

    _setupRules() {
        // reset
        const textlintConfig = this.config ? this.config.toJSON() : {};
        this.textLint.setupRules(this.ruleSet.getAllRules(), textlintConfig.rulesConfig);
    }

    /**
     * Remove all registered rule and clear messages.
     */
    resetRules() {
        this.textLint.resetRules();
        this.ruleSet.resetRules();
    }

    /**
     * Executes the current configuration on an array of file and directory names.
     * @param {String[]}  files An array of file and directory names.
     * @returns {TextLintResult[]} The results for all files that were linted.
     */
    executeOnFiles(files) {
        const targetFiles = findFiles(files, this.availableExtensions);
        const results = targetFiles.map(file => {
            return this.textLint.lintFile(file);
        });
        return Promise.all(results);
    }

    /**
     * If want to lint a text, use it.
     * But, if you have a target file, use {@link executeOnFiles} instead of it.
     * @param {string} text linting text content
     * @param {string} ext ext is a type for linting. default: ".txt"
     * @returns {TextLintResult[]}
     */
    executeOnText(text, ext = ".txt") {
        // filePath or ext
        const actualExt = ext[0] === "." ? ext : path.extname(ext);
        if (actualExt.length === 0) {
            throw new Error("should specify the extension.\nex) .md");
        }
        return this.textLint.lintText(text, actualExt).then(result => {
            return [result];
        });
    }

    /**
     * Fixes the current configuration on an array of file and directory names.
     * @param {String[]}  files An array of file and directory names.
     * @returns {TextLintFixResult[]} The results for all files that were linted.
     */
    fixFiles(files) {
        const targetFiles = findFiles(files, this.availableExtensions);
        const results = targetFiles.map(file => {
            return this.textLint.fixFile(file);
        });
        return Promise.all(results);
    }

    /**
     * Fix texts with ext option.
     *
     * @param {string} text linting text content
     * @param {string} ext ext is a type for linting. default: ".txt"
     * @returns {TextLintFixResult[]}
     */
    fixText(text, ext = ".txt") {
        // filepath or ext
        const actualExt = ext[0] === "." ? ext : path.extname(ext);
        if (actualExt.length === 0) {
            throw new Error("should specify the extension.\nex) .md");
        }
        return this.textLint.fixText(text, actualExt).then(result => {
            return [result];
        });
    }

    /**
     * format {@link results} and return output text.
     * @param {TextLintResult[]} results the collection of result
     * @returns {string} formatted output text
     * @example
     *  console.log(formatResults(results));
     */
    formatResults(results) {
        const formatterConfig = {
            formatterName: this.config.formatterName,
            color: this.config.color
        };
        const formatter = createFormatter(formatterConfig);
        return formatter(results);
    }

    /**
     * Checks if the given message is an error message.
     * @param {TextLintMessage} message The message to check.
     * @returns {boolean} Whether or not the message is an error message.
     */
    isErrorMessage(message) {
        return message.severity === 2;
    }

    /**
     * Checks if the given results contain error message.
     * If there is even one error then return true.
     * @param {TextLintResult[]} results Linting result collection
     * @returns {Boolean} Whether or not the results contain error message.
     */
    isErrorResults(results) {
        return results.some(result => {
            return result.messages.some(this.isErrorMessage);
        });
    }

    hasRuleAtLeastOne() {
        return this.ruleSet.hasRuleAtLeastOne();
    }
}
<commit_msg>refactor(engine): use constant value of rule-severity<commit_after>// LICENSE : MIT
"use strict";
const Promise = require("bluebird");
const createFormatter = require("textlint-formatter");
const path = require("path");
import TextLintCore from "./textlint-core";
import RuleSet from "./engine/rule-set";
import Config from "./config/config";
import {findFiles} from "./util/find-util";
import TextLintModuleLoader from "./engine/textlint-module-loader";
import {SeverityLevel} from "./shared/rule-severity";
export default class TextLintEngine {
    /**
     * Process files are wanted to lint.
     * TextLintEngine is a wrapper of textlint.js.
     * Aim to be called from cli with cli options.
     * @param {TextLintConfig} options the options is command line options or Config object.
     * @constructor
     */
    constructor(options) {
        /**
         * @type {Config}
         */
        this.config = null;
        if (options instanceof Config) {
            // Almost internal use-case
            this.config = options;
        } else {
            this.config = Config.initWithAutoLoading(options);
        }

        /**
         * @type {TextLintCore}
         */
        this.textLint = new TextLintCore(this.config);

        /**
         * @type {RuleSet} ruleSet is used for linting/fixer
         */
        this.ruleSet = new RuleSet();
        this.moduleLoader = new TextLintModuleLoader(this.config);
        this.moduleLoader.on(TextLintModuleLoader.Event.rule, ([ruleName, ruleCreator]) => {
            this.ruleSet.defineRule(ruleName, ruleCreator);
        });
        this.moduleLoader.on(TextLintModuleLoader.Event.processor, (Processor) => {
            this.textLint.addProcessor(Processor);
        });
        // load rule/plugin/processor
        this.moduleLoader.loadFromConfig(this.config);
        // execute files that are filtered by availableExtensions.
        this.availableExtensions = this.textLint.processors.reduce((availableExtensions, processor) => {
            const Processor = processor.constructor;
            return availableExtensions.concat(Processor.availableExtensions());
        }, this.config.extensions);
        // set settings to textlint core
        this._setupRules();
    }

    /**
     * @deprecated remove this method
     */
    setRulesBaseDirectory() {
        throw new Error(`Should not use setRulesBaseDirectory(), insteadof use
new TextLintEngine({
 rulesBaseDirectory: directory
})
        `);
    }

    /**
     * load plugin manually
     * Note: it high cost, please use config
     * @param {string} pluginName
     */
    loadPlugin(pluginName) {
        this.moduleLoader.loadPlugin(pluginName);
        this._setupRules();
    }

    /**
     * load plugin manually
     * Note: it high cost, please use config
     * @param {string} presetName
     */
    loadPreset(presetName) {
        this.moduleLoader.loadPreset(presetName);
        this._setupRules();
    }

    /**
     * load plugin manually
     * Note: it high cost, please use config
     * @param {string} ruleName
     */
    loadRule(ruleName) {
        this.moduleLoader.loadRule(ruleName);
        this._setupRules();
    }

    _setupRules() {
        // reset
        const textlintConfig = this.config ? this.config.toJSON() : {};
        this.textLint.setupRules(this.ruleSet.getAllRules(), textlintConfig.rulesConfig);
    }

    /**
     * Remove all registered rule and clear messages.
     */
    resetRules() {
        this.textLint.resetRules();
        this.ruleSet.resetRules();
    }

    /**
     * Executes the current configuration on an array of file and directory names.
     * @param {String[]}  files An array of file and directory names.
     * @returns {TextLintResult[]} The results for all files that were linted.
     */
    executeOnFiles(files) {
        const targetFiles = findFiles(files, this.availableExtensions);
        const results = targetFiles.map(file => {
            return this.textLint.lintFile(file);
        });
        return Promise.all(results);
    }

    /**
     * If want to lint a text, use it.
     * But, if you have a target file, use {@link executeOnFiles} instead of it.
     * @param {string} text linting text content
     * @param {string} ext ext is a type for linting. default: ".txt"
     * @returns {TextLintResult[]}
     */
    executeOnText(text, ext = ".txt") {
        // filePath or ext
        const actualExt = ext[0] === "." ? ext : path.extname(ext);
        if (actualExt.length === 0) {
            throw new Error("should specify the extension.\nex) .md");
        }
        return this.textLint.lintText(text, actualExt).then(result => {
            return [result];
        });
    }

    /**
     * Fixes the current configuration on an array of file and directory names.
     * @param {String[]}  files An array of file and directory names.
     * @returns {TextLintFixResult[]} The results for all files that were linted.
     */
    fixFiles(files) {
        const targetFiles = findFiles(files, this.availableExtensions);
        const results = targetFiles.map(file => {
            return this.textLint.fixFile(file);
        });
        return Promise.all(results);
    }

    /**
     * Fix texts with ext option.
     *
     * @param {string} text linting text content
     * @param {string} ext ext is a type for linting. default: ".txt"
     * @returns {TextLintFixResult[]}
     */
    fixText(text, ext = ".txt") {
        // filepath or ext
        const actualExt = ext[0] === "." ? ext : path.extname(ext);
        if (actualExt.length === 0) {
            throw new Error("should specify the extension.\nex) .md");
        }
        return this.textLint.fixText(text, actualExt).then(result => {
            return [result];
        });
    }

    /**
     * format {@link results} and return output text.
     * @param {TextLintResult[]} results the collection of result
     * @returns {string} formatted output text
     * @example
     *  console.log(formatResults(results));
     */
    formatResults(results) {
        const formatterConfig = {
            formatterName: this.config.formatterName,
            color: this.config.color
        };
        const formatter = createFormatter(formatterConfig);
        return formatter(results);
    }

    /**
     * Checks if the given message is an error message.
     * @param {TextLintMessage} message The message to check.
     * @returns {boolean} Whether or not the message is an error message.
     */
    isErrorMessage(message) {
        return message.severity === SeverityLevel.error;
    }

    /**
     * Checks if the given results contain error message.
     * If there is even one error then return true.
     * @param {TextLintResult[]} results Linting result collection
     * @returns {Boolean} Whether or not the results contain error message.
     */
    isErrorResults(results) {
        return results.some(result => {
            return result.messages.some(this.isErrorMessage);
        });
    }

    hasRuleAtLeastOne() {
        return this.ruleSet.hasRuleAtLeastOne();
    }
}
<|endoftext|>


<commit_before>/**
 * Page object
 * @typedef {Object} PageObject
 * @property {String} title - contents of <title> tag
 * @property {String} url - page URL
 * @property {Date} startTime - time when page starts loading
 * @property {Date} endTime - time when onLoad event fires
 */

/**
 * Resource object
 * @typedef {Object} ResourceObject
 * @property {Object} request - PhantomJS request object
 * @property {Object} startReply - PhantomJS response object
 * @property {Object} endReply - PhantomJS response object
 */

/**
 * This function is based on PhantomJS network logging example:
 * https://github.com/ariya/phantomjs/blob/master/examples/netsniff.js
 *
 * @param {PageObject} page
 * @param {ResourceObject} resources
 * @returns {{log: {version: string, creator: {name: string, version: string}, pages: Array, entries: Array}}}
 */
exports.createHar = function (page, resources) {
    var entries = [];

    resources.forEach(function (resource) {
        var request = resource.request,
            startReply = resource.startReply,
            endReply = resource.endReply;

        if (!request || !startReply || !endReply) {
            return;
        }

        // Exclude Data URI from HAR file because
        // they aren't included in specification
        if (request.url.match(/(^data:image\/.*)/i)) {
            return;
        }

        entries.push({
            startedDateTime: request.time.toISOString(),
            time: endReply.time - request.time,
            request: {
                method: request.method,
                url: request.url,
                httpVersion: "HTTP/1.1",
                cookies: [],
                headers: request.headers,
                queryString: [],
                headersSize: -1,
                bodySize: -1
            },
            response: {
                status: endReply.status,
                statusText: endReply.statusText,
                httpVersion: "HTTP/1.1",
                cookies: [],
                headers: endReply.headers,
                redirectURL: "",
                headersSize: -1,
                bodySize: startReply.bodySize,
                content: {
                    size: startReply.bodySize,
                    mimeType: endReply.contentType
                }
            },
            cache: {},
            timings: {
                blocked: 0,
                dns: -1,
                connect: -1,
                send: 0,
                wait: startReply.time - request.time,
                receive: endReply.time - startReply.time,
                ssl: -1
            },
            pageref: page.url
        });
    });

    return {
        log: {
            version: '1.2',
            creator: {
                name: "PhantomJS",
                version: phantom.version.major + '.' + phantom.version.minor +
                    '.' + phantom.version.patch
            },
            pages: [{
                startedDateTime: page.startTime.toISOString(),
                id: page.url,
                title: page.title,
                pageTimings: {
                    onLoad: page.endTime.getTime() - page.startTime.getTime()
                }
            }],
            entries: entries
        }
    };
};

var page = {};
exports.createHar(page, {});<commit_msg>Remove debug code from HAR library<commit_after>/**
 * Page object
 * @typedef {Object} PageObject
 * @property {String} title - contents of <title> tag
 * @property {String} url - page URL
 * @property {Date} startTime - time when page starts loading
 * @property {Date} endTime - time when onLoad event fires
 */

/**
 * Resource object
 * @typedef {Object} ResourceObject
 * @property {Object} request - PhantomJS request object
 * @property {Object} startReply - PhantomJS response object
 * @property {Object} endReply - PhantomJS response object
 */

/**
 * This function is based on PhantomJS network logging example:
 * https://github.com/ariya/phantomjs/blob/master/examples/netsniff.js
 *
 * @param {PageObject} page
 * @param {ResourceObject} resources
 * @returns {{log: {version: string, creator: {name: string, version: string}, pages: Array, entries: Array}}}
 */
exports.createHar = function (page, resources) {
    var entries = [];

    resources.forEach(function (resource) {
        var request = resource.request,
            startReply = resource.startReply,
            endReply = resource.endReply;

        if (!request || !startReply || !endReply) {
            return;
        }

        // Exclude Data URI from HAR file because
        // they aren't included in specification
        if (request.url.match(/(^data:image\/.*)/i)) {
            return;
        }

        entries.push({
            startedDateTime: request.time.toISOString(),
            time: endReply.time - request.time,
            request: {
                method: request.method,
                url: request.url,
                httpVersion: "HTTP/1.1",
                cookies: [],
                headers: request.headers,
                queryString: [],
                headersSize: -1,
                bodySize: -1
            },
            response: {
                status: endReply.status,
                statusText: endReply.statusText,
                httpVersion: "HTTP/1.1",
                cookies: [],
                headers: endReply.headers,
                redirectURL: "",
                headersSize: -1,
                bodySize: startReply.bodySize,
                content: {
                    size: startReply.bodySize,
                    mimeType: endReply.contentType
                }
            },
            cache: {},
            timings: {
                blocked: 0,
                dns: -1,
                connect: -1,
                send: 0,
                wait: startReply.time - request.time,
                receive: endReply.time - startReply.time,
                ssl: -1
            },
            pageref: page.url
        });
    });

    return {
        log: {
            version: '1.2',
            creator: {
                name: "PhantomJS",
                version: phantom.version.major + '.' + phantom.version.minor +
                    '.' + phantom.version.patch
            },
            pages: [{
                startedDateTime: page.startTime.toISOString(),
                id: page.url,
                title: page.title,
                pageTimings: {
                    onLoad: page.endTime.getTime() - page.startTime.getTime()
                }
            }],
            entries: entries
        }
    };
};
<|endoftext|>


<commit_before>var pk = pk || {};
(function(pk) {
	var ttEl=null;
	pk.tooltip=function(opt){
		if(!ttEl){
			ttEl=pk.createEl("

");
			document.body.appendChild(ttEl);
		}
		pk.bindEvent('mouseover', opt.element,function(){
			ttEl.innerHTML=opt.content;
			ttEl.style.display='block';
			var tl=pk.layout(ttEl),
				pl=pk.layout(opt.element),
				t=0,l=0;
				opt.position=opt.position || 'right';
			ttEl.style.display='';
			switch(opt.position){
				case "top":
					t=pl.top-tl.height;
					l=pl.left;
				break;
				case "bottom":
					t=pl.top+pl.height;
					l=pl.left;
				break;
				default:
				case "right":
					t=pl.top;
					l=pl.left + pl.width;
				break;
				case "left":
					t=pl.top;
					l=pl.left - tl.width;
				break;
			}
			ttEl.style.top=t+'px';
			ttEl.style.left=l+'px';
			pk.addClass(ttEl, 'pk-show');
			pk.addClass(ttEl, 'pk-'+opt.position);
		});
		pk.bindEvent('mouseout', opt.element,function(){
			ttEl.innerHTML='';
			pk.removeClass(ttEl, 'pk-show');
			pk.removeClass(ttEl, 'pk-'+opt.position);
		});
	};
    return pk;
})(pk);
<commit_msg>Update tooltip.js<commit_after>var pk = pk || {};
(function(pk) {
	var ttEl=null;
	pk.tooltip=function(opt){
		if(!ttEl){
			ttEl=pk.createEl("

");
			document.body.appendChild(ttEl);
		}
		var delay=opt.delay || 500, timer=null;
		pk.bindEvent('mouseover', opt.element,function(){
			ttEl.innerHTML=opt.content;
			ttEl.style.display='block';
			var tl=pk.layout(ttEl),
				pl=pk.layout(opt.element),
				t=0,l=0;
				opt.position=opt.position || 'right';
			ttEl.style.display='';
			switch(opt.position){
				case "top":
					t=pl.top-tl.height;
					l=pl.left;
				break;
				case "bottom":
					t=pl.top+pl.height;
					l=pl.left;
				break;
				default:
				case "right":
					t=pl.top;
					l=pl.left + pl.width;
				break;
				case "left":
					t=pl.top;
					l=pl.left - tl.width;
				break;
			}
			ttEl.style.top=t+'px';
			ttEl.style.left=l+'px';
			pk.addClass(ttEl, 'pk-'+opt.position);

			if(!timer){
				timer = setTimeout(function(){
					pk.addClass(ttEl, 'pk-show');
					clearTimeout(timer);
					timer=null;
				},delay);
			}

		});
		pk.bindEvent('mouseout', opt.element,function(){
			ttEl.innerHTML='';
			if(timer){
				clearTimeout(timer);
				timer=null;
			}
			pk.removeClass(ttEl, 'pk-show');
			pk.removeClass(ttEl, 'pk-'+opt.position);
		});
	};
    return pk;
})(pk);
<|endoftext|>


<commit_before>var AbstractItem = require('./AbstractItem');
var computedStyle = require('computed-style');
var quickLoader = require('../quickLoader');

function ImageItem(url, cfg) {
    if (!url) return;
    _super.constructor.apply(this, arguments);
    this.content = new Image();
}

module.exports = ImageItem;
var _super = AbstractItem.prototype;
var _p = ImageItem.prototype = new AbstractItem();
_p.constructor = ImageItem;
_p.load = load;
_p._onLoad = _onLoad;

ImageItem.retrieve = function(target) {
    if (target.nodeType && target.style) {

        var list = [];

        if ((target.nodeName.toLowerCase() == 'img') && (target.src.indexOf(';') < 0)) {
            list.push(target.src);
        }

        computedStyle(target, 'background-image').replace(/s?url\(\s*?[\'\"]?([^;]*?)[\'\"]?\s*?\)/g, function(a, b) {
            list.push(b);
        });

        var i = list.length;
        while (i--) {
            if (!_isNotData(list[i])) {
                list.splice(i, 1);
            }
        }
        return list.length ? list : false;
    } else if (typeof target === 'string') {
        return [target];
    } else {
        return false;
    }
};

ImageItem.type = 'image';
ImageItem.extensions = ['jpg', 'gif', 'png'];
quickLoader.register(ImageItem);

function load() {
    _super.load.apply(this, arguments);
    var img = this.content;
    img.src = this.url;
    if (img.width) {
        this._onLoad();
    } else {
        img.onload = this.boundOnLoad();
    }
}

function _onLoad() {
    delete this.content.onload;
    this.width = this.content.width;
    this.height = this.content.height;
    _super._onLoad.call(this);
}

function _isNotData(url) {
    return url.indexOf('data:') !== 0;
}
<commit_msg>image loader critical bug fix<commit_after>var AbstractItem = require('./AbstractItem');
var computedStyle = require('computed-style');
var quickLoader = require('../quickLoader');

function ImageItem(url, cfg) {
    if (!url) return;
    _super.constructor.apply(this, arguments);
    this.content = new Image();
}

module.exports = ImageItem;
var _super = AbstractItem.prototype;
var _p = ImageItem.prototype = new AbstractItem();
_p.constructor = ImageItem;
_p.load = load;
_p._onLoad = _onLoad;

ImageItem.retrieve = function(target) {
    if (target.nodeType && target.style) {

        var list = [];

        if ((target.nodeName.toLowerCase() == 'img') && (target.src.indexOf(';') < 0)) {
            list.push(target.src);
        }

        computedStyle(target, 'background-image').replace(/s?url\(\s*?[\'\"]?([^;]*?)[\'\"]?\s*?\)/g, function(a, b) {
            list.push(b);
        });

        var i = list.length;
        while (i--) {
            if (!_isNotData(list[i])) {
                list.splice(i, 1);
            }
        }
        return list.length ? list : false;
    } else if (typeof target === 'string') {
        return [target];
    } else {
        return false;
    }
};

ImageItem.type = 'image';
ImageItem.extensions = ['jpg', 'gif', 'png'];
quickLoader.register(ImageItem);

function load() {
    _super.load.apply(this, arguments);
    var img = this.content;
    img.src = this.url;
    if (img.width) {
        this._onLoad();
    } else {
        img.onload = this.boundOnLoad;
    }
}

function _onLoad() {
    delete this.content.onload;
    this.width = this.content.width;
    this.height = this.content.height;
    _super._onLoad.call(this);
}

function _isNotData(url) {
    return url.indexOf('data:') !== 0;
}
<|endoftext|>


<commit_before>'use strict';

const Schema = require('../').Schema;
const StandardError = require('standard-error');
const ValidateError = require('./error');
const _ = require('lodash');
const debug = require('debug')('archetype:umarshal');
const handleCast = require('./util').handleCast;
const join = require('./util').join;
const mpath = require('mpath');
const realPathToSchemaPath = require('./util').realPathToSchemaPath;

module.exports = castDocument;

function markSubpaths(projection, path, val) {
  const pieces = path.split('.');
  let cur = pieces[0];
  projection[cur] = val;
  for (let i = 1; i < pieces.length; ++i) {
    cur += `.${pieces[i]}`;
    projection[cur] = val;
  }
}

function handleProjection(projection) {
  if (!projection) {
    return { $inclusive: true };
  }
  projection = _.cloneDeep(projection);
  let inclusive = null;
  for (const key of Object.keys(projection)) {
    if (key.startsWith('$')) {
      continue;
    }
    if (projection[key] > 0) {
      if (inclusive === true) {
        throw new Error("Can't mix inclusive and exclusive in projection");
      }
      markSubpaths(projection, key, projection[key]);
      inclusive = false;
    } else {
      if (inclusive === false) {
        throw new Error("Can't mix inclusive and exclusive in projection");
      }
      inclusive = true;
    }
  }

  if (inclusive === null) {
    inclusive = true;
  }
  projection.$inclusive = inclusive;
  return projection;
}

function shouldSkipPath(projection, path) {
  if (projection.$inclusive) {
    return projection[path] != null;
  } else {
    return projection[path] == null;
  }
}

function castDocument(obj, schema, projection) {
  projection = handleProjection(projection);
  obj = _.cloneDeep(obj);
  applyDefaults(obj, schema, projection);
  const error = new ValidateError();
  error.merge(visitObject(obj, schema, projection, '').error);
  error.merge(checkRequired(obj, schema, projection));
  error.merge(runValidation(obj, schema, projection));
  if (error.hasError) {
    throw new StandardError(error.toString(), { errors: error.errors });
  }
  return obj;
}

function visitArray(arr, schema, projection, path) {
  debug('visitArray', arr, path, schema);
  let error = new ValidateError();
  let curPath = realPathToSchemaPath(path);
  let newPath = join(curPath, '$');
  if (!schema._paths[newPath] || !schema._paths[newPath].$type) {
    debug('skipping', newPath);
    return {
      value: arr,
      error: null
    };
  }

  if (arr == null) {
    return {
      value: arr,
      error: null
    };
  }

  if (!Array.isArray(arr)) {
    arr = [arr];
  }

  debug('newPath', newPath, schema._paths[newPath].$type);
  arr.forEach(function(value, index) {
    if (schema._paths[newPath].$type === Array ||
        Array.isArray(schema._paths[newPath].$type)) {
      let res = visitArray(value, schema, projection, join(path, index, true));
      if (res.error) {
        error.merge(res.error);
      }
      arr[index] = res.value;
      return;
    } else if (schema._paths[newPath].$type === Object) {
      let res = visitObject(value, schema, projection, join(path, index, true));
      if (res.error) {
        error.merge(res.error);
      }
      arr[index] = res.value;
      return;
    }

    try {
      handleTerminus(arr, index, schema, newPath);
    } catch(err) {
      error.markError(join(path, index, true), err);
    }
  });

  return {
    value: arr,
    error: (error.hasError ? error : null)
  };
}

function visitObject(obj, schema, projection, path) {
  debug('visitObject', obj, schema, projection, path);
  let error = new ValidateError();
  if (typeof obj !== 'object' || Array.isArray(obj)) {
    let err = new Error('Could not cast ' + require('util').inspect(obj) +
      ' to Object');
    error.markError(path, err);
    return {
      value: null,
      error: error
    };
  }

  let fakePath = realPathToSchemaPath(path);
  debug('fakePath', fakePath, obj);
  const curSchema = schema._paths[fakePath];
  if (fakePath && !curSchema.$schema) {
    return {
      value: obj,
      error: (error.hasError ? error : null)
    };
  }

  _.each(obj, function(value, key) {
    let newPath = join(fakePath, key);
    debug('visit', key);
    if (!schema._paths[newPath] || shouldSkipPath(projection, newPath)) {
      delete obj[key];
      return;
    }
    const newSchema = schema._paths[newPath]
    if (newSchema.$type == null) {
      // If type not specified, no type casting
      return;
    }

    if (schema._paths[newPath].$type === Array ||
        Array.isArray(schema._paths[newPath].$type)) {
      let res = visitArray(value, schema, projection, newPath);
      if (res.error) {
        debug('merge', res.error.errors);
        error.merge(res.error);
      }
      obj[key] = res.value;
      return;
    } else if (schema._paths[newPath].$type === Object) {
      if (value == null) {
        delete obj[key];
        return;
      }
      let res = visitObject(value, schema, projection, newPath);
      if (res.error) {
        debug('merge', res.error.errors);
        error.merge(res.error);
      }
      obj[key] = res.value;
      return;
    }

    try {
      handleTerminus(obj, key, schema, newPath);
    } catch(err) {
      error.markError(join(path, key, true), err);
    }
  });

  return {
    value: obj,
    error: (error.hasError ? error : null)
  };
}

function handleTerminus(value, key, schema, path) {
  schema = schema._paths[path];
  handleCast(value, key, schema.$type);
}

function checkRequired(obj, schema, projection) {
  const error = new ValidateError();
  _.each(Object.keys(schema._paths), path => {
    if (shouldSkipPath(projection, path) || projection.$noRequired) {
      return;
    }
    if (!schema._paths[path].$required) {
      return true;
    }
    const _path = path.replace(/\.\$\./g, '.').replace(/\.\$$/g, '');
    const val = mpath.get(_path, obj);
    if (Array.isArray(val)) {
      if (_.some(val, v => v == null)) {
        error.markError(path, new Error(`Path "${path}" is required`));
      }
    } else if (val == null) {
      error.markError(path, new Error(`Path "${path}" is required`));
    }
  });
  return error;
}

function runValidation(obj, schema, projection) {
  const error = new ValidateError();
  _.each(Object.keys(schema._paths), path => {
    debug(`Checking validation for "${path}"`);
    if (shouldSkipPath(projection, path)) {
      debug(`Skip validation for "${path}"`);
      return;
    }
    if (!schema._paths[path].$validate) {
      debug(`No validation for "${path}"`);
      return true;
    }
    const _path = path.replace(/\.\$\./g, '.').replace(/\.\$$/g, '');
    const val = mpath.get(_path, obj);
    if (val == null) {
      return;
    }
    if (Array.isArray(val)) {
      if (path.indexOf('$') === -1) {
        debug(`Path "${path}" is plain array`);
        try {
          schema._paths[path].$validate(val, schema._paths[path], obj);
        } catch(_error) {
          error.markError(path, _error);
        }
      } else {
        debug(`Validate each element for "${path}"`);
        _.each(val, (val, index) => {
          try {
            schema._paths[path].$validate(val, schema._paths[path], obj);
          } catch(_error) {
            error.markError(`${path}.${index}`, _error);
          }
        });
      }
    } else {
      try {
        schema._paths[path].$validate(val, schema._paths[path], obj);
      } catch(_error) {
        error.markError(path, _error);
      }
    }
  });
  return error;
}

function applyDefaults(obj, schema, projection) {
  _.each(Object.keys(schema._paths), path => {
    if (!('$default' in schema._paths[path])) {
      return;
    }
    if (shouldSkipPath(projection, path)) {
      return;
    }
    const _path = path.replace(/\.\$\./g, '.').replace(/\.\$$/g, '');
    const val = mpath.get(_path, obj);
    if (Array.isArray(val)) {
      for (let i = 0; i < val.length; ++i) {
        if (val[i] == null) {
          val[i] = handleDefault(schema._paths[path].$default, obj);
        }
      }
      mpath.set(_path, val, obj);
    } else if (val == null) {
      mpath.set(_path, handleDefault(schema._paths[path].$default, obj), obj);
    }
  });
}

function handleDefault(obj, ctx) {
  if (typeof obj === 'function') {
    return obj(ctx);
  }
  return obj;
}
<commit_msg>fix: throw sane error when casting null doc<commit_after>'use strict';

const Schema = require('../').Schema;
const StandardError = require('standard-error');
const ValidateError = require('./error');
const _ = require('lodash');
const debug = require('debug')('archetype:umarshal');
const handleCast = require('./util').handleCast;
const join = require('./util').join;
const mpath = require('mpath');
const realPathToSchemaPath = require('./util').realPathToSchemaPath;

module.exports = castDocument;

function markSubpaths(projection, path, val) {
  const pieces = path.split('.');
  let cur = pieces[0];
  projection[cur] = val;
  for (let i = 1; i < pieces.length; ++i) {
    cur += `.${pieces[i]}`;
    projection[cur] = val;
  }
}

function handleProjection(projection) {
  if (!projection) {
    return { $inclusive: true };
  }
  projection = _.cloneDeep(projection);
  let inclusive = null;
  for (const key of Object.keys(projection)) {
    if (key.startsWith('$')) {
      continue;
    }
    if (projection[key] > 0) {
      if (inclusive === true) {
        throw new Error("Can't mix inclusive and exclusive in projection");
      }
      markSubpaths(projection, key, projection[key]);
      inclusive = false;
    } else {
      if (inclusive === false) {
        throw new Error("Can't mix inclusive and exclusive in projection");
      }
      inclusive = true;
    }
  }

  if (inclusive === null) {
    inclusive = true;
  }
  projection.$inclusive = inclusive;
  return projection;
}

function shouldSkipPath(projection, path) {
  if (projection.$inclusive) {
    return projection[path] != null;
  } else {
    return projection[path] == null;
  }
}

function castDocument(obj, schema, projection) {
  projection = handleProjection(projection);
  if (obj == null) {
    throw new Error(`Can't cast null or undefined`);
  }
  obj = _.cloneDeep(obj);
  applyDefaults(obj, schema, projection);
  const error = new ValidateError();
  error.merge(visitObject(obj, schema, projection, '').error);
  error.merge(checkRequired(obj, schema, projection));
  error.merge(runValidation(obj, schema, projection));
  if (error.hasError) {
    throw new StandardError(error.toString(), { errors: error.errors });
  }
  return obj;
}

function visitArray(arr, schema, projection, path) {
  debug('visitArray', arr, path, schema);
  let error = new ValidateError();
  let curPath = realPathToSchemaPath(path);
  let newPath = join(curPath, '$');
  if (!schema._paths[newPath] || !schema._paths[newPath].$type) {
    debug('skipping', newPath);
    return {
      value: arr,
      error: null
    };
  }

  if (arr == null) {
    return {
      value: arr,
      error: null
    };
  }

  if (!Array.isArray(arr)) {
    arr = [arr];
  }

  debug('newPath', newPath, schema._paths[newPath].$type);
  arr.forEach(function(value, index) {
    if (schema._paths[newPath].$type === Array ||
        Array.isArray(schema._paths[newPath].$type)) {
      let res = visitArray(value, schema, projection, join(path, index, true));
      if (res.error) {
        error.merge(res.error);
      }
      arr[index] = res.value;
      return;
    } else if (schema._paths[newPath].$type === Object) {
      let res = visitObject(value, schema, projection, join(path, index, true));
      if (res.error) {
        error.merge(res.error);
      }
      arr[index] = res.value;
      return;
    }

    try {
      handleTerminus(arr, index, schema, newPath);
    } catch(err) {
      error.markError(join(path, index, true), err);
    }
  });

  return {
    value: arr,
    error: (error.hasError ? error : null)
  };
}

function visitObject(obj, schema, projection, path) {
  debug('visitObject', obj, schema, projection, path);
  let error = new ValidateError();
  if (typeof obj !== 'object' || Array.isArray(obj)) {
    let err = new Error('Could not cast ' + require('util').inspect(obj) +
      ' to Object');
    error.markError(path, err);
    return {
      value: null,
      error: error
    };
  }

  let fakePath = realPathToSchemaPath(path);
  debug('fakePath', fakePath, obj);
  const curSchema = schema._paths[fakePath];
  if (fakePath && !curSchema.$schema) {
    return {
      value: obj,
      error: (error.hasError ? error : null)
    };
  }

  _.each(obj, function(value, key) {
    let newPath = join(fakePath, key);
    debug('visit', key);
    if (!schema._paths[newPath] || shouldSkipPath(projection, newPath)) {
      delete obj[key];
      return;
    }
    const newSchema = schema._paths[newPath]
    if (newSchema.$type == null) {
      // If type not specified, no type casting
      return;
    }

    if (schema._paths[newPath].$type === Array ||
        Array.isArray(schema._paths[newPath].$type)) {
      let res = visitArray(value, schema, projection, newPath);
      if (res.error) {
        debug('merge', res.error.errors);
        error.merge(res.error);
      }
      obj[key] = res.value;
      return;
    } else if (schema._paths[newPath].$type === Object) {
      if (value == null) {
        delete obj[key];
        return;
      }
      let res = visitObject(value, schema, projection, newPath);
      if (res.error) {
        debug('merge', res.error.errors);
        error.merge(res.error);
      }
      obj[key] = res.value;
      return;
    }

    try {
      handleTerminus(obj, key, schema, newPath);
    } catch(err) {
      error.markError(join(path, key, true), err);
    }
  });

  return {
    value: obj,
    error: (error.hasError ? error : null)
  };
}

function handleTerminus(value, key, schema, path) {
  schema = schema._paths[path];
  handleCast(value, key, schema.$type);
}

function checkRequired(obj, schema, projection) {
  const error = new ValidateError();
  _.each(Object.keys(schema._paths), path => {
    if (shouldSkipPath(projection, path) || projection.$noRequired) {
      return;
    }
    if (!schema._paths[path].$required) {
      return true;
    }
    const _path = path.replace(/\.\$\./g, '.').replace(/\.\$$/g, '');
    const val = mpath.get(_path, obj);
    if (Array.isArray(val)) {
      if (_.some(val, v => v == null)) {
        error.markError(path, new Error(`Path "${path}" is required`));
      }
    } else if (val == null) {
      error.markError(path, new Error(`Path "${path}" is required`));
    }
  });
  return error;
}

function runValidation(obj, schema, projection) {
  const error = new ValidateError();
  _.each(Object.keys(schema._paths), path => {
    debug(`Checking validation for "${path}"`);
    if (shouldSkipPath(projection, path)) {
      debug(`Skip validation for "${path}"`);
      return;
    }
    if (!schema._paths[path].$validate) {
      debug(`No validation for "${path}"`);
      return true;
    }
    const _path = path.replace(/\.\$\./g, '.').replace(/\.\$$/g, '');
    const val = mpath.get(_path, obj);
    if (val == null) {
      return;
    }
    if (Array.isArray(val)) {
      if (path.indexOf('$') === -1) {
        debug(`Path "${path}" is plain array`);
        try {
          schema._paths[path].$validate(val, schema._paths[path], obj);
        } catch(_error) {
          error.markError(path, _error);
        }
      } else {
        debug(`Validate each element for "${path}"`);
        _.each(val, (val, index) => {
          try {
            schema._paths[path].$validate(val, schema._paths[path], obj);
          } catch(_error) {
            error.markError(`${path}.${index}`, _error);
          }
        });
      }
    } else {
      try {
        schema._paths[path].$validate(val, schema._paths[path], obj);
      } catch(_error) {
        error.markError(path, _error);
      }
    }
  });
  return error;
}

function applyDefaults(obj, schema, projection) {
  _.each(Object.keys(schema._paths), path => {
    if (!('$default' in schema._paths[path])) {
      return;
    }
    if (shouldSkipPath(projection, path)) {
      return;
    }
    const _path = path.replace(/\.\$\./g, '.').replace(/\.\$$/g, '');
    const val = mpath.get(_path, obj);
    if (Array.isArray(val)) {
      for (let i = 0; i < val.length; ++i) {
        if (val[i] == null) {
          val[i] = handleDefault(schema._paths[path].$default, obj);
        }
      }
      mpath.set(_path, val, obj);
    } else if (val == null) {
      mpath.set(_path, handleDefault(schema._paths[path].$default, obj), obj);
    }
  });
}

function handleDefault(obj, ctx) {
  if (typeof obj === 'function') {
    return obj(ctx);
  }
  return obj;
}
<|endoftext|>