<commit_before>/* See license.txt for terms of usage */

"use strict";

const self = require("sdk/self");

// Add-on SDK
const { Cu, Ci } = require("chrome");
const { Trace, TraceError } = require("firebug.sdk/lib/core/trace.js").get(module.id);
const { EventTarget } = require("sdk/event/target");
const { Class } = require("sdk/core/heritage");
const { loadSheet, removeSheet } = require("sdk/stylesheet/utils");

// Firebug SDK
const { Locale } = require("firebug.sdk/lib/core/locale.js");
const { devtools, safeRequire } = require("firebug.sdk/lib/core/devtools.js");
const { PanelOverlay } = require("firebug.sdk/lib/panel-overlay.js");
const { Win } = require("firebug.sdk/lib/core/window.js");

// Module paths changed:
//   https://bugzilla.mozilla.org/show_bug.cgi?id=912121
// Renaming (SelectorSearch -> InspectorSearch)
//   https://bugzilla.mozilla.org/show_bug.cgi?id=835896
const { SelectorSearch, InspectorSearch } = safeRequire(devtools,
  "devtools/client/inspector/inspector-search",
  "devtools/client/inspector/selector-search",
  "devtools/inspector/selector-search");

// Firebug.next
const { Theme } = require("../chrome/theme.js");
const { ToggleSideBarButton } = require("../chrome/toggle-sidebar-button.js");
const { RuleViewOverlay } = require("./rule-view-overlay.js");
const { ComputedViewOverlay } = require("./computed-view-overlay.js");
const { FontInspectorOverlay } = require("./font-inspector-overlay.js");
const { LayoutViewOverlay } = require("./layout-view-overlay.js");
const { AnimationInspectorOverlay } = require("./animation-inspector-overlay.js");

// Platform
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});

/**
 * @overlay This object is responsible for the Inspector panel
 * customization.
 *
 * It should append DOM side panel displaying properties of the
 * selected node (if Firebug theme is activated). Blocked by:
 * New API: WalkerFront.getObjectActorFromNodeActor()
 * https://bugzilla.mozilla.org/show_bug.cgi?id=1035742
 */
const InspectorOverlay = Class(
/** @lends InspectorOverlay */
{
  extends: PanelOverlay,

  overlayId: "inspector",
  searchable: true,

  // Initialization

  onBuild: function(options) {
    PanelOverlay.prototype.onBuild.apply(this, arguments);

    Trace.sysout("inspectorOverlay.onBuild;", options.panel);

    this.originalsetupSearchBox = this.panel.setupSearchBox;
  },

  // Side panels

  getSideOverlays: function() {
    return [
      RuleViewOverlay,
      ComputedViewOverlay,
      FontInspectorOverlay,
      LayoutViewOverlay,
      AnimationInspectorOverlay
    ];
  },

  // Events

  onApplyTheme: function(iframeWin, oldTheme) {
    PanelOverlay.prototype.onApplyTheme.apply(this, arguments);

    Trace.sysout("inspectorOverlay.onApplyTheme; " + iframeWin.inspector,
      iframeWin);

    // xxxHonza: for now we don't need default theme, but
    // this is rather a hack FIX ME.
    let doc = iframeWin.document;
    let classList = doc.documentElement.classList;
    classList.remove("theme-light");

    loadSheet(iframeWin, "chrome://firebug/skin/inspector.css", "author");
    loadSheet(iframeWin, "chrome://firebug-os/skin/inspector.css", "author");

    Theme.customizeSideBarSplitter(iframeWin, true);

    // Create side bar toggle button.
    this.toggleSideBar = new ToggleSideBarButton({
      panel: this,
      toolbar: doc.getElementById("inspector-toolbar"),
    });
  },

  onUnapplyTheme: function(iframeWin, newTheme) {
    PanelOverlay.prototype.onUnapplyTheme.apply(this, arguments);

    Trace.sysout("InspectorOverlay.onUnapplyTheme;", iframeWin);

    removeSheet(iframeWin, "chrome://firebug/skin/inspector.css", "author");
    removeSheet(iframeWin, "chrome://firebug-os/skin/inspector.css", "author");

    // Remove splitter customization
    Theme.customizeSideBarSplitter(iframeWin, false);

    this.toggleSideBar.destroy();

    this.sidebarOverlay.removeSidePanels();
  },

  // Search

  updateSearchBox: function(apply) {
    return;
    Win.loaded(this.toolbox.doc.defaultView).then(() => {
      if (!this.panel) {
        return;
      }

      let doc = this.getPanelDocument();
      let searchInput = doc.querySelector("#inspector-searchbox");

      if (apply) {
        let overlay = this.chrome.getOverlay(this.toolbox,
          "FirebugToolboxOverlay");

        overlay.searchBox.setValue(searchInput.value);

        this.panel.setupSearchBox = this.setupSearchBox.bind(
          this.panel, overlay.searchBox);
      } else {
        this.panel.setupSearchBox = this.originalsetupSearchBox;
      }

      this.panel.setupSearchBox();
    });
  },

  onSearch: function(value) {
    // Do nothing, let the SelectorSearch do the job for us
  },

  /**
   * xxxHonza: monkey patch for the {@InspectorPanel} that connects
   * the panel to the shared search box UI.
   */
  setupSearchBox: function(searchBox) {
    // Initiate the selectors search object.
    if (this.searchSuggestions) {
      this.searchSuggestions.destroy();
      this.searchSuggestions = null;
    }

    // searchSuggestions renamed to search in Firefox 45 (bug 835896)
    if (this.search) {
      this.search.destroy();
      this.search = null;
    }

    this.searchBox = searchBox.getInputBox();
    if (!this.searchBox) {
      Cu.reportError("Firebug.next ERROR: No search box!");
      return;
    }

    if (SelectorSearch) {
      this.searchSuggestions = new SelectorSearch(this, this.searchBox);
    } else {
      this.search = new InspectorSearch(this, this.searchBox);
    }
  }
});

// Exports from this module
exports.InspectorOverlay = InspectorOverlay;
<commit_msg>#438 Also Support Nightly<commit_after>/* See license.txt for terms of usage */

"use strict";

const self = require("sdk/self");

// Add-on SDK
const { Cu, Ci } = require("chrome");
const { Trace, TraceError } = require("firebug.sdk/lib/core/trace.js").get(module.id);
const { EventTarget } = require("sdk/event/target");
const { Class } = require("sdk/core/heritage");
const { loadSheet, removeSheet } = require("sdk/stylesheet/utils");

// Firebug SDK
const { Locale } = require("firebug.sdk/lib/core/locale.js");
const { devtools, safeRequire } = require("firebug.sdk/lib/core/devtools.js");
const { PanelOverlay } = require("firebug.sdk/lib/panel-overlay.js");
const { Win } = require("firebug.sdk/lib/core/window.js");

// Module paths changed:
//   https://bugzilla.mozilla.org/show_bug.cgi?id=912121
// Renaming (SelectorSearch -> InspectorSearch)
//   https://bugzilla.mozilla.org/show_bug.cgi?id=835896
const { SelectorSearch, InspectorSearch } = safeRequire(devtools,
  "devtools/client/inspector/inspector-search",
  "devtools/client/inspector/selector-search",
  "devtools/inspector/selector-search");

// Firebug.next
const { Theme } = require("../chrome/theme.js");
const { ToggleSideBarButton } = require("../chrome/toggle-sidebar-button.js");
const { RuleViewOverlay } = require("./rule-view-overlay.js");
const { ComputedViewOverlay } = require("./computed-view-overlay.js");
const { FontInspectorOverlay } = require("./font-inspector-overlay.js");
const { LayoutViewOverlay } = require("./layout-view-overlay.js");
const { AnimationInspectorOverlay } = require("./animation-inspector-overlay.js");

// Platform
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});

/**
 * @overlay This object is responsible for the Inspector panel
 * customization.
 *
 * It should append DOM side panel displaying properties of the
 * selected node (if Firebug theme is activated). Blocked by:
 * New API: WalkerFront.getObjectActorFromNodeActor()
 * https://bugzilla.mozilla.org/show_bug.cgi?id=1035742
 */
const InspectorOverlay = Class(
/** @lends InspectorOverlay */
{
  extends: PanelOverlay,

  overlayId: "inspector",
  searchable: true,

  // Initialization

  onBuild: function(options) {
    PanelOverlay.prototype.onBuild.apply(this, arguments);

    Trace.sysout("inspectorOverlay.onBuild;", options.panel);

    this.originalsetupSearchBox = this.panel.setupSearchBox;
  },

  // Side panels

  getSideOverlays: function() {
    return [
      RuleViewOverlay,
      ComputedViewOverlay,
      FontInspectorOverlay,
      LayoutViewOverlay,
      AnimationInspectorOverlay
    ];
  },

  // Events

  onApplyTheme: function(iframeWin, oldTheme) {
    PanelOverlay.prototype.onApplyTheme.apply(this, arguments);

    Trace.sysout("inspectorOverlay.onApplyTheme; " + iframeWin.inspector,
      iframeWin);

    // xxxHonza: for now we don't need default theme, but
    // this is rather a hack FIX ME.
    let doc = iframeWin.document;
    let classList = doc.documentElement.classList;
    classList.remove("theme-light");

    loadSheet(iframeWin, "chrome://firebug/skin/inspector.css", "author");
    loadSheet(iframeWin, "chrome://firebug-os/skin/inspector.css", "author");

    Theme.customizeSideBarSplitter(iframeWin, true);

    // Create side bar toggle button.
    this.toggleSideBar = new ToggleSideBarButton({
      panel: this,
      toolbar: doc.getElementById("inspector-toolbar"),
    });
  },

  onUnapplyTheme: function(iframeWin, newTheme) {
    PanelOverlay.prototype.onUnapplyTheme.apply(this, arguments);

    Trace.sysout("InspectorOverlay.onUnapplyTheme;", iframeWin);

    removeSheet(iframeWin, "chrome://firebug/skin/inspector.css", "author");
    removeSheet(iframeWin, "chrome://firebug-os/skin/inspector.css", "author");

    // Remove splitter customization
    Theme.customizeSideBarSplitter(iframeWin, false);

    this.toggleSideBar.destroy();

    this.sidebarOverlay.removeSidePanels();
  },

  // Search

  updateSearchBox: function(apply) {
    Win.loaded(this.toolbox.doc.defaultView).then(() => {
      if (!this.panel) {
        return;
      }

      let doc = this.getPanelDocument();
      let searchInput = doc.querySelector("#inspector-searchbox");

      if (apply) {
        let overlay = this.chrome.getOverlay(this.toolbox,
          "FirebugToolboxOverlay");

        overlay.searchBox.setValue(searchInput.value);

        if (SelectorSearch) {
          this.panel.setupSearchBox = this.setupSelectorSearchBox.bind(
            this.panel, overlay.searchBox);
        } else if (InspectorSearch) {
          this.panel.setupSearchBox = this.setupInspectorSearchBox.bind(
            this.panel, overlay.searchBox);
        }
      } else {
        this.panel.setupSearchBox = this.originalsetupSearchBox;
      }

      this.panel.setupSearchBox();
    });
  },

  onSearch: function(value) {
    // Do nothing, let the SelectorSearch do the job for us
  },

  /**
   * Monkey patch for the {@InspectorPanel} that connects
   * the panel to the shared search box UI.
   *
   * For Firefox < 45
   */
  setupSelectorSearchBox: function(searchBox) {
    // Initiate the selectors search object.
    if (this.searchSuggestions) {
      this.searchSuggestions.destroy();
      this.searchSuggestions = null;
    }

    this.searchBox = searchBox.getInputBox();
    if (!this.searchBox) {
      Cu.reportError("Firebug.next ERROR: No search box!");
      return;
    }

    this.searchSuggestions = new SelectorSearch(this, this.searchBox);
  },

  /**
   * Monkey patch for the {@InspectorPanel} that connects
   * the panel to the shared search box UI.
   *
   * For Firefox >= 45
   */
  setupInspectorSearchBox: function(searchBox) {
    this.searchBox = searchBox.getInputBox();

    // xxxFlorent: This is used to displayed the result index over the number
    // of results (like "1 of 15"). We probably want to take advantage of this
    // feature.
    this.searchResultsLabel =
      this.panelDoc.getElementById("inspector-searchlabel");

    this.search = new InspectorSearch(this, this.searchBox);
    this.search.on("search-cleared", this._updateSearchResultsLabel);
    this.search.on("search-result", this._updateSearchResultsLabel);
  },
});

// Exports from this module
exports.InspectorOverlay = InspectorOverlay;
<|endoftext|>


<commit_before>if(typeof Object.deepClone !== 'function') {
	console.log("[Object.deepClone] is not defined.");
	Object.prototype.deepClone = function() {
		var newObj = (this instanceof Array) ? [] : {};
		for (i in this) {
			if (Object.isFunction(this[i])) continue;		// Skip functions
			if (this[i] && typeof this[i] == "object") {
				newObj[i] = this[i].clone();
			} else {
				newObj[i] = this[i];
			}
		}
		return newObj;
	};
} else {
	console.log("[Object.deepClone] is defined.");
}

var Podcast = Class.create({
	url: undefined,
	key: undefined,				// Used for retrieval from the Mojo.Depot
	imgUrl: undefined,
	imgPath: undefined,
	outOfDate: true,
	initialize: function(feedURL) {
		if(Object.isString(feedURL)) {
			this.url = feedURL;		// Store path to feed URL
			this.key = hex_md5(this.url);	// MD5 Hash of feed URL (unique cookie ID)
		} else {
			this.copyFromObj(feedURL);
		}
		if(this.outOfDate) {
			this.updateFeed();
		}
	},
	copyFromObj: function(sourceObj) {
		try {
			// Try an extend Podcast with the object values from sourceObj
			var clone = sourceObj.deepClone();
			Object.extend(this, clone);
		} catch(error) {
			Mojo.Log.error("[Podcast.copyFromObj] %s", error.message);
		}
	},
	updateFeed: function() {
		try {
			Ajax.getFeed({
				url: this.url,
				success: this.onFeedUpdate.bind(this)
			});
		} catch(error) {
			Mojo.Log.error("[Podcast.updateFeed] %s", error.message);
		}
	},
	onFeedUpdate: function(feed) {
		this.copyFromObj(feed);
		Mojo.Log.info("[Podcast] \"%s\" has updated, %i new item(s).", feed.title, feed.items.length);
	},
	toListItem: function() {
		// Return this podcast as a list item
		var result = new Object();

		result = Object.extend({
			title: feed.title,
			img: feed.img,
			num_new_items: items.length
		}, result);

		return result;
	}
});<commit_msg>added deepClone<commit_after>if(typeof Object.deepClone !== 'function') {
	console.log("[Object.deepClone] is not defined.");
	Object.prototype.deepClone = function() {
		try {
			var newObj = (this instanceof Array) ? [] : {};
			for (i in this) {
				if (Object.isFunction(this[i])) continue;	// Skip functions
				if (this[i] && typeof this[i] == "object") {
					newObj[i] = this[i].clone();
				} else {
					newObj[i] = this[i];
				}
			}
			return newObj;
		} catch(error) {
			console.log("[Object.deepClone] %s", error.message);
			return undefined;
		}
	};
} else {
	console.log("[Object.deepClone] is defined.");
}

var Podcast = Class.create({
	url: undefined,
	key: undefined,				// Used for retrieval from the Mojo.Depot
	imgUrl: undefined,
	imgPath: undefined,
	outOfDate: true,
	initialize: function(feedURL) {
		if(Object.isString(feedURL)) {
			this.url = feedURL;		// Store path to feed URL
			this.key = hex_md5(this.url);	// MD5 Hash of feed URL (unique cookie ID)
		} else {
			this.copyFromObj(feedURL);
		}
		if(this.outOfDate) {
			this.updateFeed();
		}
	},
	copyFromObj: function(sourceObj) {
		try {
			// Try an extend Podcast with the object values from sourceObj
			var clone = sourceObj.deepClone();
			Object.extend(this, clone);
		} catch(error) {
			Mojo.Log.error("[Podcast.copyFromObj] %s", error.message);
		}
	},
	updateFeed: function() {
		try {
			Ajax.getFeed({
				url: this.url,
				success: this.onFeedUpdate.bind(this)
			});
		} catch(error) {
			Mojo.Log.error("[Podcast.updateFeed] %s", error.message);
		}
	},
	onFeedUpdate: function(feed) {
		this.copyFromObj(feed);
		Mojo.Log.info("[Podcast] \"%s\" has updated, %i new item(s).", feed.title, feed.items.length);
	},
	toListItem: function() {
		// Return this podcast as a list item
		var result = new Object();

		result = Object.extend({
			title: feed.title,
			img: feed.img,
			num_new_items: items.length
		}, result);

		return result;
	}
});<|endoftext|>


<commit_before>var os = require('os')
var path = require('path')
var fs = require('fs')
var child = require('child_process')

var plist = require('plist')
var mkdirp = require('mkdirp')
var rimraf = require('rimraf')
var ncp = require('ncp').ncp
var common = require('./common')

module.exports = {
  createApp: function createApp (opts, electronPath, cb) {
    var electronApp = path.join(electronPath, 'Electron.app')
    var tmpDir = path.join(os.tmpdir(), 'electron-packager-mac')

    var newApp = path.join(tmpDir, opts.name + '.app')

    // reset build folders + copy template app
    rimraf(tmpDir, function rmrfd () {
      // ignore errors
      mkdirp(newApp, function mkdirpd () {
        // ignore errors
        // copy .app folder and use as template (this is exactly what Atom editor does)
        ncp(electronApp, newApp, function copied (err) {
          if (err) return cb(err)
          buildMacApp(opts, cb, newApp)
        })
      })
    })
  }
}

function buildMacApp (opts, cb, newApp) {
  var paths = {
    info1: path.join(newApp, 'Contents', 'Info.plist'),
    info2: path.join(newApp, 'Contents', 'Frameworks', 'Electron Helper.app', 'Contents', 'Info.plist'),
    app: path.join(newApp, 'Contents', 'Resources', 'app')
  }

  // update plist files
  var pl1 = plist.parse(fs.readFileSync(paths.info1).toString())
  var pl2 = plist.parse(fs.readFileSync(paths.info2).toString())

  var bundleId = opts['app-bundle-id'] || 'com.electron.' + opts.name.toLowerCase()
  var bundleHelperId = opts['helper-bundle-id'] || 'com.electron.' + opts.name.toLowerCase() + '.helper'
  var appVersion = opts['app-version']

  pl1.CFBundleDisplayName = opts.name
  pl1.CFBundleIdentifier = bundleId
  pl1.CFBundleName = opts.name
  pl2.CFBundleIdentifier = bundleHelperId
  pl2.CFBundleName = opts.name

  if (appVersion) {
    pl1.CFBundleVersion = appVersion
  }

  if (opts.protocols) {
    pl2.CFBundleURLTypes = pl1.CFBundleURLTypes = opts.protocols.map(function (protocol) {
      return {
        CFBundleURLName: protocol.name,
        CFBundleURLSchemes: [].concat(protocol.schemes)
      }
    })
  }

  fs.writeFileSync(paths.info1, plist.build(pl1))
  fs.writeFileSync(paths.info2, plist.build(pl2))

  // copy users app into .app
  ncp(opts.dir, paths.app, {filter: common.userIgnoreFilter(opts), dereference: true}, function copied (err) {
    if (err) return cb(err)

    function moveApp () {
      // finally, move app into cwd
      var outdir = opts.out || process.cwd()
      var finalPath = path.join(outdir, opts.name + '.app')

      mkdirp(outdir, function mkoutdirp () {
        if (err) return cb(err)
        fs.rename(newApp, finalPath, function moved (err) {
          if (err) return cb(err)
          if (opts.asar) {
            var finalPath = path.join(opts.out || process.cwd(), opts.name + '.app', 'Contents', 'Resources')
            common.asarApp(finalPath, function (err) {
              if (err) return cb(err)
              updateMacIcon(function (err) {
                if (err) return cb(err)
                codesign()
              })
            })
          } else {
            updateMacIcon(function (err) {
              if (err) return cb(err)
              codesign()
            })
          }
        })
      })
    }

    function updateMacIcon (cb) {
      var finalPath = path.join(opts.out || process.cwd(), opts.name + '.app')

      if (!opts.icon) {
        return cb(null)
      }

      ncp(opts.icon, path.join(finalPath, 'Contents', 'Resources', 'atom.icns'), function copied (err) {
        cb(err)
      })
    }

    function codesign () {
      var appPath = path.join(opts.out || process.cwd(), opts.name + '.app')

      if (!opts.sign) return cb(null, appPath)

      child.exec('codesign --deep --force --sign ' + opts.sign + ' ' + appPath, function (err, stdout, stderr) {
        cb(err, appPath)
      })
    }

    common.prune(opts, paths.app, cb, moveApp)
  })
}
<commit_msg>Add quotes around signing identity to allow spaces<commit_after>var os = require('os')
var path = require('path')
var fs = require('fs')
var child = require('child_process')

var plist = require('plist')
var mkdirp = require('mkdirp')
var rimraf = require('rimraf')
var ncp = require('ncp').ncp
var common = require('./common')

module.exports = {
  createApp: function createApp (opts, electronPath, cb) {
    var electronApp = path.join(electronPath, 'Electron.app')
    var tmpDir = path.join(os.tmpdir(), 'electron-packager-mac')

    var newApp = path.join(tmpDir, opts.name + '.app')

    // reset build folders + copy template app
    rimraf(tmpDir, function rmrfd () {
      // ignore errors
      mkdirp(newApp, function mkdirpd () {
        // ignore errors
        // copy .app folder and use as template (this is exactly what Atom editor does)
        ncp(electronApp, newApp, function copied (err) {
          if (err) return cb(err)
          buildMacApp(opts, cb, newApp)
        })
      })
    })
  }
}

function buildMacApp (opts, cb, newApp) {
  var paths = {
    info1: path.join(newApp, 'Contents', 'Info.plist'),
    info2: path.join(newApp, 'Contents', 'Frameworks', 'Electron Helper.app', 'Contents', 'Info.plist'),
    app: path.join(newApp, 'Contents', 'Resources', 'app')
  }

  // update plist files
  var pl1 = plist.parse(fs.readFileSync(paths.info1).toString())
  var pl2 = plist.parse(fs.readFileSync(paths.info2).toString())

  var bundleId = opts['app-bundle-id'] || 'com.electron.' + opts.name.toLowerCase()
  var bundleHelperId = opts['helper-bundle-id'] || 'com.electron.' + opts.name.toLowerCase() + '.helper'
  var appVersion = opts['app-version']

  pl1.CFBundleDisplayName = opts.name
  pl1.CFBundleIdentifier = bundleId
  pl1.CFBundleName = opts.name
  pl2.CFBundleIdentifier = bundleHelperId
  pl2.CFBundleName = opts.name

  if (appVersion) {
    pl1.CFBundleVersion = appVersion
  }

  if (opts.protocols) {
    pl2.CFBundleURLTypes = pl1.CFBundleURLTypes = opts.protocols.map(function (protocol) {
      return {
        CFBundleURLName: protocol.name,
        CFBundleURLSchemes: [].concat(protocol.schemes)
      }
    })
  }

  fs.writeFileSync(paths.info1, plist.build(pl1))
  fs.writeFileSync(paths.info2, plist.build(pl2))

  // copy users app into .app
  ncp(opts.dir, paths.app, {filter: common.userIgnoreFilter(opts), dereference: true}, function copied (err) {
    if (err) return cb(err)

    function moveApp () {
      // finally, move app into cwd
      var outdir = opts.out || process.cwd()
      var finalPath = path.join(outdir, opts.name + '.app')

      mkdirp(outdir, function mkoutdirp () {
        if (err) return cb(err)
        fs.rename(newApp, finalPath, function moved (err) {
          if (err) return cb(err)
          if (opts.asar) {
            var finalPath = path.join(opts.out || process.cwd(), opts.name + '.app', 'Contents', 'Resources')
            common.asarApp(finalPath, function (err) {
              if (err) return cb(err)
              updateMacIcon(function (err) {
                if (err) return cb(err)
                codesign()
              })
            })
          } else {
            updateMacIcon(function (err) {
              if (err) return cb(err)
              codesign()
            })
          }
        })
      })
    }

    function updateMacIcon (cb) {
      var finalPath = path.join(opts.out || process.cwd(), opts.name + '.app')

      if (!opts.icon) {
        return cb(null)
      }

      ncp(opts.icon, path.join(finalPath, 'Contents', 'Resources', 'atom.icns'), function copied (err) {
        cb(err)
      })
    }

    function codesign () {
      var appPath = path.join(opts.out || process.cwd(), opts.name + '.app')

      if (!opts.sign) return cb(null, appPath)

      child.exec('codesign --deep --force --sign "' + opts.sign + '" ' + appPath, function (err, stdout, stderr) {
        cb(err, appPath)
      })
    }

    common.prune(opts, paths.app, cb, moveApp)
  })
}
<|endoftext|>


<commit_before>module.exports = Gl3dLayout;

function Gl3dLayout (config) {

    this.config = config;
}

var proto = Gl3dLayout.prototype;

proto.layoutAttributes = {
    scene: {
        type: 'sceneid'
    }
};

proto.sceneLayoutAttributes = {
    bgcolor: {
        type: 'color',
        dflt: '#fff'
    },
    cameraposition: {
        type: 'data_array'
    },
    domain: {
        x: [
            {type: 'number', min: 0, max: 1, dflt: 0},
            {type: 'number', min: 0, max: 1, dflt: 1}
        ],
        y:[
            {type: 'number', min: 0, max: 1, dflt: 0},
            {type: 'number', min: 0, max: 1, dflt: 1}
        ]
    }
};

proto.supplyLayoutDefaults = function (layoutIn, layoutOut, fullData) {

    if (!layoutOut._hasGL3D) return;

    var _this = this;
    var scenes = [];
    var Plotly = this.config.Plotly;
    var $ = this.config.jQuery;

    for (var i = 0; i < fullData.length; ++i) {
        var d = fullData[i];
        if (Plotly.Plots.isGL3D(d.type)) {
            if (scenes.indexOf(d.scene) === -1) {
                scenes.push(d.scene);
            }
        }
    }

    // until they play better together
    delete layoutIn.xaxis;
    delete layoutIn.yaxis;
    delete layoutOut.xaxis;
    delete layoutOut.yaxis;

    scenes.forEach( function (scene) {
        /*
         * Scene numbering proceeds as follows
         * scene
         * scene2
         * scene3
         *
         * and d.scene will be undefined or some number or number string
         */
        var sceneLayoutIn = layoutIn[scene] || {};
        var sceneLayoutOut = {};

        function coerceScene(attr, dflt) {
            return Plotly.Lib.coerce(sceneLayoutIn, sceneLayoutOut, _this.sceneLayoutAttributes, attr, dflt);
        }

        coerceScene('bgcolor');
        coerceScene('cameraposition');
        coerceScene('domain.x[0]');
        coerceScene('domain.x[1]');
        coerceScene('domain.y[0]');
        coerceScene('domain.y[1]');

        Plotly.Gl3dAxes.supplyDefaults(sceneLayoutIn, sceneLayoutOut, {
            font: layoutOut.font,
            scene: scene,
            data: fullData
        });

        layoutOut[scene] = sceneLayoutOut;
    });
};
<commit_msg>rm blank lines commited by mistake<commit_after>module.exports = Gl3dLayout;

function Gl3dLayout (config) {

    this.config = config;
}

var proto = Gl3dLayout.prototype;

proto.layoutAttributes = {
    scene: {
        type: 'sceneid'
    }
};

proto.sceneLayoutAttributes = {
    bgcolor: {
        type: 'color',
        dflt: '#fff'
    },
    cameraposition: {
        type: 'data_array'
    },
    domain: {
        x: [
            {type: 'number', min: 0, max: 1, dflt: 0},
            {type: 'number', min: 0, max: 1, dflt: 1}
        ],
        y:[
            {type: 'number', min: 0, max: 1, dflt: 0},
            {type: 'number', min: 0, max: 1, dflt: 1}
        ]
    }
};

proto.supplyLayoutDefaults = function (layoutIn, layoutOut, fullData) {

    if (!layoutOut._hasGL3D) return;

    var _this = this;
    var scenes = [];
    var Plotly = this.config.Plotly;
    var $ = this.config.jQuery;

    for (var i = 0; i < fullData.length; ++i) {
        var d = fullData[i];
        if (Plotly.Plots.isGL3D(d.type)) {
            if (scenes.indexOf(d.scene) === -1) {
                scenes.push(d.scene);
            }
        }
    }

    // until they play better together
    delete layoutIn.xaxis;
    delete layoutIn.yaxis;
    delete layoutOut.xaxis;
    delete layoutOut.yaxis;

    scenes.forEach( function (scene) {
        /*
         * Scene numbering proceeds as follows
         * scene
         * scene2
         * scene3
         *
         * and d.scene will be undefined or some number or number string
         */
        var sceneLayoutIn = layoutIn[scene] || {};
        var sceneLayoutOut = {};

        function coerceScene(attr, dflt) {
            return Plotly.Lib.coerce(sceneLayoutIn, sceneLayoutOut, _this.sceneLayoutAttributes, attr, dflt);
        }

        coerceScene('bgcolor');
        coerceScene('cameraposition');
        coerceScene('domain.x[0]');
        coerceScene('domain.x[1]');
        coerceScene('domain.y[0]');
        coerceScene('domain.y[1]');

        Plotly.Gl3dAxes.supplyDefaults(sceneLayoutIn, sceneLayoutOut, {
            font: layoutOut.font,
            scene: scene,
            data: fullData
        });

        layoutOut[scene] = sceneLayoutOut;
    });
};
<|endoftext|>


<commit_before>const Constants = require('./Constants');
const chalk = require('chalk');
const moment = require('moment');
const util = require('util');

class Logger {
    static _cleanArgs(args) {
        const texts = [];

        for (const arg of args) {
            if (typeof arg === 'string') {
                texts.push(arg);
                continue;
            }

            texts.push(util.inspect(arg));
        }

        return texts.join(' ');
    }

    static _log(level, ...args) {
        const texts = this._cleanArgs(args);

        const time = chalk.cyan(`[${moment().format('YYYY-MM-DD HH:mm:ss')}]:`);
        const tag = chalk.bold(`[${Constants.LogLevels[level]}]:`);
        const colored = chalk[Constants.LogColors[level]](texts);

        if (level === 4) {
            process.stderr.write(`${time} ${tag} ${colored}\n`);
            return;
        }

        process.stdout.write(`${time} ${tag} ${colored}\n`);
    }

    /**
     * Sends level 0 log ([Log]).
     * @param {...any} args - Things to log.
     * @returns {void}
     */
    static log(...args) {
        this._log(0, ...args);
    }

    /**
     * Sends level 1 log ([Info]).
     * @param {...any} args - Things to log.
     * @returns {void}
     */
    static info(...args) {
        this._log(1, ...args);
    }

    /**
     * Sends level 2 log ([Debug]).
     * @param {...any} args - Things to log.
     * @returns {void}
     */
    static debug(...args) {
        this._log(2, ...args);
    }

    /**
     * Sends level 3 log ([Warn]).
     * @param {...any} args - Things to log.
     * @returns {void}
     */
    static warn(...args) {
        this._log(3, ...args);
    }

    /**
     * Sends level 4 log ([Error]).
     * @param {...any} args - Things to log.
     * @returns {void}
     */
    static error(...args) {
        this._log(4, ...args);
    }
}

module.exports = Logger;
<commit_msg>Delete Logger.js<commit_after><|endoftext|>


<commit_before>import React, {PropTypes} from 'react';

const Song = ({id, isSelected, title, setSong}) => {

    const classNames = isSelected ? 'selected' : '';

    return (

            {title}

    );

    function onClick(event) {
        const target = event.currentTarget;
        const songId = target.id;
        const songIndex = songId.substring(3);
        setSong(songIndex);
    }
};

const AlbumView = ({album, currentSong, setSong}) =>  {

    function renderSongs () {
        if(album.album && album.album.songs){
            return album.album.songs.map((s, i) => {
                const selected = currentSong.name === s.title;
                return <Song id={`so-${i}`}
                              key={s.title}
                              track={s.track}
                              isSelected={selected}
                              title={s.title}
                              setSong={setSong}/>;
            });
        }
    }

    console.log('AlbumView.render()', album);
    return (

{album.name}

            { renderSongs() }

    );
};

AlbumView.propTypes = {
    album: PropTypes.object.isRequired,
    currentSong: PropTypes.object.isRequired,
    setSong: React.PropTypes.func.isRequired
};

export default AlbumView;

<commit_msg>key is now index of song array (unfortunately duplicated song names are not unusual for albums)<commit_after>import React, {PropTypes} from 'react';

const Song = ({id, isSelected, title, setSong}) => {

    const classNames = isSelected ? 'selected' : '';

    return (

            {title}

    );

    function onClick(event) {
        const target = event.currentTarget;
        const songId = target.id;
        const songIndex = songId.substring(3);
        setSong(songIndex);
    }
};

const AlbumView = ({album, currentSong, setSong}) =>  {

    function renderSongs () {
        if(album.album && album.album.songs){
            return album.album.songs.map((s, i) => {
                const selected = currentSong.name === s.title;
                return <Song id={`so-${i}`}
                              key={i}
                              track={s.track}
                              isSelected={selected}
                              title={s.title}
                              setSong={setSong}/>;
            });
        }
    }

    console.log('AlbumView.render()', album);
    return (

{album.name}

            { renderSongs() }

    );
};

AlbumView.propTypes = {
    album: PropTypes.object.isRequired,
    currentSong: PropTypes.object.isRequired,
    setSong: React.PropTypes.func.isRequired
};

export default AlbumView;

<|endoftext|>


<commit_before>import React from 'react'
import Helmet from 'react-helmet'
import Card, { CardContainer } from '../components/card'
import UpdateSection from '../components/update-section'
import Panel, { PanelButton } from '../components/panel'
import { prefixLink } from 'gatsby-helpers'

const updates = [

    Next batch of tickets go on{' '}

      sale
    {' '}
    Tuesday, November 27th, at 15:00 UTC.
  ,

    Watch the{' '}

      mood video
    {' '}
    from the last JSConf Iceland.
  ,
]

export default class Home extends React.Component {
  static propTypes = {
    onToggleMenu: React.PropTypes.func,
  }

  render() {
    return (

        <Helmet title="JSConf Iceland: March 1-2, 2018" />

JSConf Iceland

              March 1st — 2nd 2018

            <UpdateSection updates={updates} />

Feel free to explore

            <CardContainer>
              <Card
                icon="logo-clipped"
                link={prefixLink('/about/')}
                title="About"
              />
              <Card
                icon="schedule"
                link={prefixLink('/schedule/')}
                title="Schedule"
              />
              <Card onlyLarge blank />

              <Card onlyLarge blank />
              <Card
                icon="ticket"
                link={'https://2018.jsconf.is/tickets/'}
                title="Tickets"
              />
              <Card
                icon="tonkvisl"
                link={prefixLink('/venue/')}
                title="Venue"
              />
              <Card
                icon="call"
                link={'http://cfp.jsconf.is/events/jsconf-iceland-2018'}
                title="Call For Proposal"
              />
              <Card
                icon="podium"
                link={prefixLink('/speakers/')}
                title="Speakers"
              />

              <Card onlyLarge blank />

              <Card onlyLarge />
              <Card blank onlyLarge />
              <Card blank onlyLarge />

              <Card onlyLarge pushLeft />
              <Card onlyLarge />
            </CardContainer>

            <Panel>

JSConf will be held in Iceland March 1-2, 2018.

                That's a Thursday and Friday. Perfect for catching up on talks,
                and with friends from the JavaScript community.

                Expect 2 awesome tracks with over 30 speakers, an adventurous
                Saturday and a laid back Sunday brunch.

              <PanelButton href={prefixLink('/about/')}>Learn More</PanelButton>
            </Panel>

            <Card blank />
            <Card />
            <Card />

            <Card blank />
            <Card />

    )
  }
}
<commit_msg>Fix Time<commit_after>import React from 'react'
import Helmet from 'react-helmet'
import Card, { CardContainer } from '../components/card'
import UpdateSection from '../components/update-section'
import Panel, { PanelButton } from '../components/panel'
import { prefixLink } from 'gatsby-helpers'

const updates = [

    Next batch of tickets go on{' '}

      sale
    {' '}
    Tuesday, November 28th, at 15:00 UTC.
  ,

    Watch the{' '}

      mood video
    {' '}
    from the last JSConf Iceland.
  ,
]

export default class Home extends React.Component {
  static propTypes = {
    onToggleMenu: React.PropTypes.func,
  }

  render() {
    return (

        <Helmet title="JSConf Iceland: March 1-2, 2018" />

JSConf Iceland

              March 1st — 2nd 2018

            <UpdateSection updates={updates} />

Feel free to explore

            <CardContainer>
              <Card
                icon="logo-clipped"
                link={prefixLink('/about/')}
                title="About"
              />
              <Card
                icon="schedule"
                link={prefixLink('/schedule/')}
                title="Schedule"
              />
              <Card onlyLarge blank />

              <Card onlyLarge blank />
              <Card
                icon="ticket"
                link={'https://2018.jsconf.is/tickets/'}
                title="Tickets"
              />
              <Card
                icon="tonkvisl"
                link={prefixLink('/venue/')}
                title="Venue"
              />
              <Card
                icon="call"
                link={'http://cfp.jsconf.is/events/jsconf-iceland-2018'}
                title="Call For Proposal"
              />
              <Card
                icon="podium"
                link={prefixLink('/speakers/')}
                title="Speakers"
              />

              <Card onlyLarge blank />

              <Card onlyLarge />
              <Card blank onlyLarge />
              <Card blank onlyLarge />

              <Card onlyLarge pushLeft />
              <Card onlyLarge />
            </CardContainer>

            <Panel>

JSConf will be held in Iceland March 1-2, 2018.

                That's a Thursday and Friday. Perfect for catching up on talks,
                and with friends from the JavaScript community.

                Expect 2 awesome tracks with over 30 speakers, an adventurous
                Saturday and a laid back Sunday brunch.

              <PanelButton href={prefixLink('/about/')}>Learn More</PanelButton>
            </Panel>

            <Card blank />
            <Card />
            <Card />

            <Card blank />
            <Card />

    )
  }
}
<|endoftext|>


<commit_before>'use strict'; // indicate that code is executed in strict mode

/////////////////////////////////////////////////////////////////////////
define([ // sqid application wrapper module

	// Note: The *.config files wrap up their respective modules
	// and do initial setup work, so they are convenient
	// 'all components of that module'-dependencies

	'layout/layout.config',	// the body template, pulls in some application wide dependencies
	'i18n/i18n.config',		// localisation module
	'meta/meta.config',		// pages about pages, like start about and statistics
	'browse/browse.config',	// wikidata classes and properties browser
	'view/view.config',		// wikidata entity viewer
	'query/sparqly.config',	// sparql query generator interface
	'entitySearch/entitySearch.config' // search field

], function() {
/////////////////////////////////////////////////////////////////////////

$("[data-toggle=popover]").popover({html:true}); // <-- is this in use?

angular.module('sqid',[						// the application wrapper module

	'data', 'i18n', 'util', 'layout', 'entitySearch',	// shared modules

	'meta', 'browse', 'view', 'sparqly'			// feature / content modules
]);

return {};}); // module definition end
<commit_msg>removed unused jquery call (#81)<commit_after>'use strict'; // indicate that code is executed in strict mode

/////////////////////////////////////////////////////////////////////////
define([ // sqid application wrapper module

	// Note: The *.config files wrap up their respective modules
	// and do initial setup work, so they are convenient
	// 'all components of that module'-dependencies

	'layout/layout.config',	// the body template, pulls in some application wide dependencies
	'i18n/i18n.config',		// localisation module
	'meta/meta.config',		// pages about pages, like start about and statistics
	'browse/browse.config',	// wikidata classes and properties browser
	'view/view.config',		// wikidata entity viewer
	'query/sparqly.config',	// sparql query generator interface
	'entitySearch/entitySearch.config' // search field

], function() {
/////////////////////////////////////////////////////////////////////////

angular.module('sqid',[						// the application wrapper module

	'data', 'i18n', 'util', 'layout', 'entitySearch',	// shared modules

	'meta', 'browse', 'view', 'sparqly'			// feature / content modules
]);

return {};}); // module definition end
<|endoftext|>


<commit_before>import React, {Component} from 'react';
import PropTypes, {connect, withViewport, withContext, withStyles} from '../PropTypes.js';
// import moment from 'moment';
import ClubLocationInstructions from '../other/ClubLocationInstructions.js';

import {Strike} from '../controls.js';
import {SmallMatchCardHeader} from '../matches/Match/MatchCardHeader.js';

import Row from 'react-bootstrap/lib/Row';
import Col from 'react-bootstrap/lib/Col';
import Typist from 'react-typist';
import * as Sponsor from './Sponsors.js';
import {Eetfestijn} from './Eetfestijn.js';

const WeirdLocaleYearInfo = ({params}) => ( // eslint-disable-line

      WIJZIGING ZAAL

    Opgelet: TTC Erembodegem speelt niet meer op Groeneweg 28

    Hierna de huidige stand van zaken (verdere communicatie volgt):

FASE 2

    {params.location}

    Periode september tot eind december

    {params.trainingDays}

    (Dinsdag 18/9 en 25/9 GEEN training!)

    {params.competitionDays}

FASE 3

    Sportzaal TechniGO, eerste verdiep (Cesar Haeltermanstraat 71)

    Training: maandag en woensdag vanaf 19:30

    Competitie: maandag, woensdag en vrijdag vanaf 19:30

);

@connect(state => {
  return {
    config: state.config,
    user: state.user,
    players: state.players,
    matches: state.matches,
    teams: state.teams
  };
})
@withContext
@withViewport
@withStyles(require('./App.css'))
export default class Intro extends Component {
  static contextTypes = PropTypes.contextTypes;
  static propTypes = {
    config: PropTypes.map.isRequired,
    user: PropTypes.UserModel,
    players: PropTypes.PlayerModelList.isRequired,
    matches: PropTypes.MatchModelList.isRequired,
    teams: PropTypes.TeamModelList.isRequired,
    viewport: PropTypes.viewport,
  };

  render() {
    var inClub = {
      players: this.props.players.size,
      teamsSporta: this.props.teams.filter(t => t.competition === 'Sporta').size,
      teamsVttl: this.props.teams.filter(t => t.competition === 'Vttl').size,
    };

    const big = this.props.viewport.width > 800;
    var topSponsors;
    if (big) {
      topSponsors = (
        <Row style={{marginTop: 10}}>

            <Sponsor.BakkerijVanLierde big={big} />
            <Sponsor.SlagerijGuy big={big} />

        </Row>
      );
    }

    // const thnxEetfestijn = (
    //

    //

    //     Zondag 4 februari 2018
    //

    //
    //       Sportcentrum Schotte
    //
    //

    //     Kapellekensbaan 8
    //

    //     9320 Aalst

    //

    //     Download brochure
    //

    // );

    return (

        {topSponsors}
        <Row style={{marginTop: big ? 25 : undefined}}>
          <Col sm={6} style={{verticalAlign: 'top'}}>

{this.context.t('intro.title')}

            <ClubLocationInstructions />

            {this.context.t('intro.text', inClub)}
            <WeirdLocaleYearInfo params={this.props.config.get('params')} />
          </Col>
          <Col sm={6}>
            {!this.props.config.get('initialLoadCompleted') ? (
              <Loading t={this.context.t} bigScreen={this.props.viewport.width > 768} />
            ) : <TodaysEvents {...this.props} />}
          </Col>
        </Row>
        {big ? (

            <Row style={{marginTop: 25, marginBottom: 15, marginLeft: -65}}>

                <Sponsor.Symphony big={big} style={{padding: 15}} />

                  <Sponsor.itenium big={big} style={{paddingRight: 20}} />

            </Row>
            <Row style={{marginBottom: 15}}>

                <Sponsor.Nostech big={big} />
                <Sponsor.StoneDesign big={big} style={{marginLeft: 10, height: 110}} />

            </Row>

        ) : (
          <Row style={{margin: 10}}>

            <Col>
              <Sponsor.BakkerijVanLierde big={big} />
            </Col>
            <Col style={{marginTop: 20}}>
              <Sponsor.SlagerijGuy big={big} />
            </Col>
            <Col style={{marginTop: 20}}>
              <Sponsor.itenium big={big} />
            </Col>
            <Col style={{marginTop: 20}}>
              <Sponsor.Symphony big={big} style={{padding: 5}} />
            </Col>
            <Col style={{marginTop: 20}}>
              <Sponsor.Nostech big={big} />
            </Col>
            <Col style={{marginTop: 20}}>
              <Sponsor.StoneDesign big={big} />
            </Col>
          </Row>
        )}

    );
  }
}

// TODO: React warning: setState on unmounted component = Typist (loading schlager is gone too fast now...)
// https://github.com/jstejada/react-typist/issues/6#issuecomment-250910698
class RestartingTypist extends Component {
  static propTypes = {
    timeout: PropTypes.number,
    children: PropTypes.node,
  }
  state = {typing: true}
  done = () => {
    this.setState({typing: false}, () => {
      setTimeout(() => this.setState({typing: true}), this.props.timeout || 1200);
    });
  }
  render() {
    const {children, timeout, ...props} = this.props; // eslint-disable-line
    return this.state.typing ? <Typist {...props} onTypingDone={this.done}>{children}</Typist> : {children};
  }
}

const Loading = ({t, bigScreen}) => (

        <RestartingTypist cursor={{show: false}} startDelay={500}>{t('intro.loading')}</RestartingTypist>

);

Loading.propTypes = {
  t: PropTypes.func.isRequired,
  bigScreen: PropTypes.bool.isRequired,
};

class TodaysEvents extends Component {
  static contextTypes = PropTypes.contextTypes;
  static propTypes = {
    config: PropTypes.map.isRequired,
    user: PropTypes.UserModel,
    players: PropTypes.PlayerModelList.isRequired,
    matches: PropTypes.MatchModelList.isRequired,
    teams: PropTypes.TeamModelList.isRequired,
  };

  render() {
    // const t = this.context.t;
    // const today = moment();

    return (

        <Eetfestijn />

    );

    // const matchesToday = this.props.matches.filter(cal => cal.date.isSame(today, 'day'));
    // if (matchesToday.size) {
    //   return (
    //

    //
    //       {this._renderMatches(matchesToday)}
    //

    //   );
    // }

    // const lastPlayedMatches = this.props.matches
    //   .filter(cal => cal.date.isBefore(today, 'day'))
    //   .sort((a, b) => b.date - a.date)
    //   .take(2);

    // return (
    //

    //     {trainingEvent}
    //     {lastPlayedMatches.size ? (
    //

    //
    //         {this._renderMatches(lastPlayedMatches)}
    //

    //     ) : null}
    //

    // );
  }

  _renderMatches(matches) {
    return (

        {matches.map(match => (

            <SmallMatchCardHeader match2={match} user={this.props.user} isOpen={false} config={this.props.config} noScoreEdit />

        ))}

    );
  }
}
<commit_msg>eetfestijn next year<commit_after>import React, {Component} from 'react';
import PropTypes, {connect, withViewport, withContext, withStyles} from '../PropTypes.js';
import moment from 'moment';
import ClubLocationInstructions from '../other/ClubLocationInstructions.js';

import {Strike} from '../controls.js';
import {SmallMatchCardHeader} from '../matches/Match/MatchCardHeader.js';

import Row from 'react-bootstrap/lib/Row';
import Col from 'react-bootstrap/lib/Col';
import Typist from 'react-typist';
import * as Sponsor from './Sponsors.js';
//import {Eetfestijn} from './Eetfestijn.js';

const WeirdLocaleYearInfo = ({params}) => ( // eslint-disable-line

      WIJZIGING ZAAL

    Opgelet: TTC Erembodegem speelt niet meer op Groeneweg 28

    Hierna de huidige stand van zaken (verdere communicatie volgt):

FASE 2

    {params.location}

    Periode september tot eind december

    {params.trainingDays}

    (Dinsdag 18/9 en 25/9 GEEN training!)

    {params.competitionDays}

FASE 3

    Sportzaal TechniGO, eerste verdiep (Cesar Haeltermanstraat 71)

    Training: maandag en woensdag vanaf 19:30

    Competitie: maandag, woensdag en vrijdag vanaf 19:30

);

@connect(state => {
  return {
    config: state.config,
    user: state.user,
    players: state.players,
    matches: state.matches,
    teams: state.teams
  };
})
@withContext
@withViewport
@withStyles(require('./App.css'))
export default class Intro extends Component {
  static contextTypes = PropTypes.contextTypes;
  static propTypes = {
    config: PropTypes.map.isRequired,
    user: PropTypes.UserModel,
    players: PropTypes.PlayerModelList.isRequired,
    matches: PropTypes.MatchModelList.isRequired,
    teams: PropTypes.TeamModelList.isRequired,
    viewport: PropTypes.viewport,
  };

  render() {
    var inClub = {
      players: this.props.players.size,
      teamsSporta: this.props.teams.filter(t => t.competition === 'Sporta').size,
      teamsVttl: this.props.teams.filter(t => t.competition === 'Vttl').size,
    };

    const big = this.props.viewport.width > 800;
    var topSponsors;
    if (big) {
      topSponsors = (
        <Row style={{marginTop: 10}}>

            <Sponsor.BakkerijVanLierde big={big} />
            <Sponsor.SlagerijGuy big={big} />

        </Row>
      );
    }

    return (

        {topSponsors}
        <Row style={{marginTop: big ? 25 : undefined}}>
          <Col sm={6} style={{verticalAlign: 'top'}}>

{this.context.t('intro.title')}

            <ClubLocationInstructions />

            {this.context.t('intro.text', inClub)}
            <WeirdLocaleYearInfo params={this.props.config.get('params')} />
          </Col>
          <Col sm={6}>
            {!this.props.config.get('initialLoadCompleted') ? (
              <Loading t={this.context.t} bigScreen={this.props.viewport.width > 768} />
            ) : (

                <TodaysEvents {...this.props} />

            )}
          </Col>
        </Row>
        {big ? (

            <Row style={{marginTop: 25, marginBottom: 15, marginLeft: -65}}>

                <Sponsor.Symphony big={big} style={{padding: 15}} />

                  <Sponsor.itenium big={big} style={{paddingRight: 20}} />

            </Row>
            <Row style={{marginBottom: 15}}>

                <Sponsor.Nostech big={big} />
                <Sponsor.StoneDesign big={big} style={{marginLeft: 10, height: 110}} />

            </Row>

        ) : (
          <Row style={{margin: 10}}>

            <Col>
              <Sponsor.BakkerijVanLierde big={big} />
            </Col>
            <Col style={{marginTop: 20}}>
              <Sponsor.SlagerijGuy big={big} />
            </Col>
            <Col style={{marginTop: 20}}>
              <Sponsor.itenium big={big} />
            </Col>
            <Col style={{marginTop: 20}}>
              <Sponsor.Symphony big={big} style={{padding: 5}} />
            </Col>
            <Col style={{marginTop: 20}}>
              <Sponsor.Nostech big={big} />
            </Col>
            <Col style={{marginTop: 20}}>
              <Sponsor.StoneDesign big={big} />
            </Col>
          </Row>
        )}

    );
  }
}

// TODO: React warning: setState on unmounted component = Typist (loading schlager is gone too fast now...)
// https://github.com/jstejada/react-typist/issues/6#issuecomment-250910698
class RestartingTypist extends Component {
  static propTypes = {
    timeout: PropTypes.number,
    children: PropTypes.node,
  }
  state = {typing: true}
  done = () => {
    this.setState({typing: false}, () => {
      setTimeout(() => this.setState({typing: true}), this.props.timeout || 1200);
    });
  }
  render() {
    const {children, timeout, ...props} = this.props; // eslint-disable-line
    return this.state.typing ? <Typist {...props} onTypingDone={this.done}>{children}</Typist> : {children};
  }
}

const Loading = ({t, bigScreen}) => (

        <RestartingTypist cursor={{show: false}} startDelay={500}>{t('intro.loading')}</RestartingTypist>

);

Loading.propTypes = {
  t: PropTypes.func.isRequired,
  bigScreen: PropTypes.bool.isRequired,
};

class TodaysEvents extends Component {
  static contextTypes = PropTypes.contextTypes;
  static propTypes = {
    config: PropTypes.map.isRequired,
    user: PropTypes.UserModel,
    players: PropTypes.PlayerModelList.isRequired,
    matches: PropTypes.MatchModelList.isRequired,
    teams: PropTypes.TeamModelList.isRequired,
  };

  render() {
    const t = this.context.t;
    const today = moment();

    const matchesToday = this.props.matches.filter(cal => cal.date.isSame(today, 'day'));
    if (matchesToday.size) {
      return (

          {this._renderMatches(matchesToday)}

      );
    }

    const lastPlayedMatches = this.props.matches
      .filter(cal => cal.date.isBefore(today, 'day'))
      .sort((a, b) => b.date - a.date)
      .take(2);

    return (

        {lastPlayedMatches.size ? (

            {this._renderMatches(lastPlayedMatches)}

        ) : null}

    );
  }

  _renderMatches(matches) {
    return (

        {matches.map(match => (

            <SmallMatchCardHeader match2={match} user={this.props.user} isOpen={false} config={this.props.config} noScoreEdit />

        ))}

    );
  }
}
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { browserHistory } from 'react-router';
import { Card, BaseComponent, Dataset, DataHandler, DataHandlers, Registry, EventDispatcher } from '../ReactDashboard';
import { isArray, isEqual, pick} from 'lodash';
import { appliedFiltersToQueryString, makeKey } from '../utils/utils';
import Accordion from 'react-responsive-accordion';

export default class Dashboard extends BaseComponent {

  constructor(props) {
    super(props);
  }

  componentWillMount() {
    super.componentWillMount();

    // if doFilterRouting flag is present, get url filters
    if (this.props.doFilterRouting !== false) {
      let appliedFilters = this.getUrlFilters();
      this.state.appliedFilters = appliedFilters;
    }

    // initialize data
    this.state.isFetching = true;
    this.getDashboardData();
  }

  shouldComponentUpdate(nextProps, nextState) {
    if (nextState.isFetching) return false; // wait for all data before updating.
    return true;
  }

  componentDidUpdate(nextProps, nextState) {
    if (!isEqual(nextState.appliedFilters, this.state.appliedFilters)) {
      this.setState({isFetching: true});
      this.getDashboardData(); // getDashboard should reset isFetching to false
    }
  }

  /**
   * Apply datahandlers in sequence, passing data returned to subsequent handler
   *    makes global leve data and @@TODO event object available to ahndler
   **/
  _applyDataHandlers(datahandlers, componentData=[]) {
    let _handlers = datahandlers;
    let _appliedFilters = this.state.appliedFilters || {};
    let _data = DataHandler.handle.call(this, _handlers, componentData, this.state.data, {e:'foo'}, _appliedFilters);
    return _data;
  }

  getUrlFilters() {
    let q = this.props.location.query;
    let appliedFilters = {};

    Object.keys(q).forEach(key => {
      let payload = {}; // mock url filter as regular Dashboard filter
      payload.field = key;
      payload.value = q[key].split(',');
      payload.vals = payload.value.map(v => {
        if (!isNaN(v)) parseInt(v);
        return v;
      });

      appliedFilters = this.getUpdatedAppliedFilters(payload, appliedFilters);
    });

    return appliedFilters;
  }

  /**
   * Override this method in your application and insert data fetching stuff here!
   *    API integrations
   *    Flat file Loading
   *    Whatever you want
   **/
  getDashboardData() {
    console.log('Warning. getDashboardData should be defined in your application which extends this dashboard component. getDashboardData should return an object with dataKeys. See @@LINK');
  }

  /**
   * Maps data to components based on component settings
   **/
  getChildData(component) {
    let data = [];

    if (component.dataHandlers) {
      data = this._applyDataHandlers(component.dataHandlers, component.data);
    } else if (component.data) {
      if (component.data.length > 0) {
        data = component.data;
      }
    }

    return data;
  }

  /**
   * Figure out which appliedFilters apply to which dataKeys
   **/
  getFilters(key, appliedFilters) {
    let filters = [];
    //let appliedFilters = Object.assign({}, this.state.appliedFilters);
    return Object.keys(appliedFilters).map(k => {
      let next = appliedFilters[k];
      if (next && next.willFilter && next.willFilter.length > 0 ) {
        let will = next.willFilter.indexOf(key);
        if (will >= 0) return appliedFilters[k];
      }
    });
  }

  getFilterByField(field) {
    let filter;

    this.props.regions.forEach(region => {
      if (region.children) {
        return region.children.forEach(child => {
          if (child.field === field) filter = child;
        })
      } else if (region.elements) { // drill down through multi-component sections
        Object.keys(region.elements).forEach(k => {
          region.elements[k].forEach(el => {
            if (el.field === field) filter = el;
          });
        })
      }
    });

    return filter;
  }

  /**
   * Handle actions here.
   *    Update appliedFilters on state triggers re-render
   *    App parses appliedFilters and updates dash accordingly
   **/
  onAction(payload) {
    switch(payload.actionType) {
      case 'AUTOCOMPLETE_CHANGE':
        let appliedFilters = Object.assign({}, this.state.appliedFilters);
        let updatedAppliedFilters = this.getUpdatedAppliedFilters(payload, appliedFilters);
        let q = appliedFiltersToQueryString(updatedAppliedFilters);
        let basePath = this.props.basePath || '';

        if (this.props.doFilterRouting !== false) {
          browserHistory.push(basePath + '?' + q);
        }

        this.setState({appliedFilters: updatedAppliedFilters, isFetching: true});
        this.getDashboardData(updatedAppliedFilters);
        break;

      case 'MULTICHECKBOX_CHANGE':
        break;

      default:
        console.warn('Actions should define an actionType. See docs @@LINK');
    }
  }

  getUpdatedAppliedFilters(_payload, appliedFilters) {
    let field = _payload.field;
    let filter = this.getFilterByField(field);
    let payload = Object.assign(_payload, filter);

    // value is a non-empty array of values
    if (isArray(payload.value) && payload.value.length > 0) {
      payload.vals = payload.value.map(row => {
        if (!isNaN(row)) return parseInt(row); // the row is just a numeric value
        if (!isNaN(row.value)) return parseInt(row.value);  // ints are easier
        return row.value;
      });
      appliedFilters[field] = payload;
    } else if (payload.value && payload.value.value) { // payload value is an object with a value attribute
      if (!isNaN(payload.value.value)) payload.value.value =  parseInt(payload.value.value);  // ints are easier
      payload.value = [payload.value]
      appliedFilters[field] = payload;
    } else if (payload.value && typeof payload.value === 'string' || typeof payload.value === 'number') { // payload value is a scalar value
      payload.value = [payload.value];
      appliedFilters[field] = payload;
    } else { // if there is no value, remove this filter from appliedFilters
      delete appliedFilters[field];
    }
    return appliedFilters;
  }

  updateProps(element) {
    let props = (React.isValidElement(element)) ? element.props : element;
    let routeParams = [];
    if (this.props.doFilterRouting) routeParams =  pick(this.props, ['history', 'location', 'params', 'route', 'routeParams', 'routes']);

    props.data = this.getChildData(element) || [];
    props.globalData = Object.assign({}, this.state.data || {});
    props.appliedFilters = Object.assign({}, this.state.appliedFilters || {});
    props.vars = Object.assign({}, this.props.vars || {});
    props.routeParams = routeParams;

    return props;
  }

  getRegion(region) {
    return (

        {region.children.map( (element, key) => {
          // if it isn't a react element, the element is a settings object
          let props = this.updateProps(element);
          element.isFetching = this.state.isFetching;
          let el = (React.isValidElement(element)) ? element : React.createElement(Registry.get(element.type), props);
          return el;
        })}

    )
  }

  getAccordionRegion(region) {
    return (

        <Accordion key={makeKey()}>
        {region.children.map( (element, key) => {
          // if it isn't a react element, the element is a settings object
          let props = this.updateProps(element);
          let el = (React.isValidElement(element)) ? element : React.createElement(Registry.get(element.type), props);

          return (

              {el}

          )
        })}
        </Accordion>

    )
  }

  getRegions() {
    let regions;
    if (this.props.regions) {
      regions = this.props.regions.map( (region, key) => {
        if (region.multi) {
          let multiRegionKey = this.getChildData(region);
          region.key = key;
          region.children = region.elements[multiRegionKey];
        }

        // render accordion region
        if (region.accordion) {
          return this.getAccordionRegion(region)
        } else { // render default region
          return this.getRegion(region)
        }
      })} else {
        regions = this.props.children;
      }

    return regions;
  }

  render() {
    let markup;

    return (

        <link rel="stylesheet" type="text/css" href={this.props.faPath} />

{this.props.title}

        {this.getRegions()}

    );
  }
}
<commit_msg>Check that the title is not null before rendering the markup<commit_after>import React, { Component } from 'react';
import { browserHistory } from 'react-router';
import { Card, BaseComponent, Dataset, DataHandler, DataHandlers, Registry, EventDispatcher } from '../ReactDashboard';
import { isArray, isEqual, pick} from 'lodash';
import { appliedFiltersToQueryString, makeKey } from '../utils/utils';
import Accordion from 'react-responsive-accordion';

export default class Dashboard extends BaseComponent {

  constructor(props) {
    super(props);
  }

  componentWillMount() {
    super.componentWillMount();

    // if doFilterRouting flag is present, get url filters
    if (this.props.doFilterRouting !== false) {
      let appliedFilters = this.getUrlFilters();
      this.state.appliedFilters = appliedFilters;
    }

    // initialize data
    this.state.isFetching = true;
    this.getDashboardData();
  }

  shouldComponentUpdate(nextProps, nextState) {
    if (nextState.isFetching) return false; // wait for all data before updating.
    return true;
  }

  componentDidUpdate(nextProps, nextState) {
    if (!isEqual(nextState.appliedFilters, this.state.appliedFilters)) {
      this.setState({isFetching: true});
      this.getDashboardData(); // getDashboard should reset isFetching to false
    }
  }

  /**
   * Apply datahandlers in sequence, passing data returned to subsequent handler
   *    makes global leve data and @@TODO event object available to ahndler
   **/
  _applyDataHandlers(datahandlers, componentData=[]) {
    let _handlers = datahandlers;
    let _appliedFilters = this.state.appliedFilters || {};
    let _data = DataHandler.handle.call(this, _handlers, componentData, this.state.data, {e:'foo'}, _appliedFilters);
    return _data;
  }

  getUrlFilters() {
    let q = this.props.location.query;
    let appliedFilters = {};

    Object.keys(q).forEach(key => {
      let payload = {}; // mock url filter as regular Dashboard filter
      payload.field = key;
      payload.value = q[key].split(',');
      payload.vals = payload.value.map(v => {
        if (!isNaN(v)) parseInt(v);
        return v;
      });

      appliedFilters = this.getUpdatedAppliedFilters(payload, appliedFilters);
    });

    return appliedFilters;
  }

  /**
   * Override this method in your application and insert data fetching stuff here!
   *    API integrations
   *    Flat file Loading
   *    Whatever you want
   **/
  getDashboardData() {
    console.log('Warning. getDashboardData should be defined in your application which extends this dashboard component. getDashboardData should return an object with dataKeys. See @@LINK');
  }

  /**
   * Maps data to components based on component settings
   **/
  getChildData(component) {
    let data = [];

    if (component.dataHandlers) {
      data = this._applyDataHandlers(component.dataHandlers, component.data);
    } else if (component.data) {
      if (component.data.length > 0) {
        data = component.data;
      }
    }

    return data;
  }

  /**
   * Figure out which appliedFilters apply to which dataKeys
   **/
  getFilters(key, appliedFilters) {
    let filters = [];
    //let appliedFilters = Object.assign({}, this.state.appliedFilters);
    return Object.keys(appliedFilters).map(k => {
      let next = appliedFilters[k];
      if (next && next.willFilter && next.willFilter.length > 0 ) {
        let will = next.willFilter.indexOf(key);
        if (will >= 0) return appliedFilters[k];
      }
    });
  }

  getFilterByField(field) {
    let filter;

    this.props.regions.forEach(region => {
      if (region.children) {
        return region.children.forEach(child => {
          if (child.field === field) filter = child;
        })
      } else if (region.elements) { // drill down through multi-component sections
        Object.keys(region.elements).forEach(k => {
          region.elements[k].forEach(el => {
            if (el.field === field) filter = el;
          });
        })
      }
    });

    return filter;
  }

  /**
   * Handle actions here.
   *    Update appliedFilters on state triggers re-render
   *    App parses appliedFilters and updates dash accordingly
   **/
  onAction(payload) {
    switch(payload.actionType) {
      case 'AUTOCOMPLETE_CHANGE':
        let appliedFilters = Object.assign({}, this.state.appliedFilters);
        let updatedAppliedFilters = this.getUpdatedAppliedFilters(payload, appliedFilters);
        let q = appliedFiltersToQueryString(updatedAppliedFilters);
        let basePath = this.props.basePath || '';

        if (this.props.doFilterRouting !== false) {
          browserHistory.push(basePath + '?' + q);
        }

        this.setState({appliedFilters: updatedAppliedFilters, isFetching: true});
        this.getDashboardData(updatedAppliedFilters);
        break;

      case 'MULTICHECKBOX_CHANGE':
        break;

      default:
        console.warn('Actions should define an actionType. See docs @@LINK');
    }
  }

  getUpdatedAppliedFilters(_payload, appliedFilters) {
    let field = _payload.field;
    let filter = this.getFilterByField(field);
    let payload = Object.assign(_payload, filter);

    // value is a non-empty array of values
    if (isArray(payload.value) && payload.value.length > 0) {
      payload.vals = payload.value.map(row => {
        if (!isNaN(row)) return parseInt(row); // the row is just a numeric value
        if (!isNaN(row.value)) return parseInt(row.value);  // ints are easier
        return row.value;
      });
      appliedFilters[field] = payload;
    } else if (payload.value && payload.value.value) { // payload value is an object with a value attribute
      if (!isNaN(payload.value.value)) payload.value.value =  parseInt(payload.value.value);  // ints are easier
      payload.value = [payload.value]
      appliedFilters[field] = payload;
    } else if (payload.value && typeof payload.value === 'string' || typeof payload.value === 'number') { // payload value is a scalar value
      payload.value = [payload.value];
      appliedFilters[field] = payload;
    } else { // if there is no value, remove this filter from appliedFilters
      delete appliedFilters[field];
    }
    return appliedFilters;
  }

  updateProps(element) {
    let props = (React.isValidElement(element)) ? element.props : element;
    let routeParams = [];
    if (this.props.doFilterRouting) routeParams =  pick(this.props, ['history', 'location', 'params', 'route', 'routeParams', 'routes']);

    props.data = this.getChildData(element) || [];
    props.globalData = Object.assign({}, this.state.data || {});
    props.appliedFilters = Object.assign({}, this.state.appliedFilters || {});
    props.vars = Object.assign({}, this.props.vars || {});
    props.routeParams = routeParams;

    return props;
  }

  getRegion(region) {
    return (

        {region.children.map( (element, key) => {
          // if it isn't a react element, the element is a settings object
          let props = this.updateProps(element);
          element.isFetching = this.state.isFetching;
          let el = (React.isValidElement(element)) ? element : React.createElement(Registry.get(element.type), props);
          return el;
        })}

    )
  }

  getAccordionRegion(region) {
    return (

        <Accordion key={makeKey()}>
        {region.children.map( (element, key) => {
          // if it isn't a react element, the element is a settings object
          let props = this.updateProps(element);
          let el = (React.isValidElement(element)) ? element : React.createElement(Registry.get(element.type), props);

          return (

              {el}

          )
        })}
        </Accordion>

    )
  }

  getRegions() {
    let regions;
    if (this.props.regions) {
      regions = this.props.regions.map( (region, key) => {
        if (region.multi) {
          let multiRegionKey = this.getChildData(region);
          region.key = key;
          region.children = region.elements[multiRegionKey];
        }

        // render accordion region
        if (region.accordion) {
          return this.getAccordionRegion(region)
        } else { // render default region
          return this.getRegion(region)
        }
      })} else {
        regions = this.props.children;
      }

    return regions;
  }

  render() {
    let markup;

    return (

        <link rel="stylesheet" type="text/css" href={this.props.faPath} />
        if (this.props.title) {

{this.props.title}

        }
        {this.getRegions()}

    );
  }
}
<|endoftext|>


<commit_before>// @flow
/**
 * Module dependencies.
 */
const express = require('express');
const compression = require('compression');
const SwaggerExpress = require('swagger-express-mw');
const session = require('express-session');
const bodyParser = require('body-parser');
const logger = require('morgan');
const chalk = require('chalk');
const lusca = require('lusca');
const flash = require('express-flash');
const passport = require('passport');
const expressValidator = require('express-validator');

const http = require('http');
const socketio = require('socket.io');

const expressStatusMonitor = require('express-status-monitor');
const sass = require('node-sass-middleware');
const Raven = require('raven');
const RedisStore = require('connect-redis')(session);
const redis = require('redis');
const _ = require('lodash');

const swaggerTools = require('swagger-tools');
const YAML = require('yamljs');

type OptionsType = {
  publicPath?: string,
  viewsPath?: string,
  session?: {
    resave?: boolean,
    rolling?: boolean,
    saveUninitialized?: boolean,
  },
  swaggerConfig?: {
    appRoot: string,
    yamlPath?: string,
  }, // for optional swagger integration
  findUserById: (id: number) => Object,
  viewEngine?: string,
};

const httpServer = function httpServer(options: OptionsType) {
  const app = express();
  app.set('port', process.env.PORT || 3000);

  // $FlowBug
  const webserver = http.Server(app); // eslint-disable-line
  const io = socketio(webserver);

  if (process.env.SENTRY_DSN) {
    Raven.config(process.env.SENTRY_DSN, {
      autoBreadcrumbs: true,
      environment: process.env.NODE_ENV,
      captureUnhandledRejections: true,
    }).install();
    app.use(Raven.requestHandler());
  }

  app.use(expressStatusMonitor({
    websocket: io,
  }));
  app.use(compression());
  app.set('view engine', options.viewEngine || 'pug');
  app.use(logger('dev'));
  app.use(bodyParser.json());
  app.use(bodyParser.urlencoded({extended: true}));
  app.use(expressValidator());

  if (options.viewPath) {
    app.set('views', options.viewPath);
  }

  if (options.publicPath) {
    app.use(sass({
      src: options.publicPath,
      dest: options.publicPath,
    }));
    app.use(express.static(options.publicPath, {maxAge: 31557600000}));
  }

  app.use(flash());
  app.use(lusca.xframe('SAMEORIGIN'));
  app.use(lusca.xssProtection(true));

  let sessionStore = null;
  if (process.env.REDIS_URL) {
    const redisClient = redis.createClient({url: process.env.REDIS_URL});
    sessionStore = new RedisStore({
      ttl: process.env.TTL_IN_SECONDS || 86400, // one day
      client: redisClient,
      url: process.env.REDIS_URL,
    });
  }

  app.use(session({
    resave: options.session && options.session.hasOwnProperty('resave') ? options.session.resave : true,
    rolling: options.session && options.session.hasOwnProperty('rolling') ? options.session.rolling : true,
    saveUninitialized: options.session && options.session.hasOwnProperty('saveUninitialized') ? options.session.saveUninitialized : true,
    secret: process.env.SESSION_SECRET,
    store: sessionStore,
  }));

  passport.serializeUser((user, done) => {
    if (! (user && user.id)) {
      throw new Error('User not found');
    }
    done(null, user.id);
  });

  passport.deserializeUser((id, done) => {
    return options.findUserById(id)
      .then((user) => {
        if (_.isEmpty(user)) {
          throw new Error('User not found');
        }
        return done(null, user);
      })
      .catch((err) => done(err, false));
  });

  app.use(passport.initialize());
  app.use(passport.session());

  app.use((req, res, next) => {
    res.locals.user = req.user;
    next();
  });
  app.use((req, res, next) => {
    // After successful login, redirect back to the intended page
    if (!req.user &&
        req.path !== '/login' &&
        req.path !== '/signup' &&
        !req.path.match(/^\/auth/) &&
        !req.path.match(/\./) &&
        req.session) {
      req.session.returnTo = req.path;
    } else if (req.user &&
        req.path === '/account' &&
        req.session) {
      req.session.returnTo = req.path;
    }
    next();
  });

  /**
   * OAuth authentication routes. (Sign in)
   */
  app.get('/auth/facebook', passport.authenticate('facebook', {scope: ['email', 'public_profile']}));
  app.get('/auth/facebook/callback', passport.authenticate('facebook', {failureRedirect: '/login'}), (req, res) => {
    res.redirect(req.session.returnTo || '/');
  });
  app.get('/auth/google', passport.authenticate('google', {scope: 'profile email'}));
  app.get('/auth/google/callback', passport.authenticate('google', {failureRedirect: '/login'}), (req, res) => {
    res.redirect(req.session.returnTo || '/');
  });

  if (options.swaggerConfig && options.swaggerConfig.appRoot) {
    // Exposes /swagger (as JSON) and activates all Swagger Routers
    SwaggerExpress.create(options.swaggerConfig, function(err, swaggerExpress) {
      if (err) { throw err; }
      swaggerExpress.register(app);
    });

    // Serve Swagger Docs At /docs
    if (options.swaggerConfig && options.swaggerConfig.yamlPath) {
      const swaggerDoc = YAML.load(options.swaggerConfig.yamlPath);
      swaggerTools.initializeMiddleware(swaggerDoc, function(middleware) {
        app.use(middleware.swaggerUi());
      });
    }
  }

  return {
    app,
    io,
    passport,
    start() {
      webserver.listen(app.get('port'), () => {
        //eslint-disable
        console.log('%s App is running at http://localhost:%d in %s mode', chalk.green('✓'), app.get('port'), app.get('env')); //eslint-disable-line no-console
      });
    },
  };
};

module.exports = {
  httpServer,
};
<commit_msg>Allow Users To Overwrite Swagger Doc Options<commit_after>// @flow
/**
 * Module dependencies.
 */
const express = require('express');
const compression = require('compression');
const SwaggerExpress = require('swagger-express-mw');
const session = require('express-session');
const bodyParser = require('body-parser');
const logger = require('morgan');
const chalk = require('chalk');
const lusca = require('lusca');
const flash = require('express-flash');
const passport = require('passport');
const expressValidator = require('express-validator');

const http = require('http');
const socketio = require('socket.io');

const expressStatusMonitor = require('express-status-monitor');
const sass = require('node-sass-middleware');
const Raven = require('raven');
const RedisStore = require('connect-redis')(session);
const redis = require('redis');
const _ = require('lodash');

const swaggerTools = require('swagger-tools');
const YAML = require('yamljs');

type OptionsType = {
  publicPath?: string,
  viewsPath?: string,
  session?: {
    resave?: boolean,
    rolling?: boolean,
    saveUninitialized?: boolean,
  },
  swaggerConfig?: {
    appRoot: string,
    yamlPath?: string,
    swaggerDocOptions?: Object,
  }, // for optional swagger integration
  findUserById: (id: number) => Object,
  viewEngine?: string,
};

const httpServer = function httpServer(options: OptionsType) {
  const app = express();
  app.set('port', process.env.PORT || 3000);

  // $FlowBug
  const webserver = http.Server(app); // eslint-disable-line
  const io = socketio(webserver);

  if (process.env.SENTRY_DSN) {
    Raven.config(process.env.SENTRY_DSN, {
      autoBreadcrumbs: true,
      environment: process.env.NODE_ENV,
      captureUnhandledRejections: true,
    }).install();
    app.use(Raven.requestHandler());
  }

  app.use(expressStatusMonitor({
    websocket: io,
  }));
  app.use(compression());
  app.set('view engine', options.viewEngine || 'pug');
  app.use(logger('dev'));
  app.use(bodyParser.json());
  app.use(bodyParser.urlencoded({extended: true}));
  app.use(expressValidator());

  if (options.viewPath) {
    app.set('views', options.viewPath);
  }

  if (options.publicPath) {
    app.use(sass({
      src: options.publicPath,
      dest: options.publicPath,
    }));
    app.use(express.static(options.publicPath, {maxAge: 31557600000}));
  }

  app.use(flash());
  app.use(lusca.xframe('SAMEORIGIN'));
  app.use(lusca.xssProtection(true));

  let sessionStore = null;
  if (process.env.REDIS_URL) {
    const redisClient = redis.createClient({url: process.env.REDIS_URL});
    sessionStore = new RedisStore({
      ttl: process.env.TTL_IN_SECONDS || 86400, // one day
      client: redisClient,
      url: process.env.REDIS_URL,
    });
  }

  app.use(session({
    resave: options.session && options.session.hasOwnProperty('resave') ? options.session.resave : true,
    rolling: options.session && options.session.hasOwnProperty('rolling') ? options.session.rolling : true,
    saveUninitialized: options.session && options.session.hasOwnProperty('saveUninitialized') ? options.session.saveUninitialized : true,
    secret: process.env.SESSION_SECRET,
    store: sessionStore,
  }));

  passport.serializeUser((user, done) => {
    if (! (user && user.id)) {
      throw new Error('User not found');
    }
    done(null, user.id);
  });

  passport.deserializeUser((id, done) => {
    return options.findUserById(id)
      .then((user) => {
        if (_.isEmpty(user)) {
          throw new Error('User not found');
        }
        return done(null, user);
      })
      .catch((err) => done(err, false));
  });

  app.use(passport.initialize());
  app.use(passport.session());

  app.use((req, res, next) => {
    res.locals.user = req.user;
    next();
  });
  app.use((req, res, next) => {
    // After successful login, redirect back to the intended page
    if (!req.user &&
        req.path !== '/login' &&
        req.path !== '/signup' &&
        !req.path.match(/^\/auth/) &&
        !req.path.match(/\./) &&
        req.session) {
      req.session.returnTo = req.path;
    } else if (req.user &&
        req.path === '/account' &&
        req.session) {
      req.session.returnTo = req.path;
    }
    next();
  });

  /**
   * OAuth authentication routes. (Sign in)
   */
  app.get('/auth/facebook', passport.authenticate('facebook', {scope: ['email', 'public_profile']}));
  app.get('/auth/facebook/callback', passport.authenticate('facebook', {failureRedirect: '/login'}), (req, res) => {
    res.redirect(req.session.returnTo || '/');
  });
  app.get('/auth/google', passport.authenticate('google', {scope: 'profile email'}));
  app.get('/auth/google/callback', passport.authenticate('google', {failureRedirect: '/login'}), (req, res) => {
    res.redirect(req.session.returnTo || '/');
  });

  if (options.swaggerConfig && options.swaggerConfig.appRoot) {
    // Exposes /swagger (as JSON) and activates all Swagger Routers
    SwaggerExpress.create(options.swaggerConfig, function(err, swaggerExpress) {
      if (err) { throw err; }
      swaggerExpress.register(app);
    });

    // Serve Swagger Docs At /docs
    if (options.swaggerConfig && options.swaggerConfig.yamlPath) {
      const yamlConfig = YAML.load(options.swaggerConfig.yamlPath);
      const swaggerDoc = _.assign({}, yamlConfig, _.get(options, 'swaggerConfig.swaggerDocOptions', {}));
      swaggerTools.initializeMiddleware(swaggerDoc, function(middleware) {
        app.use(middleware.swaggerUi());
      });
    }
  }

  return {
    app,
    io,
    passport,
    start() {
      webserver.listen(app.get('port'), () => {
        //eslint-disable
        console.log('%s App is running at http://localhost:%d in %s mode', chalk.green('✓'), app.get('port'), app.get('env')); //eslint-disable-line no-console
      });
    },
  };
};

module.exports = {
  httpServer,
};
<|endoftext|>


<commit_before>const React = require('react-native')
const {
  NetInfo,
  StyleSheet,
  ListView,
  Text,
  TextInput,
  View
} = React
const Firebase = require('firebase')
const config = require('../../config')
const Item = require('./Item')

const itemsRef = new Firebase(`${ config.FIREBASE_ROOT }/items`)
const connectedRef = new Firebase(`${ config.FIREBASE_ROOT }/.info/connected`)

const Groceries = React.createClass({
  getInitialState: function() {
    return {
      newItem: ''
    }
  },

  componentWillMount: function() {
    this.dataSource = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2})

    this.props.loadOfflineItems()

    itemsRef.on('child_added', (snapshot) => {
      this.props.addItem(snapshot.val())
    })

    itemsRef.on('child_removed', (snapshot) => {
      this.props.removeItem(snapshot.val().id)
    })

    NetInfo.isConnected.fetch().done(isConnected => {
      if (isConnected) {
        this.props.checkConnection()
      } else {
        this.props.goOffline()
      }
    })

    connectedRef.on('value', snap => {
      if (snap.val() === true) {
        this.props.goOnline()
      } else {
        this.props.goOffline()
      }
    })
  },

  renderRow: function(rowData) {
    return (
      <Item name={rowData.title}
            removable={this.props.connected}
            onRemove={() => this._remove(rowData.id)} />
    )
  },

  _add: function() {
    const id = Math.random().toString(36).substring(7)
    const itemRef = itemsRef.child(id)

    itemRef.set({
      id,
      title: this.state.newItem,
      time: new Date().getTime()
    })

    this.setState({newItem: ''})

    setTimeout(() => this.refs.newItem.focus(), 1)
  },

  _remove: function(id) {
    itemsRef.child(id).remove()
  },

  render: function() {
    let items, readonlyMessage
    if (this.props.connected) {
      items = this.props.onlineItems
    } else if (this.props.connectionChecked) {
      items = this.props.offlineItems
      readonlyMessage = <Text style={styles.offline}>Offline</Text>
    } else {
      items = []
      readonlyMessage = <Text style={styles.offline}>Loading...</Text>
    }

    return (
      <View style={styles.container}>
        {readonlyMessage}
        <TextInput placeholder="Something delicious"
                   style={styles.newItem}
                   ref="newItem"
                   editable={this.props.connected}
                   value={this.state.newItem}
                   onChangeText={(newItem) => this.setState({newItem})}
                   onSubmitEditing={() => this._add()} />

        <ListView
          dataSource={this.dataSource.cloneWithRows(items)}
          renderRow={this.renderRow}
        />
      </View>
    )
  }
})

const styles = StyleSheet.create({
  container: {
    flex: 1,
    paddingTop: 40,
    backgroundColor: '#F6F6F6'
  },
  newItem: {
    backgroundColor: '#FFFFFF',
    height: 40,
    borderColor: '#CCCCCC',
    borderWidth: 1,
    marginBottom: 10,
    marginLeft: 20,
    marginRight: 20,
    paddingLeft: 10,
    borderRadius: 5,
    fontSize: 20
  },
  offline: {
    backgroundColor: '#000000',
    color: '#FFFFFF',
    textAlign: 'center',
    marginBottom: 10,
    paddingTop: 5,
    paddingBottom: 5
  }
})

module.exports = Groceries
<commit_msg>Handle lack of NetInfo native module on Android<commit_after>const React = require('react-native')
const {
  StyleSheet,
  ListView,
  Text,
  TextInput,
  View
} = React
const NetInfo = React.NativeModules.NetInfo
const Firebase = require('firebase')
const config = require('../../config')
const Item = require('./Item')

const itemsRef = new Firebase(`${ config.FIREBASE_ROOT }/items`)
const connectedRef = new Firebase(`${ config.FIREBASE_ROOT }/.info/connected`)

const Groceries = React.createClass({
  getInitialState: function() {
    return {
      newItem: ''
    }
  },

  componentWillMount: function() {
    this.dataSource = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2})

    this.props.loadOfflineItems()

    itemsRef.on('child_added', (snapshot) => {
      this.props.addItem(snapshot.val())
    })

    itemsRef.on('child_removed', (snapshot) => {
      this.props.removeItem(snapshot.val().id)
    })

    if (NetInfo) {
      NetInfo.isConnected.fetch().done(isConnected => {
        if (isConnected) {
          this.props.checkConnection()
        } else {
          this.props.goOffline()
        }
      })
    } else {
      this.props.checkConnection()
    }

    connectedRef.on('value', snap => {
      if (snap.val() === true) {
        this.props.goOnline()
      } else {
        this.props.goOffline()
      }
    })
  },

  renderRow: function(rowData) {
    return (
      <Item name={rowData.title}
            removable={this.props.connected}
            onRemove={() => this._remove(rowData.id)} />
    )
  },

  _add: function() {
    const id = Math.random().toString(36).substring(7)
    const itemRef = itemsRef.child(id)

    itemRef.set({
      id,
      title: this.state.newItem,
      time: new Date().getTime()
    })

    this.setState({newItem: ''})

    setTimeout(() => this.refs.newItem.focus(), 1)
  },

  _remove: function(id) {
    itemsRef.child(id).remove()
  },

  render: function() {
    let items, readonlyMessage
    if (this.props.connected) {
      items = this.props.onlineItems
    } else if (this.props.connectionChecked) {
      items = this.props.offlineItems
      readonlyMessage = <Text style={styles.offline}>Offline</Text>
    } else {
      items = []
      readonlyMessage = <Text style={styles.offline}>Loading...</Text>
    }

    return (
      <View style={styles.container}>
        {readonlyMessage}
        <TextInput placeholder="Something delicious"
                   style={styles.newItem}
                   ref="newItem"
                   editable={this.props.connected}
                   value={this.state.newItem}
                   onChangeText={(newItem) => this.setState({newItem})}
                   onSubmitEditing={() => this._add()} />

        <ListView
          dataSource={this.dataSource.cloneWithRows(items)}
          renderRow={this.renderRow}
        />
      </View>
    )
  }
})

const styles = StyleSheet.create({
  container: {
    flex: 1,
    paddingTop: 40,
    backgroundColor: '#F6F6F6'
  },
  newItem: {
    backgroundColor: '#FFFFFF',
    height: 40,
    borderColor: '#CCCCCC',
    borderWidth: 1,
    marginBottom: 10,
    marginLeft: 20,
    marginRight: 20,
    paddingLeft: 10,
    borderRadius: 5,
    fontSize: 20
  },
  offline: {
    backgroundColor: '#000000',
    color: '#FFFFFF',
    textAlign: 'center',
    marginBottom: 10,
    paddingTop: 5,
    paddingBottom: 5
  }
})

module.exports = Groceries
<|endoftext|>


<commit_before>import { ColourContext } from 'context/colour';
import NextLink from 'next/link';
import PropTypes from 'prop-types';
import { forwardRef, useContext, useState } from 'react';

import Strike from '../Strike';

const propTypes = {
  href: PropTypes.string.isRequired,
  text: PropTypes.string.isRequired,
  strike: PropTypes.bool,
  className: PropTypes.string,
};

const defaultTextColour = 'currentColor';

const A = forwardRef(({
  hoverColour, setHoverColour, text, colour, className, underline, href, ...rest
}, ref) => (
  <a
    {...rest}
    ref={ref}
    href={href}
    className={`${underline ? 'underline' : ''} ${className}`}
    style={{ color: hoverColour }}
    onMouseEnter={() => {
      setHoverColour(colour);
    }}
    onMouseLeave={() => {
      setHoverColour(defaultTextColour);
    }}
  >
    {text}
  </a>
));

A.displayName = 'Anchor'

A.propTypes = {
  ...propTypes,
};

const Link = ({
  href, text, strike, className, underline,
}) => {
  const { colour } = useContext(ColourContext);
  const [hoverColour, setHoverColour] = useState(defaultTextColour);
  const sharedProps = {
    className,
    colour,
    hoverColour,
    setHoverColour,
    text,
    underline,
  };
  return (
    <>
      <Strike strike={strike}>
        {href.includes('http' || 'www')
          ? <A {...sharedProps} href={href} rel="noopener noreferrer" target="_blank" />
          : (
            <NextLink href={href} passHref>
              <A {...sharedProps} />
            </NextLink>
          )}
      </Strike>
      {' '}
    </>
  );
};

Link.propTypes = {
  ...propTypes,
};

Link.defaultProps = {
  strike: false,
  className: '',
};

export default Link;
<commit_msg>Fix Link bug<commit_after>import { ColourContext } from 'context/colour';
import NextLink from 'next/link';
import PropTypes from 'prop-types';
import { forwardRef, useContext, useState } from 'react';

import Strike from '../Strike';

const propTypes = {
  href: PropTypes.string.isRequired,
  text: PropTypes.string.isRequired,
  strike: PropTypes.bool,
  className: PropTypes.string,
};

const defaultTextColour = 'currentColor';

const A = forwardRef(({
  hoverColour, setHoverColour, text, colour, className, underline, href, ...rest
}, ref) => (
  <a
    {...rest}
    ref={ref}
    href={href}
    className={`${underline ? 'underline' : ''} ${className}`}
    style={{ color: hoverColour }}
    onMouseEnter={() => {
      setHoverColour(colour);
    }}
    onMouseLeave={() => {
      setHoverColour(defaultTextColour);
    }}
  >
    {text}
  </a>
));

A.displayName = 'Anchor'

A.propTypes = {
  ...propTypes,
};

const Link = ({
  href, text, strike, className, underline,
}) => {
  const { colour } = useContext(ColourContext);
  const [hoverColour, setHoverColour] = useState(defaultTextColour);
  const sharedProps = {
    className,
    colour,
    hoverColour,
    setHoverColour,
    text,
    underline,
  };
  return (
    <>
      <Strike strike={strike}>
        {href.startsWith('http') || href.startsWith('www')
          ? <A {...sharedProps} href={href} rel="noopener noreferrer" target="_blank" />
          : (
            <NextLink href={href} passHref>
              <A {...sharedProps} />
            </NextLink>
          )}
      </Strike>
      {' '}
    </>
  );
};

Link.propTypes = {
  ...propTypes,
};

Link.defaultProps = {
  strike: false,
  className: '',
};

export default Link;
<|endoftext|>


<commit_before>// @flow
import React from 'react'
import { connect } from 'react-redux'
import PageLoginDialog from './PageLoginDialog'
import PageHeader from './PageHeader'
import PageFooter from './PageFooter'
import NotFound from './NotFound'

class Page extends React.Component {
  props: Props
  _isMounted = false

  componentDidMount() {
    this._isMounted = true
    const { onMounted } = this.props
    if (onMounted !== void 0) {
      onMounted()
    }
  }

  render() {
    const { isNotFound, isLoading, children } = this.props
    if (this._isMounted && !isLoading && isNotFound) {
      return <NotFound />
    }
    return (

        <PageLoginDialog />
        <PageHeader />

          {this._isMounted && !isLoading
            ?
              children
            :

Загрузка...

          }

        <PageFooter />

    )
  }
}

// Page.propTypes = {
//   children: PropTypes.any.isRequired,
//   isLoading: PropTypes.bool.isRequired,
//   onMounted: PropTypes.func.isRequired,
//   isNotFound: PropTypes.bool,
// }

type Props = {
  onMounted?: Function,
  isNotFound?: boolean,
  isLoading?: boolean,
  children?: typeof React.Element,
}

const mapStateToProps = (state, props) => ({
  isLoading: state.app.isLoading
})

export { NotFound }
export default connect(mapStateToProps)(Page)
<commit_msg>Рефакторить Page<commit_after>// @flow
import React from 'react'
import { connect } from 'react-redux'
import PageLoginDialog from './PageLoginDialog'
import PageHeader from './PageHeader'
import PageFooter from './PageFooter'
import NotFound from './NotFound'

class Page extends React.Component {
  props: Props
  _isMounted = false

  componentDidMount() {
    this._isMounted = true
    const { onMounted } = this.props
    if (onMounted !== void 0) {
      onMounted()
    }
  }

  render() {
    const { isNotFound, isLoading, children } = this.props
    if (this._isMounted && !isLoading && isNotFound) {
      return <NotFound />
    }
    return (

        <PageLoginDialog />
        <PageHeader />

          {this._isMounted && !isLoading
            ?
              children
            :

Загрузка...

          }

        <PageFooter />

    )
  }
}

// Page.propTypes = {
//   children: PropTypes.any.isRequired,
//   isLoading: PropTypes.bool.isRequired,
//   onMounted: PropTypes.func.isRequired,
//   isNotFound: PropTypes.bool,
// }

type Props = {
  onMounted?: Function,
  isNotFound?: boolean,
  isLoading: boolean,
  children?: typeof React.Element,
}

const mapStateToProps = (state, props) => ({
  isLoading: state.app.isLoading
})

export { NotFound }
export default connect(mapStateToProps)(Page)
<|endoftext|>