<commit_before>/*******************************************************************************
 * Copyright 2015 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *******************************************************************************/
var Probe = require('../lib/probe.js');
var request = require('../lib/request.js');
var aspect = require('../lib/aspect');
var util = require('util');
var path = require('path');

function TraceProbe() {
	Probe.call(this, 'trace');
	this.config = {
			includeModules: [],
			excludeModules: []
	};
}
util.inherits(TraceProbe, Probe);

TraceProbe.prototype.attach = function( moduleName, target ) {
    if( moduleName.slice(0,1) != "." || stopList[moduleName] || !isAppInnerRequire() ||
    	this.config.excludeModules.indexOf(moduleName) != -1 ) {
    	return target;
    }

    if(target.__ddProbeAttached__) {
    	return target;
    }

    var ret = target;
    if (typeof(target) != "function") {
        instrumentMethods(moduleName, target);
    } else {
        instrumentMethods(moduleName, target.prototype);
        ret = target;
		if(Object.keys(target.prototype).length==0 && Object.keys(target).length == 0){
			ret = function () {
				var rc = target.apply(null, arguments);
				instrumentMethods(moduleName, rc);
				return rc;
			}
		}
    }

    ret.__ddProbeAttached__ = function(){return true};
    return ret;
};

var stopList = { "./commands/base_command" : true, "./aspects": true };

function instrument( target, name, method, fullName ) {
var methodString = ''+method;
var methodargs = methodString.toString().split(')')[0].split('(')[1].split(',');
var lastMethodArg = methodargs[methodargs.length-1].replace(/ /g,'');
if(lastMethodArg == '') lastMethodArg = 'undefined';
    var f = function() {
        var instrumentedMethodKNJ = true;
        var req = request.startMethod( fullName );
        var args = arguments;
        var cxtFunc = function() {
            var cxt = {};
            for( var i = 0; i<args.length; ++i ) {
                var arg = args[i];
                var value;
                if( typeof(arg) == "function" &&
			Object.keys(arg).length == 0 &&
                            Object.keys(arg.prototype).length==0) {
                    var fName = arg.name != 0 ? arg.name : '<anonymous>';
                    value = "function " + fName;
                } else if( typeof(arg) == "object" ) {
                    value = "object";
                } else {
                    value = "" + arg;
                }
                cxt["arg"+i] = value;
            }
            return cxt;
        }
        var isCallback = false;
        /*
        if( arguments.length > 0 && typeof(arguments[arguments.length-1]) == "function" && Object.keys(arguments[arguments.length-1]).length == 0) {
        	console.log('Type is ' + typeof(arguments[arguments.length-1].prototype));
        	if (typeof(arguments[arguments.length-1].prototype) === 'object') {
        		console.log('Checking object');
        		console.log(Object.keys(arguments[arguments.length-1].prototype));
        	}
        	else {
        		console.log('Not object');
        	}

        }
        */
        if( arguments.length > 0 &&
        	typeof(arguments[arguments.length-1]) == "function" &&
        	Object.keys(arguments[arguments.length-1]).length == 0 &&
        	// Add to deal with no prototype
        	(!arguments[arguments.length-1].hasOwnProperty('prototype') ||
        	Object.keys(arguments[arguments.length-1].prototype).length == 0) &&
        	methodString.indexOf(lastMethodArg+'.call') < 0 &&
        	methodString.indexOf(lastMethodArg+'.apply')<0 &&
        	(''+arguments[arguments.length-1]).indexOf('instrumentedMethodKNJ')<0
) {
            isCallback = true;
            if (isResponseMethod(arguments)) {
                var resArg = arguments[arguments.length-2];

                var sendCb = resArg.send;
                resArg.send = function() {
                    req.stop(cxtFunc);
                    return sendCb.apply(resArg, arguments);
                }

                var renderCb = resArg.render;
                resArg.render = function() {
                    req.stop(cxtFunc);
                    return renderCb.apply(resArg, arguments);
                }
            } else {
                var cb = arguments[arguments.length-1];
                arguments[arguments.length-1] = function() {
                    req.stop(cxtFunc);
                    cb.apply(this, arguments);
                }
            }
        }
        var res = method.apply(this, arguments);
        if( !isCallback ) {
            req.stop(cxtFunc);
        }
        return res;
    };
    target[name] = f;
    target[name].prototype = method.prototype;
}

function isResponseMethod(args) {
    if (args.length > 1) {
        var arg = args[args.length-2];
        if (typeof(arg) == 'object' && arg!=null && 'send' in arg && 'render' in arg && typeof(arg['send']) == 'function' && typeof(arg['render']) == 'function') {
            return true;
        }
    }
    return false;
}

function traceMethod( moduleName, target, name ) {
    var method = target[name];
    if( method && !method.__ddInstrumented__ ) {
        var fullName = moduleName + "." + name;
//        logger.debug( "instrumenting method", fullName );
        instrument( target, name, method, fullName );

        var p = target[name].prototype;
        for (var item in p) {
            if (typeof(p[item]) == "function" &&
                   Object.keys(p[item]).length==0 &&
                        Object.keys(p[item].prototype).length==0) {
                var itemName = fullName + "." + item;
                instrument(p, item, p[item], itemName);
            }
        }
    }
}

var moduleStackRegexp = /\((.*):\d*:\d*\)/;
var debug = typeof v8debug === 'object';

function getRootModuleDir() {
    Error.stackTraceLimit = 40;
    var trace = {};
    Error.captureStackTrace(trace);
    var stack = trace.stack.split('\n');
    var rootAppModule = stack[stack.length - (debug ? 7 : 8)]; // stack changes depending on debug
    var match = moduleStackRegexp.exec(rootAppModule);
    Error.stackTraceLimit = 10;
    return path.dirname(match[1]);
}

function isAppInnerRequire() {
    var trace = {};
    Error.captureStackTrace(trace);
    var callerLine = trace.stack.split('\n'); // This line contains 'node_modules' reference for generic libs
    return callerLine[9].indexOf('node_modules') == -1;
}

// not used right now, but may be needed in the future:
var rootModuleDir = getRootModuleDir();

function instrumentMethods(moduleName, target) {
    for( var name in target ) {
        if( !target.__lookupGetter__(name) && typeof(target[name]) == "function" ) {
          if(!target[name].__super__ &&
                         (  !target[name].prototype ||
                                  ( target[name].prototype && Object.keys(target[name].prototype).length==0 ) ) && Object.keys(target[name]).length==0){
            traceMethod(moduleName, target,name);
            }
        }
    }
}

TraceProbe.prototype.enable = function () {};
TraceProbe.prototype.enableRequests = function () {};

module.exports = TraceProbe;<commit_msg>Reduce number of traced functions<commit_after>/*******************************************************************************
 * Copyright 2015 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *******************************************************************************/
var Probe = require('../lib/probe.js');
var request = require('../lib/request.js');
var aspect = require('../lib/aspect');
var util = require('util');
var path = require('path');

function TraceProbe() {
	Probe.call(this, 'trace');
	this.config = {
			includeModules: [],
			excludeModules: []
	};
}
util.inherits(TraceProbe, Probe);

TraceProbe.prototype.attach = function( moduleName, target ) {
    if( moduleName.slice(0,1) != "." || stopList[moduleName] || !isAppInnerRequire() ||
    	this.config.excludeModules.indexOf(moduleName) != -1 ) {
    	return target;
    }

    if(target.__ddProbeAttached__) {
    	return target;
    }

    var ret = target;
    if (typeof(target) != "function") {
        instrumentMethods(moduleName, target);
    } else {
        instrumentMethods(moduleName, target.prototype);
        ret = target;
		if(Object.keys(target.prototype).length==0 && Object.keys(target).length == 0){
			ret = function () {
				var rc = target.apply(null, arguments);
				instrumentMethods(moduleName, rc);
				return rc;
			}
		}
    }

    ret.__ddProbeAttached__ = function(){return true};
    return ret;
};

var stopList = { "./commands/base_command" : true, "./aspects": true };

function instrument( target, name, method, fullName ) {
var methodString = ''+method;
var methodargs = methodString.toString().split(')')[0].split('(')[1].split(',');
var lastMethodArg = methodargs[methodargs.length-1].replace(/ /g,'');
if(lastMethodArg == '') lastMethodArg = 'undefined';
    var f = function() {
        var instrumentedMethodKNJ = true;
        var req = request.startMethod( fullName );
        var args = arguments;
        var cxtFunc = function() {
            var cxt = {};
            for( var i = 0; i<args.length; ++i ) {
                var arg = args[i];
                var value;
                if( typeof(arg) == "function" &&
			Object.keys(arg).length == 0 &&
                            Object.keys(arg.prototype).length==0) {
                    var fName = arg.name != 0 ? arg.name : '<anonymous>';
                    value = "function " + fName;
                } else if( typeof(arg) == "object" ) {
                    value = "object";
                } else {
                    value = "" + arg;
                }
                cxt["arg"+i] = value;
            }
            return cxt;
        }
        var isCallback = false;
        /*
        if( arguments.length > 0 && typeof(arguments[arguments.length-1]) == "function" && Object.keys(arguments[arguments.length-1]).length == 0) {
        	console.log('Type is ' + typeof(arguments[arguments.length-1].prototype));
        	if (typeof(arguments[arguments.length-1].prototype) === 'object') {
        		console.log('Checking object');
        		console.log(Object.keys(arguments[arguments.length-1].prototype));
        	}
        	else {
        		console.log('Not object');
        	}

        }
        */
        if( arguments.length > 0 &&
        	typeof(arguments[arguments.length-1]) == "function" &&
        	Object.keys(arguments[arguments.length-1]).length == 0 &&
        	// Add to deal with no prototype
        	(!arguments[arguments.length-1].hasOwnProperty('prototype') ||
        	Object.keys(arguments[arguments.length-1].prototype).length == 0) &&
        	methodString.indexOf(lastMethodArg+'.call') < 0 &&
        	methodString.indexOf(lastMethodArg+'.apply')<0 &&
        	(''+arguments[arguments.length-1]).indexOf('instrumentedMethodKNJ')<0
) {
            isCallback = true;
            if (isResponseMethod(arguments)) {
                var resArg = arguments[arguments.length-2];

                var sendCb = resArg.send;
                resArg.send = function() {
                    req.stop(cxtFunc);
                    return sendCb.apply(resArg, arguments);
                }

                var renderCb = resArg.render;
                resArg.render = function() {
                    req.stop(cxtFunc);
                    return renderCb.apply(resArg, arguments);
                }
            } else {
                var cb = arguments[arguments.length-1];
                arguments[arguments.length-1] = function() {
                    req.stop(cxtFunc);
                    cb.apply(this, arguments);
                }
            }
        }
        var res = method.apply(this, arguments);
        if( !isCallback ) {
            req.stop(cxtFunc);
        }
        return res;
    };
    target[name] = f;
    target[name].prototype = method.prototype;
}

function isResponseMethod(args) {
    if (args.length > 1) {
        var arg = args[args.length-2];
        if (typeof(arg) == 'object' && arg!=null && 'send' in arg && 'render' in arg && typeof(arg['send']) == 'function' && typeof(arg['render']) == 'function') {
            return true;
        }
    }
    return false;
}

function traceMethod( moduleName, target, name ) {
    var method = target[name];
    if( method && !method.__ddInstrumented__ ) {
        var fullName = moduleName + "." + name;
//        logger.debug( "instrumenting method", fullName );
        instrument( target, name, method, fullName );

        var p = target[name].prototype;
        for (var item in p) {
            if (typeof(p[item]) == "function" &&
                   Object.keys(p[item]).length==0 &&
                        Object.keys(p[item].prototype).length==0) {
                var itemName = fullName + "." + item;
                instrument(p, item, p[item], itemName);
            }
        }
    }
}

var moduleStackRegexp = /\((.*):\d*:\d*\)/;
var debug = typeof v8debug === 'object';

function getRootModuleDir() {
    Error.stackTraceLimit = 40;
    var trace = {};
    Error.captureStackTrace(trace);
    var stack = trace.stack.split('\n');
    var rootAppModule = stack[stack.length - (debug ? 7 : 8)]; // stack changes depending on debug
    var match = moduleStackRegexp.exec(rootAppModule);
    Error.stackTraceLimit = 10;
    return path.dirname(match[1]);
}

function isAppInnerRequire() {
    var trace = {};
    Error.captureStackTrace(trace);
    var callerLine = trace.stack.split('\n'); // This line contains 'node_modules' reference for generic libs
    return callerLine[6].indexOf('node_modules') == -1;
}

// not used right now, but may be needed in the future:
var rootModuleDir = getRootModuleDir();

function instrumentMethods(moduleName, target) {
    for( var name in target ) {
        if( !target.__lookupGetter__(name) && typeof(target[name]) == "function" ) {
          if(!target[name].__super__ &&
                         (  !target[name].prototype ||
                                  ( target[name].prototype && Object.keys(target[name].prototype).length==0 ) ) && Object.keys(target[name]).length==0){
            traceMethod(moduleName, target,name);
            }
        }
    }
}

TraceProbe.prototype.enable = function () {};
TraceProbe.prototype.enableRequests = function () {};

module.exports = TraceProbe;<|endoftext|>


<commit_before>/**
 * Controls the First Time Experience for the user interface.
 *
 */
betterlink_user_interface.createModule("FTE", function(api, apiInternal) {
	api.requireModules( ["Util.DOM", "Storage", "FTE Tooltip", "LastSubmission", "Drawer Slider", "Action Drawer", "Util.HTTP", "HTTP", "Smooth Scrolling", "Event Messaging"] );

	// Element Selectors. These should be dynamic to make the FTE
	// resilient.
	var TOOLTIP_SELECTOR = "#betterlink-tooltip";
	var DRAWER_ID = "betterlink-drawer";
	var NEXUS_CLASS = "betterlink-nexus";
	var PEN_CLASS = "betterlink-pen";
	var SELECTED_CLASS = "betterlink-selected";
	var DRAWER_BACKGROUND = "#E9E9E9";

	var BUTTON_CLASS = "betterlink-tooltip-btn";
	var BUTTON_CLASS_SECONDARY = "betterlink-tooltip-btn-secondary";
	var BUTTONS_CLASS = "betterlink-tooltip-btns";
	var MASK_CLASS = "betterlink-fte-mask";
	var MASK_OVERRIDE_CLASS = "betterlink-fte-mask-override";

	var CSS =
		[   TOOLTIP_SELECTOR + " ." + BUTTON_CLASS + " { background-color: #3299BB; border: 1px solid #277799; color: #FFF; font-size: 14px; margin: 5px; padding: 6px 12px; border-radius: .4em; display: inline-block; text-align: center; white-space: nowrap; vertical-align: middle; touch-action: manipulation; cursor: pointer; text-decoration: none; }",
			TOOLTIP_SELECTOR + " ." + BUTTON_CLASS + ":hover { background-color: #277799; text-decoration: none; }",
			TOOLTIP_SELECTOR + " ." + BUTTON_CLASS_SECONDARY + " { background-color: #BCBCBC; border: 1px solid #9B9B9B; }",
			TOOLTIP_SELECTOR + " ." + BUTTON_CLASS_SECONDARY + ":hover { background-color: #9B9B9B; }",
			TOOLTIP_SELECTOR + " ." + BUTTONS_CLASS + " { text-align: right; width: auto; margin-top: 5px }",
			TOOLTIP_SELECTOR + " p { margin-bottom: 6px; }",

			// The mask has a z-index one less than the maximum
			// Any overrides have a z-index that's the maximum value
			"." + MASK_CLASS + ":after { content: ''; background-color: #000; opacity: 0.6; display: block; position: fixed; top: 0; left: 0; height: 100%; width: 100%; z-index: 2147483646; }",
			"." + MASK_OVERRIDE_CLASS + "{ position: relative !important; box-shadow: 0 0 5px 2px #BCBCBC; text-shadow: 0 1px 1px rgba(0, 0, 0, 0.25); }"

		].join(' ');

	var stylesInitialized = false;
	var fteRun = false;
	var drawerLock;

	/****************************************************************************************************/

	apiInternal.events.registerObserverForRemoveBetterlink(closeFTE);
	apiInternal.addInitListener(loadFTE);

	// Register the FTE to run with the next successful submission
	function loadFTE() {
		if(api['config']['enableFTE']) {
			// Queries the server to determine if the user has already
			// viewed the FTE, based on registerFTE()
			apiInternal.checkFTE(decideToLoadFTE);

			// Everytime there is a new submission, refresh that the user
			// doesn't need the FTE. In the event the user *has not* seen
			// it, this will get called along with runIntro the first time.
			apiInternal.lastSubmission.subscribeSuccess.onsuccess(apiInternal.registerFTE);
		}
	}

	// Asynchronous check for whether we should load the FTE for this
	// user
	function decideToLoadFTE(errorInfo, response) {
		// If we can't get a response from the server, assume the user
		// *has not* seen the FTE. Rationale: we're currently only
		// displaying the FTE on the Betterlink landing page.
		if(errorInfo) {
			apiInternal.lastSubmission.subscribeSuccess.onsuccess(runIntro);
		}
		else {
			// Asynchronously parse the response JSON. Expected result:
			// { fte: '1' } indicates the user has seen the FTE
			apiInternal.util.http.parseJSONServerResponseAsync(response, function(parsedResponse) {
				if(Object.hasOwnProperty.call(parsedResponse, 'fte')) {
					if(parsedResponse['fte'] !== '1') {
						apiInternal.lastSubmission.subscribeSuccess.onsuccess(runIntro);
					}
				}
			});
		}
	}

	// STEP 1
	// This explains that a new link was created and allows the user
	// to demo visiting their new link
	function runIntro() {
		if(!fteRun) {
			// The core interface gets loaded via an init listener, just
			// like loadFTE(). This means we can't guarantee that the
			// drawer won't load *after* we attempt to subscribe the
			// onSuccess event listener. Therefore, we have to run the
			// initialization check here.
			if(!apiInternal.drawer.initialized) {
				fteRun = true;
				return;
			}

			fteRun = true;
			initializeStyles();

			var nexus = apiInternal.util.dom.getElementsByClassName(NEXUS_CLASS)[0];
			var tooltipContent = buildIntroTooltip();

			var drawer = document.getElementById(DRAWER_ID);
			drawerLock = apiInternal.slider.lockDrawerOpen();
			apiInternal.util.dom.applyClassToElement(drawer, MASK_CLASS);

			applyMaskOverrides(nexus, DRAWER_BACKGROUND);
			apiInternal.fteTooltip.addTooltipToDrawer(nexus, tooltipContent);
		}
	}

	// STEP 2
	// This highlights the next steps that are available to the user.
	// Specifically, sharing or saving the link.
	function runActionElements() {
		var pen = apiInternal.util.dom.getElementsByClassName(PEN_CLASS)[0];
		var tooltipContent = buildActionTooltip();

		removeMaskOverrides();
		applyMaskOverrides(pen, DRAWER_BACKGROUND);
		apiInternal.fteTooltip.addTooltipToDrawer(pen, tooltipContent);
	}

	// STEP 3
	// This communicates that the user can click on the previous submission
	// text to re-open the drawer
	function runReopenDrawer() {
		var selectedText = apiInternal.util.dom.getElementsByClassName(SELECTED_CLASS);
		if(selectedText && selectedText.length) {
			var firstSelectedText = selectedText[0];
			var tooltipContent = buildReopenTooltip();

			removeMaskOverrides();
			applyMaskOverrides(selectedText);
			apiInternal.fteTooltip.addTooltipToPage(firstSelectedText, tooltipContent);

			apiInternal.smoothScroll(TOOLTIP_SELECTOR.substr(1), {pixelBuffer: 125});
		}
	}

	function closeFTE(e) {
		if(e) {
			e.preventDefault ? e.preventDefault() : window.event.returnValue = false;
		}

		var drawer = document.getElementById(DRAWER_ID);
		apiInternal.fteTooltip.remove();
		removeMaskOverrides();
		apiInternal.util.dom.removeClassFromElement(drawer, MASK_CLASS);
		apiInternal.slider.releaseDrawerLock(drawerLock);
	}

	/* ========================================================== */

	// Build the content for the tooltip for the Intro step
	function buildIntroTooltip() {
		var div = document.createElement('div');
		var btns = document.createElement('div');
		var primaryBtn = apiInternal.util.dom.createAnchorElement('Follow Your Link', apiInternal.lastSubmission.lastSuccessful.link, "_blank");
		var secondaryBtn = document.createElement('button');

		btns.className = BUTTONS_CLASS;
		primaryBtn.className = BUTTON_CLASS;
		secondaryBtn.className = BUTTON_CLASS + " " + BUTTON_CLASS_SECONDARY;
		secondaryBtn.type = 'button';
		secondaryBtn.appendChild(document.createTextNode('Not Now'));

		btns.appendChild(primaryBtn);
		btns.appendChild(secondaryBtn);

		var p1 = document.createElement('p');
		var p2 = document.createElement('p');
		p1.appendChild(document.createTextNode('You just created a new link!'));
		p2.appendChild(document.createTextNode('Following it will take you right back to the highlighted text.'));

		div.appendChild(p1);
		div.appendChild(p2);
		div.appendChild(btns);

		div.style.width = 'auto';

		apiInternal.addListener(secondaryBtn, "click", runActionElements);
		apiInternal.addListener(secondaryBtn, "touch", runActionElements);

		apiInternal.addListener(primaryBtn, "click", runActionElements);
		apiInternal.addListener(primaryBtn, "touch", runActionElements);
		apiInternal.addListener(primaryBtn, "click", addFTECookie);
		apiInternal.addListener(primaryBtn, "touch", addFTECookie);

		return div;
	}

	// Build the content for the tooltip for the sharing/saving
	// links
	function buildActionTooltip() {
		var div = document.createElement('div');
		var btns = document.createElement('div');
		var primaryBtn = document.createElement('button');

		btns.className = BUTTONS_CLASS;
		primaryBtn.className = BUTTON_CLASS;
		primaryBtn.type = 'button';
		primaryBtn.appendChild(document.createTextNode('Continue'));

		btns.appendChild(primaryBtn);

		div.appendChild(document.createTextNode('Use these buttons to share or save your link.'));
		div.appendChild(btns);

		div.style.width = 'auto';

		apiInternal.addListener(primaryBtn, "click", runReopenDrawer);
		apiInternal.addListener(primaryBtn, "touch", runReopenDrawer);

		return div;
	}

	// Build the content for the tooltip for reopening the drawer
	function buildReopenTooltip() {
		var div = document.createElement('div');
		var btns = document.createElement('div');
		var primaryBtn = document.createElement('button');

		btns.className = BUTTONS_CLASS;
		primaryBtn.className = BUTTON_CLASS;
		primaryBtn.type = 'button';
		primaryBtn.appendChild(document.createTextNode('Done'));

		btns.appendChild(primaryBtn);

		div.appendChild(document.createTextNode('When the sidebar closes, you can reopen it by clicking on your selection.'));
		div.appendChild(btns);

		div.style.width = 'auto';

		apiInternal.addListener(primaryBtn, "click", closeFTE);
		apiInternal.addListener(primaryBtn, "touch", closeFTE);

		return div;
	}

	// Apply a class to the provided list of elements that will make them
	// 'pop out' of the background and display on top of the FTE mask.
	function applyMaskOverrides(elements, opt_background) {
		if(!elements.length) { elements = [elements]; }

		for(var i = 0, len = elements.length; i < len; i++) {
			apiInternal.util.dom.applyClassToElement(elements[i], MASK_OVERRIDE_CLASS);
			elements[i].style.setProperty("z-index", "2147483647", "important");
			if(opt_background) {
				elements[i].style.setProperty("background-color", opt_background, "important");
			}
		}
	}

	// Remove all instances of the MASK_OVERRIDE_CLASS
	function removeMaskOverrides() {
		var overrides = apiInternal.util.dom.getElementsByClassName(MASK_OVERRIDE_CLASS);
		for(var i = overrides.length-1; i >= 0; i--) {
			var override = overrides[i];
			apiInternal.util.dom.removeClassFromElement(override, MASK_OVERRIDE_CLASS);
			override.style.zIndex = '';
			override.style.backgroundColor = '';
		}
	}

	function addFTECookie() {
		var minutesUntilExpire = 1;
		var d = new Date()
		var expires = (d.getTime() + (minutesUntilExpire*60*1000))/1000;

		apiInternal.storage.setCookie('betterlink-fromFTE', 1, expires);
	}

	function removeFTECookie() {
		apiInternal.storage.removeCookie('betterlink-fromFTE');
	}

	function initializeStyles() {
		if(!stylesInitialized) {
			stylesInitialized = true;
			apiInternal.util.dom.createAndAppendStyleElement(CSS);
		}
	}
});
<commit_msg>add FTE step for viewing the result of submission<commit_after>/**
 * Controls the First Time Experience for the user interface.
 *
 */
betterlink_user_interface.createModule("FTE", function(api, apiInternal) {
	api.requireModules( ["Util.DOM", "Storage", "FTE Tooltip", "LastSubmission", "Drawer Slider", "Action Drawer", "Util.HTTP", "HTTP", "Smooth Scrolling", "Event Messaging"] );

	// Element Selectors. These should be dynamic to make the FTE
	// resilient.
	var TOOLTIP_SELECTOR = "#betterlink-tooltip";
	var DRAWER_ID = "betterlink-drawer";
	var NEXUS_CLASS = "betterlink-nexus";
	var PEN_CLASS = "betterlink-pen";
	var SELECTED_CLASS = "betterlink-selected";
	var RESULT_CLASS = api["config"]["highlightCustomCssClass"] || api["config"]["highlightCssClass"];
	var DRAWER_BACKGROUND = "#E9E9E9";

	var BUTTON_CLASS = "betterlink-tooltip-btn";
	var BUTTON_CLASS_SECONDARY = "betterlink-tooltip-btn-secondary";
	var BUTTONS_CLASS = "betterlink-tooltip-btns";
	var MASK_CLASS = "betterlink-fte-mask";
	var MASK_OVERRIDE_CLASS = "betterlink-fte-mask-override";

	var CSS =
		[   TOOLTIP_SELECTOR + " ." + BUTTON_CLASS + " { background-color: #3299BB; border: 1px solid #277799; color: #FFF; font-size: 14px; margin: 5px; padding: 6px 12px; border-radius: .4em; display: inline-block; text-align: center; white-space: nowrap; vertical-align: middle; touch-action: manipulation; cursor: pointer; text-decoration: none; }",
			TOOLTIP_SELECTOR + " ." + BUTTON_CLASS + ":hover { background-color: #277799; text-decoration: none; }",
			TOOLTIP_SELECTOR + " ." + BUTTON_CLASS_SECONDARY + " { background-color: #BCBCBC; border: 1px solid #9B9B9B; }",
			TOOLTIP_SELECTOR + " ." + BUTTON_CLASS_SECONDARY + ":hover { background-color: #9B9B9B; }",
			TOOLTIP_SELECTOR + " ." + BUTTONS_CLASS + " { text-align: right; width: auto; margin-top: 5px }",
			TOOLTIP_SELECTOR + " p { margin-bottom: 6px; }",

			// The mask has a z-index one less than the maximum
			// Any overrides have a z-index that's the maximum value
			"." + MASK_CLASS + ":after { content: ''; background-color: #000; opacity: 0.6; display: block; position: fixed; top: 0; left: 0; height: 100%; width: 100%; z-index: 2147483646; }",
			"." + MASK_OVERRIDE_CLASS + "{ position: relative !important; box-shadow: 0 0 5px 2px #BCBCBC; text-shadow: 0 1px 1px rgba(0, 0, 0, 0.25); }"

		].join(' ');

	var stylesInitialized = false;
	var fteRun = false;
	var drawerLock;

	/****************************************************************************************************/

	apiInternal.events.registerObserverForRemoveBetterlink(closeFTE);
	apiInternal.addInitListener(loadFTE);

	// Register the FTE to run with the next successful submission
	function loadFTE() {
		if(api['config']['enableFTE']) {
			// Queries the server to determine if the user has already
			// viewed the FTE, based on registerFTE()
			apiInternal.checkFTE(decideToLoadFTE);

			// Everytime there is a new submission, refresh that the user
			// doesn't need the FTE. In the event the user *has not* seen
			// it, this will get called along with runIntro the first time.
			apiInternal.lastSubmission.subscribeSuccess.onsuccess(apiInternal.registerFTE);

			// If the user is opening the page and the 'fromFTE' cookie is
			// set, assume the user has just clicked 'Follow Your Link'
			// from the FTE. Once Betterlink highlights the saved content,
			// display the continuation of the FTE.
			if(apiInternal.storage.getCookie('betterlink-fromFTE')) {
				window.setTimeout(runViewingLink, 1000);
			}
		}
	}

	// Asynchronous check for whether we should load the FTE for this
	// user
	function decideToLoadFTE(errorInfo, response) {
		// If we can't get a response from the server, assume the user
		// *has not* seen the FTE. Rationale: we're currently only
		// displaying the FTE on the Betterlink landing page.
		if(errorInfo) {
			apiInternal.lastSubmission.subscribeSuccess.onsuccess(runIntro);
		}
		else {
			// Asynchronously parse the response JSON. Expected result:
			// { fte: '1' } indicates the user has seen the FTE
			apiInternal.util.http.parseJSONServerResponseAsync(response, function(parsedResponse) {
				if(Object.hasOwnProperty.call(parsedResponse, 'fte')) {
					if(parsedResponse['fte'] !== '1') {
						apiInternal.lastSubmission.subscribeSuccess.onsuccess(runIntro);
					}
				}
			});
		}
	}

	// STEP 1
	// This explains that a new link was created and allows the user
	// to demo visiting their new link
	function runIntro() {
		if(!fteRun) {
			// The core interface gets loaded via an init listener, just
			// like loadFTE(). This means we can't guarantee that the
			// drawer won't load *after* we attempt to subscribe the
			// onSuccess event listener. Therefore, we have to run the
			// initialization check here.
			if(!apiInternal.drawer.initialized) {
				fteRun = true;
				return;
			}

			fteRun = true;
			initializeStyles();

			var nexus = apiInternal.util.dom.getElementsByClassName(NEXUS_CLASS)[0];
			var tooltipContent = buildIntroTooltip();

			var drawer = document.getElementById(DRAWER_ID);
			drawerLock = apiInternal.slider.lockDrawerOpen();
			apiInternal.util.dom.applyClassToElement(drawer, MASK_CLASS);

			applyMaskOverrides(nexus, DRAWER_BACKGROUND);
			apiInternal.fteTooltip.addTooltipToDrawer(nexus, tooltipContent);
		}
	}

	// STEP 2
	// This highlights the next steps that are available to the user.
	// Specifically, sharing or saving the link.
	function runActionElements() {
		var pen = apiInternal.util.dom.getElementsByClassName(PEN_CLASS)[0];
		var tooltipContent = buildActionTooltip();

		removeMaskOverrides();
		applyMaskOverrides(pen, DRAWER_BACKGROUND);
		apiInternal.fteTooltip.addTooltipToDrawer(pen, tooltipContent);
	}

	// STEP 3
	// This communicates that the user can click on the previous submission
	// text to re-open the drawer
	function runReopenDrawer() {
		var selectedText = apiInternal.util.dom.getElementsByClassName(SELECTED_CLASS);
		if(selectedText && selectedText.length) {
			var firstSelectedText = selectedText[0];
			var tooltipContent = buildReopenTooltip();

			removeMaskOverrides();
			applyMaskOverrides(selectedText);
			apiInternal.fteTooltip.addTooltipToPage(firstSelectedText, tooltipContent);

			apiInternal.smoothScroll(TOOLTIP_SELECTOR.substr(1), {pixelBuffer: 125});
		}
	}

	// STEP 1b
	// This explains that the user is viewing the result of their submission
	// and directs the user back to the previous page.
	// Note: This step is the first of a newly-loaded page
	function runViewingLink() {
		removeFTECookie();
		var selectedText = apiInternal.util.dom.getElementsByClassName(RESULT_CLASS);
		if(selectedText && selectedText.length) {
			initializeStyles();
			var firstSelectedText = selectedText[0];
			var tooltipContent = buildViewingLinkTooltip();

			// Because the drawer will be closed in this example, we need
			// to apply the overlay to the body
			apiInternal.util.dom.applyClassToElement(document.body, MASK_CLASS);

			applyMaskOverrides(selectedText);
			apiInternal.fteTooltip.addTooltipToPage(firstSelectedText, tooltipContent);

			apiInternal.smoothScroll(TOOLTIP_SELECTOR.substr(1), {pixelBuffer: 75});
		}
	}

	function closeFTE(e) {
		if(e) {
			e.preventDefault ? e.preventDefault() : window.event.returnValue = false;
		}

		var drawer = document.getElementById(DRAWER_ID);
		apiInternal.fteTooltip.remove();
		removeMaskOverrides();
		apiInternal.util.dom.removeClassFromElement(drawer, MASK_CLASS);
		apiInternal.util.dom.removeClassFromElement(document.body, MASK_CLASS);
		apiInternal.slider.releaseDrawerLock(drawerLock);
	}

	/* ========================================================== */

	// Build the content for the tooltip for the Intro step
	function buildIntroTooltip() {
		var div = document.createElement('div');
		var btns = document.createElement('div');
		var primaryBtn = apiInternal.util.dom.createAnchorElement('Follow Your Link', apiInternal.lastSubmission.lastSuccessful.link, "_blank");
		var secondaryBtn = document.createElement('button');

		btns.className = BUTTONS_CLASS;
		primaryBtn.className = BUTTON_CLASS;
		secondaryBtn.className = BUTTON_CLASS + " " + BUTTON_CLASS_SECONDARY;
		secondaryBtn.type = 'button';
		secondaryBtn.appendChild(document.createTextNode('Not Now'));

		btns.appendChild(primaryBtn);
		btns.appendChild(secondaryBtn);

		var p1 = document.createElement('p');
		var p2 = document.createElement('p');
		p1.appendChild(document.createTextNode('You just created a new link!'));
		p2.appendChild(document.createTextNode('Following it will take you right back to the highlighted text.'));

		div.appendChild(p1);
		div.appendChild(p2);
		div.appendChild(btns);

		div.style.width = 'auto';

		apiInternal.addListener(secondaryBtn, "click", runActionElements);
		apiInternal.addListener(secondaryBtn, "touch", runActionElements);

		apiInternal.addListener(primaryBtn, "click", runActionElements);
		apiInternal.addListener(primaryBtn, "touch", runActionElements);
		apiInternal.addListener(primaryBtn, "click", addFTECookie);
		apiInternal.addListener(primaryBtn, "touch", addFTECookie);

		return div;
	}

	// Build the content for the tooltip for the sharing/saving
	// links
	function buildActionTooltip() {
		var div = document.createElement('div');
		var btns = document.createElement('div');
		var primaryBtn = document.createElement('button');

		btns.className = BUTTONS_CLASS;
		primaryBtn.className = BUTTON_CLASS;
		primaryBtn.type = 'button';
		primaryBtn.appendChild(document.createTextNode('Continue'));

		btns.appendChild(primaryBtn);

		div.appendChild(document.createTextNode('Use these buttons to share or save your link.'));
		div.appendChild(btns);

		div.style.width = 'auto';

		apiInternal.addListener(primaryBtn, "click", runReopenDrawer);
		apiInternal.addListener(primaryBtn, "touch", runReopenDrawer);

		return div;
	}

	// Build the content for the tooltip for reopening the drawer
	function buildReopenTooltip() {
		var div = document.createElement('div');
		var btns = document.createElement('div');
		var primaryBtn = document.createElement('button');

		btns.className = BUTTONS_CLASS;
		primaryBtn.className = BUTTON_CLASS;
		primaryBtn.type = 'button';
		primaryBtn.appendChild(document.createTextNode('Done'));

		btns.appendChild(primaryBtn);

		div.appendChild(document.createTextNode('When the sidebar closes, you can reopen it by clicking on your selection.'));
		div.appendChild(btns);

		div.style.width = 'auto';

		apiInternal.addListener(primaryBtn, "click", closeFTE);
		apiInternal.addListener(primaryBtn, "touch", closeFTE);

		return div;
	}

	// Build the content for the tooltip for viewing the result
	// of a submission
	function buildViewingLinkTooltip() {
		var div = document.createElement('div');
		var btns = document.createElement('div');
		var primaryBtn = document.createElement('button');

		btns.className = BUTTONS_CLASS;
		primaryBtn.className = BUTTON_CLASS;
		primaryBtn.type = 'button';
		primaryBtn.appendChild(document.createTextNode('Close Page'));

		btns.appendChild(primaryBtn);

		var p1 = document.createElement('p');
		var p2 = document.createElement('p');
		p1.appendChild(document.createTextNode('Visitors to your new link will see this text highlighted.'));
		p2.appendChild(document.createTextNode('This example opened in a new tab. To go back to your submission, close this page.'));
		p2.style.fontSize = "smaller";
		p2.style.fontStyle = "italic";

		div.appendChild(p1);
		div.appendChild(p2);
		div.appendChild(btns);

		div.style.width = 'auto';

		apiInternal.addListener(primaryBtn, "click", closeFTE);
		apiInternal.addListener(primaryBtn, "touch", closeFTE);
		apiInternal.addListener(primaryBtn, "click", window.close, window);
		apiInternal.addListener(primaryBtn, "touch", window.close, window);

		return div;
	}

	// Apply a class to the provided list of elements that will make them
	// 'pop out' of the background and display on top of the FTE mask.
	function applyMaskOverrides(elements, opt_background) {
		if(!elements.length) { elements = [elements]; }

		for(var i = 0, len = elements.length; i < len; i++) {
			apiInternal.util.dom.applyClassToElement(elements[i], MASK_OVERRIDE_CLASS);
			elements[i].style.setProperty("z-index", "2147483647", "important");
			if(opt_background) {
				elements[i].style.setProperty("background-color", opt_background, "important");
			}
		}
	}

	// Remove all instances of the MASK_OVERRIDE_CLASS
	function removeMaskOverrides() {
		var overrides = apiInternal.util.dom.getElementsByClassName(MASK_OVERRIDE_CLASS);
		for(var i = overrides.length-1; i >= 0; i--) {
			var override = overrides[i];
			apiInternal.util.dom.removeClassFromElement(override, MASK_OVERRIDE_CLASS);
			override.style.zIndex = '';
			override.style.backgroundColor = '';
		}
	}

	function addFTECookie() {
		var minutesUntilExpire = 1;
		var d = new Date()
		var expires = (d.getTime() + (minutesUntilExpire*60*1000))/1000;

		apiInternal.storage.setCookie('betterlink-fromFTE', 1, expires);
	}

	function removeFTECookie() {
		apiInternal.storage.removeCookie('betterlink-fromFTE');
	}

	function initializeStyles() {
		if(!stylesInitialized) {
			stylesInitialized = true;
			apiInternal.util.dom.createAndAppendStyleElement(CSS);
		}
	}
});
<|endoftext|>


<commit_before>// Usage:
// osmjs -l sparsetable -j osm-boundaries.js boundaries.osm | psql <dbname>

var ways_table = 'carto_boundary';

Osmium.Callbacks.way = function() {
    // This will import all ways in the OSM file except coastlines. We assume
    // that we are only looking at ways that are members of boundary relations.

    // ignore coastlines & closure segments
    if (this.tags['natural'] == 'coastline'
        || this.tags['closure_segment']) {
        return;
    }

    var geometry = this.geom.toHexWKB(true);
    // Catch failed geometries, skip them
    if (geometry == undefined) {
        return;
    }

    var maritime = 0;
    var disputed = 0;
    var admin_level;
    var maritime_like = [
        'eez',
        'maritime',
        'territorial_waters',
        'territorial waters'
    ];

    if (this.tags['maritime']) {
        // TODO: more tags
        maritime = 1;
    }

    if (this.tags['disputed'] || this.tags['dispute']
        || this.tags['border_status'] === 'dispute')  {
        disputed = 1;
    }

    print(["SELECT insert_boundary(",this.id, ", ", maritime, ", ", disputed,
          ", '", geometry, "'::geometry);"].join(""));
}

Osmium.Callbacks.relation = function() {
    var rel_id = this.id,
        way_ids = [],
        admin_level,
        maritime,
        disputed;

    try {
        admin_level = parseInt(this.tags['admin_level']);
    } catch(e) {}

    for (var i=0; i < this.members.length; i++) {
        // build a list of way members for processing
        if (this.members[i].type = 'w') {
            way_ids.push(this.members[i].ref);
        }
    }

    if (way_ids.length === 0) {
        // relation has no way members, no updates needed
        return;
    }

    way_ids = way_ids.join(', ');

    if (typeof admin_level === 'number') {
        print(['UPDATE', ways_table, 'SET admin_level =', admin_level,
              'WHERE osm_id in (', way_ids, ') AND (admin_level >',
              admin_level, 'OR admin_level IS NULL);'].join(' '));
    }

    if (this.tags['maritime']) {
        // TODO: more tags
        print(['UPDATE', ways_table, 'SET maritime = 1 WHERE osm_id in (',
              way_ids, ');'].join(' '));
    }

    if (this.tags['disputed'] || this.tags['dispute']) {
        print(['UPDATE', ways_table, 'SET disputed = 1 WHERE osm_id in (',
              way_ids, ');'].join(' '));
    }
}
<commit_msg>Moves maritime and disputed checks to separate functions. Improves checks.<commit_after>// Usage:
// osmjs -l sparsetable -j osm-boundaries.js boundaries.osm | psql <dbname>

var ways_table = 'carto_boundary';

is_maritime = function(tags) {
    if (tags['maritime']) {
        return 1
    }
    var maritime_tags = [
        'boundary_type',
        'border_type',
        'boundary'
    ];
    var maritime_vals = [
        'eez',
        'maritime',
        'territorial_waters',
        'territorial waters'
    ];
    for (i = 0; i < maritime_tags.length; i++) {
        if (maritime_vals.indexOf(tags[maritime_tags[i]]) >= 0) {
            return 1;
        }
    }
    return 0;
}

is_disputed = function(tags) {
    if (tags['disputed'] || tags['dispute']
        || tags['border_status'] === 'dispute')  {
        return 1
    }
    return 0
}

Osmium.Callbacks.way = function() {
    // This will import all ways in the OSM file except coastlines. We assume
    // that we are only looking at ways that are members of boundary relations.

    // ignore coastlines & closure segments
    if (this.tags['natural'] == 'coastline'
        || this.tags['closure_segment']) {
        return;
    }

    var geometry = this.geom.toHexWKB(true);
    // Catch failed geometries, skip them
    if (geometry == undefined) {
        return;
    }

    print(["SELECT insert_boundary(",this.id, ", ", is_maritime(this.tags),
          ", ", is_disputed(this.tags), ", '", geometry,
          "'::geometry);"].join(""));
}

Osmium.Callbacks.relation = function() {
    var rel_id = this.id,
        way_ids = [],
        admin_level

    try {
        admin_level = parseInt(this.tags['admin_level']);
    } catch(e) {}

    for (var i=0; i < this.members.length; i++) {
        // build a list of way members for processing
        if (this.members[i].type = 'w') {
            way_ids.push(this.members[i].ref);
        }
    }

    if (way_ids.length === 0) {
        // relation has no way members, no updates needed
        return;
    }

    way_ids = way_ids.join(', ');

    if (typeof admin_level === 'number') {
        print(['UPDATE', ways_table, 'SET admin_level =', admin_level,
              'WHERE osm_id in (', way_ids, ') AND (admin_level >',
              admin_level, 'OR admin_level IS NULL);'].join(' '));
    }

    if (is_maritime(this.tags)) {
        // TODO: more tags
        print(['UPDATE', ways_table, 'SET maritime = 1 WHERE osm_id in (',
              way_ids, ');'].join(' '));
    }

    if (is_disputed(this.tags)) {
        print(['UPDATE', ways_table, 'SET disputed = 1 WHERE osm_id in (',
              way_ids, ');'].join(' '));
    }
}
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { storiesOf } from '@storybook/react';

import { Grommet, Box, Button, Grid, Text } from 'grommet';
import { grommet } from 'grommet/themes';

class AppGrid extends Component {
  state = { sidebar: true };

  render() {
    const { sidebar } = this.state;
    return (
      <Grommet full theme={grommet}>
        <Grid
          fill
          rows={['auto', 'flex']}
          columns={['auto', 'flex']}
          areas={[
            { name: 'header', start: [0, 0], end: [1, 0] },
            { name: 'sidebar', start: [0, 1], end: [0, 1] },
            { name: 'main', start: [1, 1], end: [1, 1] },
          ]}
        >
          <Box
            gridArea="header"
            direction="row"
            align="center"
            justify="between"
            pad={{ horizontal: 'medium', vertical: 'small' }}
            background="dark-2"
          >
            <Button onClick={() => this.setState({ sidebar: !sidebar })}>
              <Text size="large">Title</Text>
            </Button>
            <Text>my@email</Text>
          </Box>
          {sidebar && (
            <Box
              gridArea="sidebar"
              background="dark-3"
              width="small"
              animation={[
                { type: 'fadeIn', duration: 300 },
                { type: 'slideRight', size: 'xlarge', duration: 150 },
              ]}
            >
              {['First', 'Second', 'Third'].map(name => (
                <Button key={name} href="#" hoverIndicator>
                  <Box pad={{ horizontal: 'medium', vertical: 'small' }}>
                    <Text>{name}</Text>
                  </Box>
                </Button>
              ))}
            </Box>
          )}
          <Box gridArea="main" justify="center" align="center">
            <Text>main</Text>
          </Box>
        </Grid>
      </Grommet>
    );
  }
}

const Percentages = () => (
  <Grommet theme={grommet} full>
    <Grid
      fill
      areas={[
        { name: 'nav', start: [0, 0], end: [0, 0] },
        { name: 'main', start: [1, 0], end: [1, 0] },
      ]}
      columns={['small', 'flex']}
      rows={['flex']}
      gap="small"
    >
      <Box gridArea="nav" background="brand" />
      <Box gridArea="main" background="brand" />
    </Grid>
  </Grommet>
);

const NColumnGrid = () => (
  <Grommet theme={grommet} full>
    <Grid
      columns={{
        count: 6,
        size: 'auto',
      }}
      gap="small"
    >
      <Box background="brand">Item 1</Box>
      <Box background="brand">Item 2</Box>
      <Box background="brand">Item 3</Box>
      <Box background="brand">Item 4</Box>
      <Box background="brand">Item 5</Box>
      <Box background="brand">Item 6</Box>
    </Grid>
  </Grommet>
);

storiesOf('Grid', module)
  .add('App', () => <AppGrid />)
  .add('Percentages', () => <Percentages />)
  .add('N-column layout', () => <NColumnGrid />);
<commit_msg>Signed-off-by: imad <imad.messelmani@live.com> (#3266)<commit_after>import React, { Component } from 'react';
import { storiesOf } from '@storybook/react';

import { Grommet, Box, Button, Grid, Text, Heading, ResponsiveContext } from 'grommet';
import { grommet } from 'grommet/themes';
import { deepMerge } from 'grommet/utils';

class AppGrid extends Component {
  state = { sidebar: true };

  render() {
    const { sidebar } = this.state;
    return (
      <Grommet full theme={grommet}>
        <Grid
          fill
          rows={['auto', 'flex']}
          columns={['auto', 'flex']}
          areas={[
            { name: 'header', start: [0, 0], end: [1, 0] },
            { name: 'sidebar', start: [0, 1], end: [0, 1] },
            { name: 'main', start: [1, 1], end: [1, 1] },
          ]}
        >
          <Box
            gridArea="header"
            direction="row"
            align="center"
            justify="between"
            pad={{ horizontal: 'medium', vertical: 'small' }}
            background="dark-2"
          >
            <Button onClick={() => this.setState({ sidebar: !sidebar })}>
              <Text size="large">Title</Text>
            </Button>
            <Text>my@email</Text>
          </Box>
          {sidebar && (
            <Box
              gridArea="sidebar"
              background="dark-3"
              width="small"
              animation={[
                { type: 'fadeIn', duration: 300 },
                { type: 'slideRight', size: 'xlarge', duration: 150 },
              ]}
            >
              {['First', 'Second', 'Third'].map(name => (
                <Button key={name} href="#" hoverIndicator>
                  <Box pad={{ horizontal: 'medium', vertical: 'small' }}>
                    <Text>{name}</Text>
                  </Box>
                </Button>
              ))}
            </Box>
          )}
          <Box gridArea="main" justify="center" align="center">
            <Text>main</Text>
          </Box>
        </Grid>
      </Grommet>
    );
  }
}

const Percentages = () => (
  <Grommet theme={grommet} full>
    <Grid
      fill
      areas={[
        { name: 'nav', start: [0, 0], end: [0, 0] },
        { name: 'main', start: [1, 0], end: [1, 0] },
      ]}
      columns={['small', 'flex']}
      rows={['flex']}
      gap="small"
    >
      <Box gridArea="nav" background="brand" />
      <Box gridArea="main" background="brand" />
    </Grid>
  </Grommet>
);

const NColumnGrid = () => (
  <Grommet theme={grommet} full>
    <Grid
      columns={{
        count: 6,
        size: 'auto',
      }}
      gap="small"
    >
      <Box background="brand">Item 1</Box>
      <Box background="brand">Item 2</Box>
      <Box background="brand">Item 3</Box>
      <Box background="brand">Item 4</Box>
      <Box background="brand">Item 5</Box>
      <Box background="brand">Item 6</Box>
    </Grid>
  </Grommet>
);

// Two responsive grids
//    - First one with a known number of elements
//    - Second one with an unknown number of elements

// set custom breakpoints so we can see the changes
const customBreakpoints = deepMerge(grommet, {
  global: {
    breakpoints: {
      small: {
        value: 600,
      },
      medium: {
        value: 900,
      },
      large: 3000,
    },
  },
});

// columns, rows and areas are for Grid with a known number of contents / boxes.

// If the size is small, we only see 1 column
// If the size is medium, we only see 2 columns
// If the size is either large or xlarge, we see 3 columns
const columns = {
  small: ['auto'],
  medium: ['auto', 'auto'],
  large: ['auto', 'auto', 'auto'],
  xlarge: ['auto', 'auto', 'auto'],
};

// If the size is small, we have 3 rows
// If the size is medium, we have 2 rows
// If the size is large or xlarge, we have 1 row
const rows = {
  small: ['xsmall', 'xsmall', 'xsmall'],
  medium: ['xsmall', 'xsmall'],
  large: ['xsmall'],
  xlarge: ['xsmall'],
};

// set the different areas you need for every size
const fixedGridAreas = {
  small: [
    { name: 'header', start: [0, 0], end: [0, 0] },
    { name: 'test', start: [0, 1], end: [0, 1] },
    { name: 'test1', start: [0, 2], end: [0, 2] },
  ],
  medium: [
    { name: 'header', start: [0, 0], end: [1, 0] },
    { name: 'test', start: [0, 1], end: [0, 1] },
    { name: 'test1', start: [1, 1], end: [1, 1] },
  ],
  large: [
    { name: 'header', start: [0, 0], end: [0, 0] },
    { name: 'test', start: [1, 0], end: [1, 0] },
    { name: 'test1', start: [2, 0], end: [2, 0] },
  ],
  xlarge: [
    { name: 'header', start: [0, 0], end: [0, 0] },
    { name: 'test', start: [1, 0], end: [1, 0] },
    { name: 'test1', start: [2, 0], end: [2, 0] },
  ],
};

// let's say this is returned from an API
const animals = [
  'dog',
  'cat',
  'pig',
  'cow',
  'giraffe',
  'elephant',
  'dinosaur',
  'chicken',
  'duck',
  'tiger',
  'lion',
  'cheetah',
];

// Create box for each animal
const listAnimalsBoxes = animals.map(animalName => (
  <Box
    elevation="large"
    key={animalName}
    background="light-3"
    flex={false}
    justify="center"
    align="center"
  >
    <Heading level={2}>{animalName}</Heading>
  </Box>
));

const Responsive = ({
  children,
  overrideColumns,
  overrideRows,
  areas,
  ...props
}) => (
  <ResponsiveContext.Consumer>
    {size => {
      // take into consideration if not array is sent but a simple string
      let columnsVal = columns;
      if (columns) {
        if (columns[size]) {
          columnsVal = columns[size];
        }
      }

      let rowsVal = rows;
      if (rows) {
        if (rows[size]) {
          rowsVal = rows[size];
        }
      }

      // also if areas is a simple array not an object of arrays for different sizes
      let areasVal = areas;
      if (areas && !Array.isArray(areas)) areasVal = areas[size];

      return (
        <Grid
          {...props}
          areas={!areasVal ? undefined : areasVal}
          rows={!rowsVal ? size : rowsVal}
          columns={!columnsVal ? size : columnsVal}
        >
          {children}
        </Grid>
      );
    }}
  </ResponsiveContext.Consumer>
);

const ResponsiveGrid = () => (
  <Grommet theme={customBreakpoints}>
    <Box>
      <Heading level={2}>Resize me.</Heading>
      <Responsive
        rows={rows}
        columns={columns}
        gap="small"
        areas={fixedGridAreas}
        margin="medium"
      >
        <Box
          gridArea="header"
          background="neutral-2"
          justify="center"
          align="center"
        >
          Box 1
        </Box>
        <Box
          gridArea="test"
          background="neutral-3"
          justify="center"
          align="center"
        >
          Box 2
        </Box>
        <Box
          gridArea="test1"
          background="neutral-4"
          justify="center"
          align="center"
        >
          Box 3
        </Box>
      </Responsive>
      <Responsive
        gap="small"
        margin="medium"
        columns="medium"
        rows="xsmall"
      >
        {listAnimalsBoxes}
      </Responsive>
    </Box>
  </Grommet>
);

storiesOf('Grid', module)
  .add('App', () => <AppGrid />)
  .add('Percentages', () => <Percentages />)
  .add('N-column layout', () => <NColumnGrid />)
  .add('Responsive Grid', () => <ResponsiveGrid />);
<|endoftext|>


<commit_before>import * as R from "ramda"

//

function Identity(value) {this.value = value}
const Ident = x => new Identity(x)
Identity.prototype.map = function (x2y) {return new Identity(x2y(this.value))}
Identity.prototype.of = Ident

//

function Constant(value) {this.value = value}
const Const = x => new Constant(x)
Constant.prototype.map = function () {return this}
Constant.prototype.of = Const

//

const warned = {}

const deprecated = message => {
  if (!(message in warned)) {
    warned[message] = message
    console.warn("partial.lenses:", message)
  }
}

//

const id = x => x
const snd = (_, c) => c

//

const check = (expected, predicate) => x => {
  if (predicate(x))
    return x
  else
    throw new Error(`Expected ${expected}, but got ${x}.`)
}

const assert = process.env.NODE_ENV === "production" ? () => id : check

//

const empty = {}

const deleteKey = (k, o) => {
  if (o === undefined || !(k in o))
    return o
  let r
  for (const p in o) {
    if (p !== k) {
      if (undefined === r)
        r = {}
      r[p] = o[p]
    }
  }
  return r
}

const setKey = (k, v, o) => {
  if (o === undefined)
    return {[k]: v}
  if (k in o && R.equals(v, o[k]))
    return o
  const r = {[k]: v}
  for (const p in o)
    if (p !== k)
      r[p] = o[p]
  return r
}

//

const dropped = xs => Object.keys(xs).length === 0 ? undefined : xs

//

const toPartial = transform => x => undefined === x ? x : transform(x)

//

const conserve = (c1, c0) => R.equals(c1, c0) ? c0 : c1

const toConserve = f => (y, c0) => conserve(f(y, c0), c0)

//

const seemsLens = x => typeof x === "function" && x.length === 1

export const fromRamda = assert("a lens", seemsLens)

export const toRamda = l => {
  if (isProp(l))  return toRamdaProp(l)
  if (isIndex(l)) return toRamdaIndex(l)
  return fromRamda(l)
}

export const compose = (...ls) =>
  ls.length === 0 ? identity :
  ls.length === 1 ? ls[0] :
  R.compose(...ls.map(toRamda))

export const remove = R.curry((l, s) => setI(toRamda(l), undefined, s))

export const removeAll = R.curry((lens, data) => {
  deprecated("`removeAll` is deprecated and there is no planned replacement --- use a different approach.")
  while (get(lens, data) !== undefined)
    data = remove(lens, data)
  return data
})

const setI = (l, x, s) => l(() => Ident(x))(s).value
const getI = (l, s) => l(Const)(s).value
const modifyI = (l, x2x, s) => l(y => Ident(x2x(y)))(s).value
const lensI = (getter, setter) => toFn => target =>
  toFn(getter(target)).map(focus => setter(focus, target))

export const lens = R.curry(lensI)
export const modify = R.curry((l, x2x, s) => modifyI(toRamda(l), x2x, s))
export const set = R.curry((l, x, s) => setI(toRamda(l), x, s))
export const get = R.curry((l, s) => getI(toRamda(l), s))

export const chain = R.curry((x2yL, xL) =>
  compose(xL, choose(xO => xO === undefined ? nothing : x2yL(xO))))

export const just = x => lensI(R.always(x), snd)

export const choose = x2yL => toFunctor => target => {
  const l = toRamda(x2yL(target))
  return R.map(focus => setI(l, focus, target), toFunctor(getI(l, target)))
}

export const nothing = lensI(snd, snd)

export const orElse =
  R.curry((d, l) => choose(x => getI(toRamda(l), x) !== undefined ? l : d))

export const choice = (...ls) => choose(x => {
  const i = ls.findIndex(l => getI(toRamda(l), x) !== undefined)
  return 0 <= i ? ls[i] : nothing
})

export const replace = R.curry((inn, out) =>
  lensI(x => R.equals(x, inn) ? out : x,
        toConserve(y => R.equals(y, out) ? inn : y)))

export const defaults = replace(undefined)
export const required = inn => replace(inn, undefined)
export const define = v => R.compose(required(v), defaults(v))

export const normalize = transform =>
  lensI(toPartial(transform), toConserve(toPartial(transform)))

const isProp = x => typeof x === "string"

export const prop = assert("a string", isProp)

const toRamdaProp = k =>
  lensI(o => o && o[k],
        (v, o) => v === undefined ? deleteKey(k, o) : setKey(k, v, o))

export const find = predicate => choose(xs => {
  if (xs === undefined)
    return append
  const i = xs.findIndex(predicate)
  return i < 0 ? append : i
})

export const findWith = (...ls) => {
  const lls = toRamda(compose(...ls))
  return compose(find(x => getI(lls, x) !== undefined), lls)
}

const isIndex = x => Number.isInteger(x) && 0 <= x

export const index = assert("a non-negative integer", isIndex)

const toRamdaIndex = i => lensI(xs => xs && xs[i], (x, xs) => {
  if (x === undefined) {
    if (xs === undefined)
      return undefined
    if (i < xs.length)
      return dropped(xs.slice(0, i).concat(xs.slice(i+1)))
    return xs
  } else {
    if (xs === undefined)
      return Array(i).concat([x])
    if (xs.length <= i)
      return xs.concat(Array(i - xs.length), [x])
    if (R.equals(x, xs[i]))
      return xs
    return xs.slice(0, i).concat([x], xs.slice(i+1))
  }
})

export const append = lensI(snd, (x, xs) =>
  x === undefined ? xs : xs === undefined ? [x] : xs.concat([x]))

export const filter = p => lensI(xs => xs && xs.filter(p), (ys, xs) =>
  conserve(dropped(R.concat(ys || [], (xs || []).filter(R.complement(p)))), xs))

export const augment = template => lensI(
  toPartial(x => {
    const z = {...x}
    for (const k in template)
      z[k] = template[k](x)
    return z
  }),
  toConserve((y, c) => {
    if (y === undefined)
      return undefined
    let z
    const set = (k, v) => {
      if (undefined === z)
        z = {}
      z[k] = v
    }
    for (const k in y) {
      if (!(k in template))
        set(k, y[k])
      else
        if (k in c)
          set(k, c[k])
    }
    return z
  }))

export const pick = template => lensI(
  c => {
    let r
    for (const k in template) {
      const v = getI(toRamda(template[k]), c)
      if (v !== undefined) {
        if (r === undefined)
          r = {}
        r[k] = v
      }
    }
    return r
  },
  (o = empty, cIn) => {
    let c = cIn
    for (const k in template)
      c = setI(toRamda(template[k]), o[k], c)
    return c
  })

export const identity = lensI(id, conserve)

export const props = (...ks) => pick(R.zipObj(ks, ks))

const show = (...labels) => x => console.log(...labels, x) || x

export const log = (...labels) =>
  lensI(show(...labels, "get"), show(...labels, "set"))

export default compose
<commit_msg>Renamed internal `deprecated` to `warn`.<commit_after>import * as R from "ramda"

//

function Identity(value) {this.value = value}
const Ident = x => new Identity(x)
Identity.prototype.map = function (x2y) {return new Identity(x2y(this.value))}
Identity.prototype.of = Ident

//

function Constant(value) {this.value = value}
const Const = x => new Constant(x)
Constant.prototype.map = function () {return this}
Constant.prototype.of = Const

//

const warned = {}

const warn = message => {
  if (!(message in warned)) {
    warned[message] = message
    console.warn("partial.lenses:", message)
  }
}

//

const id = x => x
const snd = (_, c) => c

//

const check = (expected, predicate) => x => {
  if (predicate(x))
    return x
  else
    throw new Error(`Expected ${expected}, but got ${x}.`)
}

const assert = process.env.NODE_ENV === "production" ? () => id : check

//

const empty = {}

const deleteKey = (k, o) => {
  if (o === undefined || !(k in o))
    return o
  let r
  for (const p in o) {
    if (p !== k) {
      if (undefined === r)
        r = {}
      r[p] = o[p]
    }
  }
  return r
}

const setKey = (k, v, o) => {
  if (o === undefined)
    return {[k]: v}
  if (k in o && R.equals(v, o[k]))
    return o
  const r = {[k]: v}
  for (const p in o)
    if (p !== k)
      r[p] = o[p]
  return r
}

//

const dropped = xs => Object.keys(xs).length === 0 ? undefined : xs

//

const toPartial = transform => x => undefined === x ? x : transform(x)

//

const conserve = (c1, c0) => R.equals(c1, c0) ? c0 : c1

const toConserve = f => (y, c0) => conserve(f(y, c0), c0)

//

const seemsLens = x => typeof x === "function" && x.length === 1

export const fromRamda = assert("a lens", seemsLens)

export const toRamda = l => {
  if (isProp(l))  return toRamdaProp(l)
  if (isIndex(l)) return toRamdaIndex(l)
  return fromRamda(l)
}

export const compose = (...ls) =>
  ls.length === 0 ? identity :
  ls.length === 1 ? ls[0] :
  R.compose(...ls.map(toRamda))

export const remove = R.curry((l, s) => setI(toRamda(l), undefined, s))

export const removeAll = R.curry((lens, data) => {
  warn("`removeAll` is deprecated and there is no planned replacement --- use a different approach.")
  while (get(lens, data) !== undefined)
    data = remove(lens, data)
  return data
})

const setI = (l, x, s) => l(() => Ident(x))(s).value
const getI = (l, s) => l(Const)(s).value
const modifyI = (l, x2x, s) => l(y => Ident(x2x(y)))(s).value
const lensI = (getter, setter) => toFn => target =>
  toFn(getter(target)).map(focus => setter(focus, target))

export const lens = R.curry(lensI)
export const modify = R.curry((l, x2x, s) => modifyI(toRamda(l), x2x, s))
export const set = R.curry((l, x, s) => setI(toRamda(l), x, s))
export const get = R.curry((l, s) => getI(toRamda(l), s))

export const chain = R.curry((x2yL, xL) =>
  compose(xL, choose(xO => xO === undefined ? nothing : x2yL(xO))))

export const just = x => lensI(R.always(x), snd)

export const choose = x2yL => toFunctor => target => {
  const l = toRamda(x2yL(target))
  return R.map(focus => setI(l, focus, target), toFunctor(getI(l, target)))
}

export const nothing = lensI(snd, snd)

export const orElse =
  R.curry((d, l) => choose(x => getI(toRamda(l), x) !== undefined ? l : d))

export const choice = (...ls) => choose(x => {
  const i = ls.findIndex(l => getI(toRamda(l), x) !== undefined)
  return 0 <= i ? ls[i] : nothing
})

export const replace = R.curry((inn, out) =>
  lensI(x => R.equals(x, inn) ? out : x,
        toConserve(y => R.equals(y, out) ? inn : y)))

export const defaults = replace(undefined)
export const required = inn => replace(inn, undefined)
export const define = v => R.compose(required(v), defaults(v))

export const normalize = transform =>
  lensI(toPartial(transform), toConserve(toPartial(transform)))

const isProp = x => typeof x === "string"

export const prop = assert("a string", isProp)

const toRamdaProp = k =>
  lensI(o => o && o[k],
        (v, o) => v === undefined ? deleteKey(k, o) : setKey(k, v, o))

export const find = predicate => choose(xs => {
  if (xs === undefined)
    return append
  const i = xs.findIndex(predicate)
  return i < 0 ? append : i
})

export const findWith = (...ls) => {
  const lls = toRamda(compose(...ls))
  return compose(find(x => getI(lls, x) !== undefined), lls)
}

const isIndex = x => Number.isInteger(x) && 0 <= x

export const index = assert("a non-negative integer", isIndex)

const toRamdaIndex = i => lensI(xs => xs && xs[i], (x, xs) => {
  if (x === undefined) {
    if (xs === undefined)
      return undefined
    if (i < xs.length)
      return dropped(xs.slice(0, i).concat(xs.slice(i+1)))
    return xs
  } else {
    if (xs === undefined)
      return Array(i).concat([x])
    if (xs.length <= i)
      return xs.concat(Array(i - xs.length), [x])
    if (R.equals(x, xs[i]))
      return xs
    return xs.slice(0, i).concat([x], xs.slice(i+1))
  }
})

export const append = lensI(snd, (x, xs) =>
  x === undefined ? xs : xs === undefined ? [x] : xs.concat([x]))

export const filter = p => lensI(xs => xs && xs.filter(p), (ys, xs) =>
  conserve(dropped(R.concat(ys || [], (xs || []).filter(R.complement(p)))), xs))

export const augment = template => lensI(
  toPartial(x => {
    const z = {...x}
    for (const k in template)
      z[k] = template[k](x)
    return z
  }),
  toConserve((y, c) => {
    if (y === undefined)
      return undefined
    let z
    const set = (k, v) => {
      if (undefined === z)
        z = {}
      z[k] = v
    }
    for (const k in y) {
      if (!(k in template))
        set(k, y[k])
      else
        if (k in c)
          set(k, c[k])
    }
    return z
  }))

export const pick = template => lensI(
  c => {
    let r
    for (const k in template) {
      const v = getI(toRamda(template[k]), c)
      if (v !== undefined) {
        if (r === undefined)
          r = {}
        r[k] = v
      }
    }
    return r
  },
  (o = empty, cIn) => {
    let c = cIn
    for (const k in template)
      c = setI(toRamda(template[k]), o[k], c)
    return c
  })

export const identity = lensI(id, conserve)

export const props = (...ks) => pick(R.zipObj(ks, ks))

const show = (...labels) => x => console.log(...labels, x) || x

export const log = (...labels) =>
  lensI(show(...labels, "get"), show(...labels, "set"))

export default compose
<|endoftext|>


<commit_before>/*
* @Author: dmyang
* @Date:   2015-08-02 14:16:41
* @Last Modified by:   dmyang
* @Last Modified time: 2016-08-01 16:07:10
*/

'use strict';

const path = require('path')
const fs = require('fs')

const webpack = require('webpack')
const _ = require('lodash')
const glob = require('glob')

const ExtractTextPlugin = require('extract-text-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

const UglifyJsPlugin = webpack.optimize.UglifyJsPlugin
const CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin
const DefinePlugin = webpack.DefinePlugin

const srcDir = path.resolve(process.cwd(), 'src')
const assets = path.resolve(process.cwd(), 'assets')
const nodeModPath = path.resolve(__dirname, './node_modules')
const pathMap = require('./src/pathmap.json')

let entries = (() => {
    let jsDir = path.resolve(srcDir, 'js')
    let entryFiles = glob.sync(jsDir + '/*.{js,jsx}')
    let map = {}

    entryFiles.forEach((filePath) => {
        let filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))
        map[filename] = filePath
    })

    return map
})()
let chunks = Object.keys(entries)

module.exports = (options) => {
    options = options || {}

    let dev = options.dev !== undefined ? options.dev : true
    // 这里publicPath要使用绝对路径，不然scss/css最终生成的css图片引用路径是错误的，应该是scss-loader的bug
    let publicPath = '/'
    let extractCSS
    let cssLoader
    let sassLoader

    // generate entry html files
    // 自动生成入口文件，入口js名必须和入口文件名相同
    // 例如，a页的入口文件是a.html，那么在js目录下必须有一个a.js作为入口文件
    let plugins = (() => {
        let entryHtml = glob.sync(srcDir + '/*.html')
        let r = []

        entryHtml.forEach((filePath) => {
            let filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))
            let conf = {
                template: 'html!' + filePath,
                filename: filename + '.html'
            }

            if(filename in entries) {
                conf.inject = 'body'
                conf.chunks = ['vender', 'common', filename]
            }

            if('b' === filename || 'c' === filename) conf.chunks.splice(2, 0, 'common-b-c')
            // dll打包过的库，只能通过script标签引入？？
            // if('react-demo' === filename) conf.chunks.splice(2, 0, 'reactStuff')

            r.push(new HtmlWebpackPlugin(conf))
        })

        return r
    })()

    // 没有真正引用也会加载到runtime，如果没安装这些模块会导致报错，有点坑
    /*plugins.push(
        new webpack.ProvidePlugin({
            React: 'react',
            ReactDOM: 'react-dom',
            _: 'lodash', 按需引用
            $: 'jquery'
        })
    )*/

    if(dev) {
        extractCSS = new ExtractTextPlugin('css/[name].css?[contenthash]')
        cssLoader = extractCSS.extract(['css'])
        sassLoader = extractCSS.extract(['css', 'sass'])
        plugins.push(extractCSS, new webpack.HotModuleReplacementPlugin())
    } else {
        extractCSS = new ExtractTextPlugin('css/[contenthash:8].[name].min.css', {
            // 当allChunks指定为false时，css loader必须指定怎么处理
            // additional chunk所依赖的css，即指定`ExtractTextPlugin.extract()`
            // 第一个参数`notExtractLoader`，一般是使用style-loader
            // @see https://github.com/webpack/extract-text-webpack-plugin
            allChunks: false
        })
        cssLoader = extractCSS.extract(['css?minimize'])
        sassLoader = extractCSS.extract(['css?minimize', 'sass'])

        plugins.push(
            extractCSS,
            new UglifyJsPlugin({
                compress: {
                    warnings: false
                },
                output: {
                    comments: false
                },
                mangle: {
                    except: ['$', 'exports', 'require']
                }
            }),
            // use `production` mode
            new DefinePlugin({'process.env': {'NODE_ENV': JSON.stringify('production')}}),
            // new AssetsPlugin({
            //     filename: path.resolve(assets, 'source-map.json')
            // }),
            new webpack.optimize.DedupePlugin(),
            new webpack.NoErrorsPlugin()
        )
    }

    let config = {
        entry: Object.assign(entries, {
            // 用到什么公共lib（例如React.js），就把它加进vender去，目的是将公用库单独提取打包
            'vender': ['zepto'],
            // 'reactStuff': 'assets/dll/js/reactStuff.js'
        }),

        output: {
            path: assets,
            filename: dev ? '[name].js' : 'js/[chunkhash:8].[name].min.js',
            chunkFilename: dev ? '[chunkhash:8].chunk.js' : 'js/[chunkhash:8].chunk.min.js',
            hotUpdateChunkFilename: dev ? '[id].js' : 'js/[id].[chunkhash:8].min.js',
            publicPath: publicPath
        },

        resolve: {
            root: [srcDir, nodeModPath],
            alias: pathMap,
            extensions: ['', '.js', '.css', '.scss', '.tpl', '.png', '.jpg']
        },

        module: {
            loaders: [
                {
                    test: /\.((woff2?|svg)(\?v=[0-9]\.[0-9]\.[0-9]))|(woff2?|svg|jpe?g|png|gif|ico)$/,
                    loaders: [
                        // url-loader更好用，小于10KB的图片会自动转成dataUrl，
                        // 否则则调用file-loader，参数直接传入
                        'url?limit=10000&name=img/[hash:8].[name].[ext]',
                        'image?{bypassOnDebug:true, progressive:true,optimizationLevel:3,pngquant:{quality:"65-80",speed:4}}'
                    ]
                },
                {
                    test: /\.((ttf|eot)(\?v=[0-9]\.[0-9]\.[0-9]))|(ttf|eot)$/,
                    loader: 'url?limit=10000&name=fonts/[hash:8].[name].[ext]'
                },
                {test: /\.(tpl|ejs)$/, loader: 'ejs'},
                {test: /\.css$/, loader: cssLoader},
                {test: /\.scss$/, loader: sassLoader},
                {test: /\.jsx?$/, loader: 'babel?presets[]=react,presets[]=es2015'}
            ]
        },

        plugins: [
            /*new webpack.DllReferencePlugin({
                context: process.cwd(),
                manifest: require(path.join(assets, 'dll', 'js', 'reactStuff-manifest.json')),
                sourceType: 'var',
                // name: 'assets/dll/js/reactStuff.js'
            }),*/
            new CommonsChunkPlugin({
                name: 'common-b-c',
                chunks: ['b', 'c']
            }),
            new CommonsChunkPlugin({
                name: 'common',
                chunks: ['common-b-c', 'a']
            }),
            new CommonsChunkPlugin({
                name: 'vender',
                chunks: ['common']
            })
        ].concat(plugins),

        devServer: {
            hot: true,
            noInfo: false,
            inline: true,
            publicPath: publicPath,
            stats: {
                cached: false,
                colors: true
            }
        }
    }

    if (dev) {
        // 为实现webpack-hot-middleware做相关配置
        // @see https://github.com/glenjamin/webpack-hot-middleware
        ((entry) => {
            for (let key of Object.keys(entry)) {
                if (! Array.isArray(entry[key])) {
                    entry[key] = Array.of(entry[key])
                }
                entry[key].push('webpack-hot-middleware/client?reload=true')
            }
        })(config.entry)

        config.plugins.push( new webpack.HotModuleReplacementPlugin() )
        config.plugins.push( new webpack.NoErrorsPlugin() )
    }

    return config
}
<commit_msg>fix #32<commit_after>/*
* @Author: dmyang
* @Date:   2015-08-02 14:16:41
* @Last Modified by:   Ian Hu
* @Last Modified time: 2016-08-09 22:06:18
*/

'use strict';

const path = require('path')
const fs = require('fs')

const webpack = require('webpack')
const _ = require('lodash')
const glob = require('glob')

const ExtractTextPlugin = require('extract-text-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

const UglifyJsPlugin = webpack.optimize.UglifyJsPlugin
const CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin
const DefinePlugin = webpack.DefinePlugin

const srcDir = path.resolve(process.cwd(), 'src')
const assets = path.resolve(process.cwd(), 'assets')
const nodeModPath = path.resolve(__dirname, './node_modules')
const pathMap = require('./src/pathmap.json')

let entries = (() => {
    let jsDir = path.resolve(srcDir, 'js')
    let entryFiles = glob.sync(jsDir + '/*.{js,jsx}')
    let map = {}

    entryFiles.forEach((filePath) => {
        let filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))
        map[filename] = filePath
    })

    return map
})()
let chunks = Object.keys(entries)

module.exports = (options) => {
    options = options || {}

    let dev = options.dev !== undefined ? options.dev : true
    // 这里publicPath要使用绝对路径，不然scss/css最终生成的css图片引用路径是错误的，应该是scss-loader的bug
    let publicPath = '/'
    let extractCSS
    let cssLoader
    let sassLoader

    // generate entry html files
    // 自动生成入口文件，入口js名必须和入口文件名相同
    // 例如，a页的入口文件是a.html，那么在js目录下必须有一个a.js作为入口文件
    let plugins = (() => {
        let entryHtml = glob.sync(srcDir + '/*.html')
        let r = []

        entryHtml.forEach((filePath) => {
            let filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))
            let conf = {
                template: 'html!' + filePath,
                filename: filename + '.html'
            }

            if(filename in entries) {
                conf.inject = 'body'
                conf.chunks = ['vender', 'common', filename]
            }

            if('b' === filename || 'c' === filename) conf.chunks.splice(2, 0, 'common-b-c')
            // dll打包过的库，只能通过script标签引入？？
            // if('react-demo' === filename) conf.chunks.splice(2, 0, 'reactStuff')

            r.push(new HtmlWebpackPlugin(conf))
        })

        return r
    })()

    // 没有真正引用也会加载到runtime，如果没安装这些模块会导致报错，有点坑
    /*plugins.push(
        new webpack.ProvidePlugin({
            React: 'react',
            ReactDOM: 'react-dom',
            _: 'lodash', 按需引用
            $: 'jquery'
        })
    )*/

    if(dev) {
        extractCSS = new ExtractTextPlugin('css/[name].css?[contenthash]')
        cssLoader = extractCSS.extract('style', ['css'])
        sassLoader = extractCSS.extract('style', ['css', 'sass'])
        plugins.push(extractCSS, new webpack.HotModuleReplacementPlugin())
    } else {
        extractCSS = new ExtractTextPlugin('css/[contenthash:8].[name].min.css', {
            // 当allChunks指定为false时，css loader必须指定怎么处理
            // additional chunk所依赖的css，即指定`ExtractTextPlugin.extract()`
            // 第一个参数`notExtractLoader`，一般是使用style-loader
            // @see https://github.com/webpack/extract-text-webpack-plugin
            allChunks: false
        })
        cssLoader = extractCSS.extract('style', ['css?minimize'])
        sassLoader = extractCSS.extract('style', ['css?minimize', 'sass'])

        plugins.push(
            extractCSS,
            new UglifyJsPlugin({
                compress: {
                    warnings: false
                },
                output: {
                    comments: false
                },
                mangle: {
                    except: ['$', 'exports', 'require']
                }
            }),
            // use `production` mode
            new DefinePlugin({'process.env': {'NODE_ENV': JSON.stringify('production')}}),
            // new AssetsPlugin({
            //     filename: path.resolve(assets, 'source-map.json')
            // }),
            new webpack.optimize.DedupePlugin(),
            new webpack.NoErrorsPlugin()
        )
    }

    let config = {
        entry: Object.assign(entries, {
            // 用到什么公共lib（例如React.js），就把它加进vender去，目的是将公用库单独提取打包
            'vender': ['zepto'],
            // 'reactStuff': 'assets/dll/js/reactStuff.js'
        }),

        output: {
            path: assets,
            filename: dev ? '[name].js' : 'js/[chunkhash:8].[name].min.js',
            chunkFilename: dev ? '[chunkhash:8].chunk.js' : 'js/[chunkhash:8].chunk.min.js',
            hotUpdateChunkFilename: dev ? '[id].js' : 'js/[id].[chunkhash:8].min.js',
            publicPath: publicPath
        },

        resolve: {
            root: [srcDir, nodeModPath],
            alias: pathMap,
            extensions: ['', '.js', '.css', '.scss', '.tpl', '.png', '.jpg']
        },

        module: {
            loaders: [
                {
                    test: /\.((woff2?|svg)(\?v=[0-9]\.[0-9]\.[0-9]))|(woff2?|svg|jpe?g|png|gif|ico)$/,
                    loaders: [
                        // url-loader更好用，小于10KB的图片会自动转成dataUrl，
                        // 否则则调用file-loader，参数直接传入
                        'url?limit=10000&name=img/[hash:8].[name].[ext]',
                        'image?{bypassOnDebug:true, progressive:true,optimizationLevel:3,pngquant:{quality:"65-80",speed:4}}'
                    ]
                },
                {
                    test: /\.((ttf|eot)(\?v=[0-9]\.[0-9]\.[0-9]))|(ttf|eot)$/,
                    loader: 'url?limit=10000&name=fonts/[hash:8].[name].[ext]'
                },
                {test: /\.(tpl|ejs)$/, loader: 'ejs'},
                {test: /\.css$/, loader: cssLoader},
                {test: /\.scss$/, loader: sassLoader},
                {test: /\.jsx?$/, loader: 'babel?presets[]=react,presets[]=es2015'}
            ]
        },

        plugins: [
            /*new webpack.DllReferencePlugin({
                context: process.cwd(),
                manifest: require(path.join(assets, 'dll', 'js', 'reactStuff-manifest.json')),
                sourceType: 'var',
                // name: 'assets/dll/js/reactStuff.js'
            }),*/
            new CommonsChunkPlugin({
                name: 'common-b-c',
                chunks: ['b', 'c']
            }),
            new CommonsChunkPlugin({
                name: 'common',
                chunks: ['common-b-c', 'a']
            }),
            new CommonsChunkPlugin({
                name: 'vender',
                chunks: ['common']
            })
        ].concat(plugins),

        devServer: {
            hot: true,
            noInfo: false,
            inline: true,
            publicPath: publicPath,
            stats: {
                cached: false,
                colors: true
            }
        }
    }

    if (dev) {
        // 为实现webpack-hot-middleware做相关配置
        // @see https://github.com/glenjamin/webpack-hot-middleware
        ((entry) => {
            for (let key of Object.keys(entry)) {
                if (! Array.isArray(entry[key])) {
                    entry[key] = Array.of(entry[key])
                }
                entry[key].push('webpack-hot-middleware/client?reload=true')
            }
        })(config.entry)

        config.plugins.push( new webpack.HotModuleReplacementPlugin() )
        config.plugins.push( new webpack.NoErrorsPlugin() )
    }

    return config
}
<|endoftext|>


<commit_before>// see http://vuejs-templates.github.io/webpack for documentation.
var path = require('path')

module.exports = {
  build: {
    env: require('./prod.env'),
    index: path.resolve(__dirname, '../dist/index.html'),
    assetsRoot: path.resolve(__dirname, '../dist'),
    assetsSubDirectory: 'static',
    assetsPublicPath: './',
    productionSourceMap: true,
    // Gzip off by default as many popular static hosts such as
    // Surge or Netlify already gzip all static assets for you.
    // Before setting to `true`, make sure to:
    // npm install --save-dev compression-webpack-plugin
    productionGzip: false,
    productionGzipExtensions: ['js', 'css']
  },
  dev: {
    env: require('./dev.env'),
    port: 9000,
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',
    proxyTable: {
        '/api': {
            target: 'http://localhost:3000',
            changeOrigin: true,
            pathRewrite: {
                '^/api': ''
            }
        }
    },
    // CSS Sourcemaps off by default because relative paths are "buggy"
    // with this option, according to the CSS-Loader README
    // (https://github.com/webpack/css-loader#sourcemaps)
    // In our experience, they generally work as expected,
    // just be aware of this issue when enabling this option.
    cssSourceMap: false
  }
}
<commit_msg>add MANAGE_BASE<commit_after>// see http://vuejs-templates.github.io/webpack for documentation.
var path = require('path')

module.exports = {
  build: {
    env: require('./prod.env'),
    index: path.resolve(__dirname, '../dist/index.html'),
    assetsRoot: path.resolve(__dirname, '../dist'),
    assetsSubDirectory: 'static',
    assetsPublicPath: '/blog/manage/',
    productionSourceMap: true,
    // Gzip off by default as many popular static hosts such as
    // Surge or Netlify already gzip all static assets for you.
    // Before setting to `true`, make sure to:
    // npm install --save-dev compression-webpack-plugin
    productionGzip: false,
    productionGzipExtensions: ['js', 'css']
  },
  dev: {
    env: require('./dev.env'),
    port: 9000,
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',
    proxyTable: {
        '/api': {
            target: 'http://localhost:3000',
            changeOrigin: true,
            pathRewrite: {
                '^/api': ''
            }
        }
    },
    // CSS Sourcemaps off by default because relative paths are "buggy"
    // with this option, according to the CSS-Loader README
    // (https://github.com/webpack/css-loader#sourcemaps)
    // In our experience, they generally work as expected,
    // just be aware of this issue when enabling this option.
    cssSourceMap: false
  }
}
<|endoftext|>


<commit_before>

ManyModel = LinkableModel.extend();

LinkableModel.prototype.registerLinkableType = function (model, type) {
    model.prototype._objectType = type;
    LinkableTypes[type] = model.prototype._collection;
};

addLinkSchema = function() {
  var addSchema = function(model) {
    model.appendSchema({
      "links" : {
        type : Object,
        optional : true,
      }
    });
  };

  var calledCollections = [];
  return function(model) {
      if(!_.contains(calledCollections, model.collection._name)) {
        addSchema(model);
        calledCollections.push(model.collection._name);
      } else {
        console.log("Already called");
      }
  }
}();

addMethodToModel = function(model, prefix, type, func) {
	var methodName = prefix + type;
	var methods = {};
	methods[methodName] = func;
	model.methods(methods);
}

addLinkToModel = function(model, linkID, schemaString) {
    var query = {};
    query[schemaString] = linkID;
    model.update({$addToSet : query});
}

configureLinkableType = function(collection, model, type) {
  addLinkSchema(collection);
  var schemaString = "links." + type;
    var schemaObject = {};
    schemaObject[schemaString] = {
	    type : [String],
      regEx:SimpleSchema.RegEx.Id,
      autoform: {omit: true}
    };
    collection.appendSchema(schemaObject);
	var upperCaseString = type.charAt(0).toUpperCase() + type.slice(1);
  //add
	addMethodToModel(collection, 'add', upperCaseString, function(linkID){
	   addLinkToModel(this, linkID, schemaString);
  });

  addMethodToModel(collection, 'link', upperCaseString, function(linkID){
    addLinkToModel(this, linkID, schemaString);
    var that = this;
    model.collection.find(linkID).forEach(function(linkedModel){
      var linkedSchemaString = 'links.' +  that._objectType;
      addLinkToModel(linkedModel, that._id, linkedSchemaString);
    });
  });

  //get
	addMethodToModel(collection, 'getLinked', upperCaseString, function(){
		return LinkableModel.getCollectionForRegisteredType(type).find({
      _id : {$in : this.links[type]}});
	});
  //remove
  addMethodToModel(collection, 'remove', upperCaseString, function(linkID){
    var query = {};
		query[schemaString] = [linkID];
		this.update({$pullAll : query});
	});
}
<commit_msg>error handling for undefined links<commit_after>

ManyModel = LinkableModel.extend();

LinkableModel.prototype.registerLinkableType = function (model, type) {
    model.prototype._objectType = type;
    LinkableTypes[type] = model.prototype._collection;
};

addLinkSchema = function() {
  var addSchema = function(model) {
    model.appendSchema({
      "links" : {
        type : Object,
        optional : true,
      }
    });
  };

  var calledCollections = [];
  return function(model) {
      if(!_.contains(calledCollections, model.collection._name)) {
        addSchema(model);
        calledCollections.push(model.collection._name);
      } else {
        console.log("Already called");
      }
  }
}();

addMethodToModel = function(model, prefix, type, func) {
	var methodName = prefix + type;
	var methods = {};
	methods[methodName] = func;
	model.methods(methods);
}

addLinkToModel = function(model, linkID, schemaString) {
    var query = {};
    query[schemaString] = linkID;
    model.update({$addToSet : query});
}

configureLinkableType = function(collection, model, type) {
  addLinkSchema(collection);
  var schemaString = "links." + type;
    var schemaObject = {};
    schemaObject[schemaString] = {
	    type : [String],
      regEx:SimpleSchema.RegEx.Id,
      autoform: {omit: true}
    };
    collection.appendSchema(schemaObject);
	var upperCaseString = type.charAt(0).toUpperCase() + type.slice(1);
  //add
	addMethodToModel(collection, 'add', upperCaseString, function(linkID){
	   addLinkToModel(this, linkID, schemaString);
  });

  addMethodToModel(collection, 'link', upperCaseString, function(linkID){
    addLinkToModel(this, linkID, schemaString);
    var that = this;
    model.collection.find(linkID).forEach(function(linkedModel){
      var linkedSchemaString = 'links.' +  that._objectType;
      addLinkToModel(linkedModel, that._id, linkedSchemaString);
    });
  });

  //get
	addMethodToModel(collection, 'getLinked', upperCaseString, function(){
    if (typeof this.links != 'undefined') {
  		return LinkableModel.getCollectionForRegisteredType(type).find({
        _id : {$in : this.links[type]}});
    }else {
      throw new Meteor.Error("no-links",
      "There is no links for this model");
    }
	});
  //remove
  addMethodToModel(collection, 'remove', upperCaseString, function(linkID){
    var query = {};
		query[schemaString] = [linkID];
		this.update({$pullAll : query});
	});
}
<|endoftext|>


<commit_before><commit_msg>Detach Chartist properly on unmounting<commit_after><|endoftext|>


<commit_before>var fs = require('fs')
var nba = require('nba')
var d3 = require('d3')
var queue = require('queue-async')
var glob = require('glob')
var request = require('request')
var _ = require('lodash')
var queue = require('queue-async')

var periodToMin = [48,36,24,12,0,-5,-10,-15,-20]

var games = glob.sync(__dirname + '/play-by-play/*.json').map(function(fileStr,i){
  var scores = JSON.parse(fs.readFileSync(fileStr, 'utf-8')).playByPlay
      .filter(d => d.score)
      .map(d => ({
              h:   +d.score.split('-')[0],
              v:   +d.score.split('-')[1],
              min: periodToMin[d.period]
                    + +d.pctimestring.split(':')[0]
                    + +d.pctimestring.split(':')[1]/60
            }))
  scores.splice(0, 0, {min: 48, h: 0, v: 0})

  var minutes = []
  var curMin = 49
  scores.forEach(function(d){
    while (Math.floor(d.min) < curMin){
      curMin--
      minutes.push({min: curMin, h: d.h, v: d.v})
    }
  })

  var box = JSON.parse(fs.readFileSync(fileStr.replace('play-by-play', 'box'), 'utf-8'))

  return {
    minutes: minutes,
    home: box.sqlTeamsMisc[0].teamAbbreviation,
    away: box.sqlTeamsMisc[1].teamAbbreviation,
  }
})

fs.writeFile(__dirname + '/' + 'game-scores' + '.json', JSON.stringify(games), function(){})
<commit_msg>saves data<commit_after>var fs = require('fs')
var nba = require('nba')
var d3 = require('d3')
var queue = require('queue-async')
var glob = require('glob')
var request = require('request')
var _ = require('lodash')
var queue = require('queue-async')

var periodToMin = [48,36,24,12,0,-5,-10,-15,-20]

var games = glob.sync(__dirname + '/play-by-play/*.json').map(function(fileStr,i){
  var scores = JSON.parse(fs.readFileSync(fileStr, 'utf-8')).playByPlay
      .filter(d => d.score)
      .map(d => ({
              h:   +d.score.split('-')[0],
              v:   +d.score.split('-')[1],
              min: periodToMin[d.period]
                    + +d.pctimestring.split(':')[0]
                    + +d.pctimestring.split(':')[1]/60
            }))
  scores.splice(0, 0, {min: 48, h: 0, v: 0})

  var minutes = []
  var curMin = 49
  scores.forEach(function(d){
    while (Math.floor(d.min) < curMin){
      curMin--
      minutes.push({min: curMin, h: d.h, v: d.v})
    }
  })

  var box = JSON.parse(fs.readFileSync(fileStr.replace('play-by-play', 'box'), 'utf-8'))

  return {
    minutes: minutes,
    home: box.sqlTeamsMisc[0].teamAbbreviation,
    away: box.sqlTeamsMisc[1].teamAbbreviation,
    date: box.sqlTeamsMisc[0].gameDateEst
  }
})

fs.writeFile(__dirname + '/' + 'game-scores' + '.json', JSON.stringify(games), function(){})
<|endoftext|>