<commit_before>import React, { Component } from 'react';
import {
  View,
  ActivityIndicator,
  Dimensions,
  DeviceEventEmitter,
  Animated,
  Easing,
  StatusBar,
  Image,
  Text,
  Platform,
  TouchableHighlight
} from 'react-native';
import MapView from 'react-native-maps';
import GeoPoint from 'geopoint';
import I18n from 'locales';

import ActionBtn from 'components/common/action-button';
import Config from 'react-native-config';
import Theme from 'config/theme';
import tracker from 'helpers/googleAnalytics';
import styles from './styles';

import { SensorManager } from 'NativeModules';
const { RNLocation: Location } = require('NativeModules');

const { width, height } = Dimensions.get('window');

const ASPECT_RATIO = width / height;
const LATITUDE_DELTA = 10;
const LONGITUDE_DELTA = LATITUDE_DELTA * ASPECT_RATIO;

const markerImage = require('assets/marker.png');
const markerCompassRedImage = require('assets/compass_circle_red.png');
const alertGladImage = require('assets/alert-glad.png');
const alertViirsmage = require('assets/alert-viirs.png');
const alertWhiteImage = require('assets/alert-white.png');
const compassImage = require('assets/compass_direction.png');
const backgroundImage = require('assets/map_bg_gradient.png');
const backIconWhite = require('assets/previous_white.png');

function renderLoading() {
  return (
    <View style={[styles.container, styles.loader]}>
      <ActivityIndicator
        color={Theme.colors.color1}
        style={{ height: 80 }}
        size="large"
      />
    </View>
  );
}

function getGoogleMapsCoordinates(coordinates) {
  const cords = [];

  coordinates.forEach((cordinate) => {
    cords.push({
      latitude: cordinate.lat,
      longitude: cordinate.long
    });
  });

  return cords;
}

class Map extends Component {
  constructor(props) {
    super(props);
    const { params } = this.props.navigation.state;
    const intialCoords = params.center
      ? params.center
      : [Config.maps.lng, Config.maps.lat];

    this.afterRenderTimer = null;
    this.eventLocation = null;
    this.eventOrientation = null;
    this.state = {
      renderMap: false,
      lastPosition: null,
      heading: null,
      geoMarkerOpacity: new Animated.Value(0.3),
      region: {
        latitude: intialCoords.lat,
        longitude: intialCoords.lon,
        latitudeDelta: LATITUDE_DELTA,
        longitudeDelta: LONGITUDE_DELTA
      },
      alertSelected: null,
      alerts: params.features && params.features.length > 0 ? params.features.slice(0, 50) : [] // Provisional
    };
  }

  componentDidMount() {
    tracker.trackScreenView('Map');

    if (Platform.OS === 'ios') {
      Location.requestWhenInUseAuthorization();
      StatusBar.setBarStyle('light-content');
    }

    this.renderMap();
    this.geoLocate();
  }

  geoLocate() {
    this.animateGeo();

    navigator.geolocation.getCurrentPosition(
      (location) => {
        this.setState({
          lastPosition: {
            latitude: location.coords.latitude,
            longitude: location.coords.longitude
          }
        });
      },
      (error) => console.log(error),
      { enableHighAccuracy: true, timeout: 30000, maximumAge: 0 }
    );

    Location.startUpdatingLocation();

    this.eventLocation = DeviceEventEmitter.addListener(
      'locationUpdated',
      (location) => {
        const coords = Platform.OS === 'ios' ? location.coords : location;
        this.setState({
          lastPosition: coords
        });
      }
    );

    if (Platform.OS === 'ios') {
      Location.startUpdatingHeading();
      this.eventOrientation = DeviceEventEmitter.addListener(
        'headingUpdated',
        (data) => {
          this.setState({ heading: parseInt(data.heading, 10) });
        }
      );
    } else {
      SensorManager.startOrientation(1000);
      this.eventOrientation = DeviceEventEmitter.addListener(
        'Orientation',
        (data) => {
          this.setState({
            heading: parseInt(data.azimuth, 10)
          });
        }
      );
    }
  }

  animateGeo() {
    Animated.sequence([
      Animated.timing(this.state.geoMarkerOpacity, {
        toValue: 0.4,
        easing: Easing.in(Easing.quad),
        duration: 800
      }),
      Animated.timing(this.state.geoMarkerOpacity, {
        toValue: 0.15,
        easing: Easing.out(Easing.quad),
        duration: 1000
      })
    ]).start(event => {
      if (event.finished) {
        this.animateGeo();
      }
    });
  }

  componentWillUnmount() {
    Location.stopUpdatingLocation();

    clearTimeout(this.afterRenderTimer);

    if (this.eventLocation) {
      this.eventLocation.remove();
    }

    if (this.eventOrientation) {
      this.eventOrientation.remove();
    }

    if (Platform.OS === 'ios') {
      StatusBar.setBarStyle('default');
      Location.stopUpdatingHeading();
    } else {
      SensorManager.stopOrientation();
    }
  }

  onAlertPress(alertSelected) {
    const alerts = [];

    this.state.alerts.forEach((alert) => {
      const newArea = Object.assign({}, alert);
      newArea.selected = alert.id === alertSelected.id;
      alerts.push(newArea);
    });

    this.setState({
      alerts,
      alertSelected
    });
  }

  onLayout = () => {
    if (!this.state.alertSelected) {
      if (this.afterRenderTimer) {
        clearTimeout(this.afterRenderTimer);
      }
      this.afterRenderTimer = setTimeout(() => {
        const { params } = this.props.navigation.state;
        if (params && params.features && params.features.length > 0) {
          this.map.fitToCoordinates(getGoogleMapsCoordinates(params.features), {
            edgePadding: { top: 100, right: 100, bottom: 100, left: 100 },
            animated: true
          });
        }
      }, 1000);
    }
  }

  renderMap() {
    if (!this.state.renderMap) {
      this.setState({
        renderMap: true
      });
    }
  }

  renderFooter() {
    let distanceText = I18n.t('commonText.notAvailable');
    let distance = 999999;
    const { lastPosition } = this.state;

    if (lastPosition) {
      const geoPoint = new GeoPoint(this.state.alertSelected.lat, this.state.alertSelected.long);
      const currentPoint = new GeoPoint(lastPosition.latitude, lastPosition.longitude);
      distance = currentPoint.distanceTo(geoPoint, true).toFixed(4);
      distanceText = `${distance} ${I18n.t('commonText.kmAway')}`; // in Kilometers
    }

    const createReport = () => {
      const form = `New-report-${Math.floor(Math.random() * 1000)}`;
      let latLng = '0,0';
      if (lastPosition) {
        latLng = `${lastPosition.latitude},${lastPosition.longitude}`;
      }
      this.props.createReport(form, latLng);
      this.props.navigate('NewReport', { form });
    };

    const reportBtn = (
      <ActionBtn
        style={styles.footerButton}
        text={I18n.t('report.title')}
        onPress={() => createReport()}
      />
    );
    return (
      <View style={styles.footer}>
        <Image
          style={styles.footerBg}
          source={backgroundImage}
        />
        <Text style={styles.footerTitle}>
          {distanceText}
        </Text>
        {reportBtn}
      </View>
    );
  }

  renderFooterLoading() {
    return (!this.state.lastPosition &&
      <View style={styles.footer}>
        <Image
          style={styles.footerBg}
          source={backgroundImage}
        />
        <View style={styles.signalNotice}>
          <View style={styles.geoLocationContainer}>
            <Image
              style={styles.marker}
              source={markerCompassRedImage}
            />
            <Animated.View
              style={[styles.geoLocation, { opacity: this.state.geoMarkerOpacity }]}
            />
          </View>
          <Text style={styles.signalNoticeText}>{I18n.t('alerts.satelliteSignal')}</Text>
        </View>
      </View>
    );
  }

  render() {
    const { params } = this.props.navigation.state;

    return (
      this.state.renderMap
      ?
        <View style={styles.container}>
          <View
            style={styles.header}
            pointerEvents={'box-none'}
          >
            <Image
              style={styles.headerBg}
              source={backgroundImage}
            />
            <Text style={styles.headerTitle}>
              {params.title}
            </Text>
            {this.state.alertSelected &&
              <Text style={styles.headerSubtitle}>
                {this.state.alertSelected.lat}, {this.state.alertSelected.long}
              </Text>
            }
            <TouchableHighlight
              style={styles.headerBtn}
              onPress={() => this.props.navigation.goBack()}
              underlayColor="transparent"
              activeOpacity={0.8}
            >
              <Image style={Theme.icon} source={backIconWhite} />
            </TouchableHighlight>
          </View>
          <MapView
            ref={(ref) => { this.map = ref; }}
            style={styles.map}
            provider={MapView.PROVIDER_GOOGLE}
            mapType="hybrid"
            rotateEnabled={false}
            initialRegion={this.state.region}
            onLayout={this.onLayout}
            moveOnMarkerPress={false}
          >
            {this.state.lastPosition &&
              <MapView.Marker.Animated
                image={markerImage}
                coordinate={this.state.lastPosition}
                style={{ zIndex: 2 }}
                pointerEvents={'none'}
              />
            }
            {this.state.lastPosition && this.state.heading
              ?
                <MapView.Marker
                  key={'compass'}
                  coordinate={this.state.lastPosition}
                  zIndex={1}
                  anchor={{ x: 0.5, y: 0.6 }}
                  pointerEvents={'none'}
                >
                  <Animated.Image
                    style={{
                      width: 94,
                      height: 94,
                      transform: [
                        { rotate: `${this.state.heading ? this.state.heading : '0'}deg` }
                      ]
                    }}
                    source={compassImage}
                  />
                </MapView.Marker>
              : null
            }
            {this.state.alerts.map((point, key) => {
              let image = alertGladImage;

              if (point.type === 'viirs') {
                image = alertViirsmage;
              }

              if (point.selected) {
                image = alertWhiteImage;
              }

              return (
                <MapView.Marker.Animated
                  key={key}
                  image={image}
                  style={{ opacity: 0.8 }}
                  coordinate={{
                    latitude: point.lat,
                    longitude: point.long
                  }}
                  daggable={false}
                  onPress={() => this.onAlertPress(point)}
                />
              );
            })
            }
          </MapView>
          {this.state.alertSelected
            ? this.renderFooter()
            : this.renderFooterLoading()
          }
        </View>
      :
        renderLoading()
    );
  }
}

Map.propTypes = {
  navigation: React.PropTypes.object.isRequired,
  navigate: React.PropTypes.func.isRequired,
  createReport: React.PropTypes.func.isRequired
};

Map.navigationOptions = {
  header: {
    visible: false
  }
};

export default Map;
<commit_msg>Fix property typo<commit_after>import React, { Component } from 'react';
import {
  View,
  ActivityIndicator,
  Dimensions,
  DeviceEventEmitter,
  Animated,
  Easing,
  StatusBar,
  Image,
  Text,
  Platform,
  TouchableHighlight
} from 'react-native';
import MapView from 'react-native-maps';
import GeoPoint from 'geopoint';
import I18n from 'locales';

import ActionBtn from 'components/common/action-button';
import Config from 'react-native-config';
import Theme from 'config/theme';
import tracker from 'helpers/googleAnalytics';
import styles from './styles';

import { SensorManager } from 'NativeModules';
const { RNLocation: Location } = require('NativeModules');

const { width, height } = Dimensions.get('window');

const ASPECT_RATIO = width / height;
const LATITUDE_DELTA = 10;
const LONGITUDE_DELTA = LATITUDE_DELTA * ASPECT_RATIO;

const markerImage = require('assets/marker.png');
const markerCompassRedImage = require('assets/compass_circle_red.png');
const alertGladImage = require('assets/alert-glad.png');
const alertViirsmage = require('assets/alert-viirs.png');
const alertWhiteImage = require('assets/alert-white.png');
const compassImage = require('assets/compass_direction.png');
const backgroundImage = require('assets/map_bg_gradient.png');
const backIconWhite = require('assets/previous_white.png');

function renderLoading() {
  return (
    <View style={[styles.container, styles.loader]}>
      <ActivityIndicator
        color={Theme.colors.color1}
        style={{ height: 80 }}
        size="large"
      />
    </View>
  );
}

function getGoogleMapsCoordinates(coordinates) {
  const cords = [];

  coordinates.forEach((cordinate) => {
    cords.push({
      latitude: cordinate.lat,
      longitude: cordinate.long
    });
  });

  return cords;
}

class Map extends Component {
  constructor(props) {
    super(props);
    const { params } = this.props.navigation.state;
    const intialCoords = params.center
      ? params.center
      : [Config.maps.lng, Config.maps.lat];

    this.afterRenderTimer = null;
    this.eventLocation = null;
    this.eventOrientation = null;
    this.state = {
      renderMap: false,
      lastPosition: null,
      heading: null,
      geoMarkerOpacity: new Animated.Value(0.3),
      region: {
        latitude: intialCoords.lat,
        longitude: intialCoords.lon,
        latitudeDelta: LATITUDE_DELTA,
        longitudeDelta: LONGITUDE_DELTA
      },
      alertSelected: null,
      alerts: params.features && params.features.length > 0 ? params.features.slice(0, 50) : [] // Provisional
    };
  }

  componentDidMount() {
    tracker.trackScreenView('Map');

    if (Platform.OS === 'ios') {
      Location.requestWhenInUseAuthorization();
      StatusBar.setBarStyle('light-content');
    }

    this.renderMap();
    this.geoLocate();
  }

  geoLocate() {
    this.animateGeo();

    navigator.geolocation.getCurrentPosition(
      (location) => {
        this.setState({
          lastPosition: {
            latitude: location.coords.latitude,
            longitude: location.coords.longitude
          }
        });
      },
      (error) => console.log(error),
      { enableHighAccuracy: true, timeout: 30000, maximumAge: 0 }
    );

    Location.startUpdatingLocation();

    this.eventLocation = DeviceEventEmitter.addListener(
      'locationUpdated',
      (location) => {
        const coords = Platform.OS === 'ios' ? location.coords : location;
        this.setState({
          lastPosition: coords
        });
      }
    );

    if (Platform.OS === 'ios') {
      Location.startUpdatingHeading();
      this.eventOrientation = DeviceEventEmitter.addListener(
        'headingUpdated',
        (data) => {
          this.setState({ heading: parseInt(data.heading, 10) });
        }
      );
    } else {
      SensorManager.startOrientation(1000);
      this.eventOrientation = DeviceEventEmitter.addListener(
        'Orientation',
        (data) => {
          this.setState({
            heading: parseInt(data.azimuth, 10)
          });
        }
      );
    }
  }

  animateGeo() {
    Animated.sequence([
      Animated.timing(this.state.geoMarkerOpacity, {
        toValue: 0.4,
        easing: Easing.in(Easing.quad),
        duration: 800
      }),
      Animated.timing(this.state.geoMarkerOpacity, {
        toValue: 0.15,
        easing: Easing.out(Easing.quad),
        duration: 1000
      })
    ]).start(event => {
      if (event.finished) {
        this.animateGeo();
      }
    });
  }

  componentWillUnmount() {
    Location.stopUpdatingLocation();

    clearTimeout(this.afterRenderTimer);

    if (this.eventLocation) {
      this.eventLocation.remove();
    }

    if (this.eventOrientation) {
      this.eventOrientation.remove();
    }

    if (Platform.OS === 'ios') {
      StatusBar.setBarStyle('default');
      Location.stopUpdatingHeading();
    } else {
      SensorManager.stopOrientation();
    }
  }

  onAlertPress(alertSelected) {
    const alerts = [];

    this.state.alerts.forEach((alert) => {
      const newArea = Object.assign({}, alert);
      newArea.selected = alert.id === alertSelected.id;
      alerts.push(newArea);
    });

    this.setState({
      alerts,
      alertSelected
    });
  }

  onLayout = () => {
    if (!this.state.alertSelected) {
      if (this.afterRenderTimer) {
        clearTimeout(this.afterRenderTimer);
      }
      this.afterRenderTimer = setTimeout(() => {
        const { params } = this.props.navigation.state;
        if (params && params.features && params.features.length > 0) {
          this.map.fitToCoordinates(getGoogleMapsCoordinates(params.features), {
            edgePadding: { top: 100, right: 100, bottom: 100, left: 100 },
            animated: true
          });
        }
      }, 1000);
    }
  }

  renderMap() {
    if (!this.state.renderMap) {
      this.setState({
        renderMap: true
      });
    }
  }

  renderFooter() {
    let distanceText = I18n.t('commonText.notAvailable');
    let distance = 999999;
    const { lastPosition } = this.state;

    if (lastPosition) {
      const geoPoint = new GeoPoint(this.state.alertSelected.lat, this.state.alertSelected.long);
      const currentPoint = new GeoPoint(lastPosition.latitude, lastPosition.longitude);
      distance = currentPoint.distanceTo(geoPoint, true).toFixed(4);
      distanceText = `${distance} ${I18n.t('commonText.kmAway')}`; // in Kilometers
    }

    const createReport = () => {
      const form = `New-report-${Math.floor(Math.random() * 1000)}`;
      let latLng = '0,0';
      if (lastPosition) {
        latLng = `${lastPosition.latitude},${lastPosition.longitude}`;
      }
      this.props.createReport(form, latLng);
      this.props.navigate('NewReport', { form });
    };

    const reportBtn = (
      <ActionBtn
        style={styles.footerButton}
        text={I18n.t('report.title')}
        onPress={() => createReport()}
      />
    );
    return (
      <View style={styles.footer}>
        <Image
          style={styles.footerBg}
          source={backgroundImage}
        />
        <Text style={styles.footerTitle}>
          {distanceText}
        </Text>
        {reportBtn}
      </View>
    );
  }

  renderFooterLoading() {
    return (!this.state.lastPosition &&
      <View style={styles.footer}>
        <Image
          style={styles.footerBg}
          source={backgroundImage}
        />
        <View style={styles.signalNotice}>
          <View style={styles.geoLocationContainer}>
            <Image
              style={styles.marker}
              source={markerCompassRedImage}
            />
            <Animated.View
              style={[styles.geoLocation, { opacity: this.state.geoMarkerOpacity }]}
            />
          </View>
          <Text style={styles.signalNoticeText}>{I18n.t('alerts.satelliteSignal')}</Text>
        </View>
      </View>
    );
  }

  render() {
    const { params } = this.props.navigation.state;

    return (
      this.state.renderMap
      ?
        <View style={styles.container}>
          <View
            style={styles.header}
            pointerEvents={'box-none'}
          >
            <Image
              style={styles.headerBg}
              source={backgroundImage}
            />
            <Text style={styles.headerTitle}>
              {params.title}
            </Text>
            {this.state.alertSelected &&
              <Text style={styles.headerSubtitle}>
                {this.state.alertSelected.lat}, {this.state.alertSelected.long}
              </Text>
            }
            <TouchableHighlight
              style={styles.headerBtn}
              onPress={() => this.props.navigation.goBack()}
              underlayColor="transparent"
              activeOpacity={0.8}
            >
              <Image style={Theme.icon} source={backIconWhite} />
            </TouchableHighlight>
          </View>
          <MapView
            ref={(ref) => { this.map = ref; }}
            style={styles.map}
            provider={MapView.PROVIDER_GOOGLE}
            mapType="hybrid"
            rotateEnabled={false}
            initialRegion={this.state.region}
            onLayout={this.onLayout}
            moveOnMarkerPress={false}
          >
            {this.state.lastPosition &&
              <MapView.Marker.Animated
                image={markerImage}
                coordinate={this.state.lastPosition}
                style={{ zIndex: 2 }}
                pointerEvents={'none'}
              />
            }
            {this.state.lastPosition && this.state.heading
              ?
                <MapView.Marker
                  key={'compass'}
                  coordinate={this.state.lastPosition}
                  zIndex={1}
                  anchor={{ x: 0.5, y: 0.6 }}
                  pointerEvents={'none'}
                >
                  <Animated.Image
                    style={{
                      width: 94,
                      height: 94,
                      transform: [
                        { rotate: `${this.state.heading ? this.state.heading : '0'}deg` }
                      ]
                    }}
                    source={compassImage}
                  />
                </MapView.Marker>
              : null
            }
            {this.state.alerts.map((point, key) => {
              let image = alertGladImage;

              if (point.type === 'viirs') {
                image = alertViirsmage;
              }

              if (point.selected) {
                image = alertWhiteImage;
              }

              return (
                <MapView.Marker.Animated
                  key={key}
                  image={image}
                  style={{ opacity: 0.8 }}
                  coordinate={{
                    latitude: point.lat,
                    longitude: point.long
                  }}
                  draggable={false}
                  onPress={() => this.onAlertPress(point)}
                />
              );
            })
            }
          </MapView>
          {this.state.alertSelected
            ? this.renderFooter()
            : this.renderFooterLoading()
          }
        </View>
      :
        renderLoading()
    );
  }
}

Map.propTypes = {
  navigation: React.PropTypes.object.isRequired,
  navigate: React.PropTypes.func.isRequired,
  createReport: React.PropTypes.func.isRequired
};

Map.navigationOptions = {
  header: {
    visible: false
  }
};

export default Map;
<|endoftext|>


<commit_before>/**
 * @name: PyHouse/src/Modules/Web/js/houseMenu.js
 * @author: D. Brian Kimmel
 * @contact: D.BrianKimmel@gmail.com
 * @Copyright (c) 2012-2014 by D. Brian Kimmel
 * @license: MIT License
 * @note: Created about 2012
 * @summary: Displays the house menu element
 *
 */
// import Nevow.Athena
// import globals
// import helpers

/**
 * The house menu widget.
 *
 */
helpers.Widget.subclass(houseMenu, 'HouseMenuWidget').methods(

    function __init__(self, node) {
        houseMenu.HouseMenuWidget.upcall(self, "__init__", node);
    },

	// ============================================================================
    /**
     * Startup - Place the widget in the workspace and hide it.
     *
     * Override the ready function in C{ helpers.Widget.ready() }
     */
	function ready(self) {
		function cb_widgetready(res) {
			// do whatever init needs here, show for the widget is handled in superclass
			self.hideWidget();
		}
		var uris = collectIMG_src(self.node, null);
		var l_defer = loadImages(uris);
		l_defer.addCallback(cb_widgetready);
		return l_defer;
	},
	function startWidget(self) {
		showSelectionButtons(self);
		self.buildLcarSelectScreen();
	},

// ============================================================================
		/**
		 * Build a screen full of buttons - One for each menu item and some actions.
		 */
	function menuItems(self){
		var l_list = [
		    // Key,           Caption,               Widget Name
			['Location' ,    'House Information',   'House'           ],
			['Rooms',        'Rooms',               'Rooms'           ],
			['Lights',       'Lights',              'Lights'          ],
			['Buttons',      'Buttons',             'Buttons'         ],
			['Controllers',  'Controllers',         'Controllers'     ],
			['Schedules',    'Scheduling',          'Schedules'       ],
			['Levels',       'Lighhting Control',   'ControlLighting' ],
			['Internet',     'Network Addressing',  'Internet'        ],
			['Thermo',       'Thermostat',          'Thermostat'      ],
			['Weather',      'Weather',             'Weather'         ],
			['Nodes',        'Nodes',               'Nodes'           ]
			];
		return l_list;
	},
	function buildLcarSelectScreen(self){
		var l_menu_html = "
\n";
		l_menu_html += buildLcarMenuButtons(self.menuItems(), 'doHandleOnClick');
		l_menu_html += "
\n";
		l_menu_html += "
\n";
		l_obj = {'Name' : 'Back', 'Key' : 'Back'};
		l_menu_html += buildLcarButton(l_obj, 'doHandleOnClick', 'lcars-salmon-bg');
		l_menu_html += "
\n";

		var l_html = build_lcars_top('House Menu', 'lcars-salmon-color');
		l_html += build_lcars_middle_menu(10, l_menu_html);
		l_html += build_lcars_bottom();
		self.nodeById('SelectionButtonsDiv').innerHTML = l_html;
	},

// ============================================================================
	/**
	 * @param self is <"Instance" of undefined.houseMenu.HouseMenuWidget>
	 * @param p_node is node <button> of the button clicked
	 */
	function doHandleOnClick(self, p_node) {
		var l_key = p_node.name;
		var l_node;
		switch (l_key) {
		case 'Location':
			self.showWidget('House');
			break;
		case 'Rooms':
			self.showWidget('Rooms');
			break;
		case 'Lights':
			self.showWidget('Lights');
			break;
		case 'Buttons':
			self.showWidget('Buttons');
			break;
		case 'Controllers':
			self.showWidget('Controllers');
			break;
		case 'Schedules':
			self.showWidget('Schedules');
			break;
		case 'Internet':
			self.showWidget('Internet');
			break;
		case 'Nodes':
			self.showWidget('Nodes');
			break;
		case 'Thermo':
			self.showWidget('Thermostat');
			break;
		case 'Back':
			self.showWidget('RootMenu');
			break;
		default:
			Divmod.debug('---', 'houseMenu.doHandleOnClick(Default) was called.');
			break;
		}
	}
);
// Divmod.debug('---', 'houseMenu.doHandleOnClick(Default) was called.');
// console.log("houseMenu.handleDataOnClick()  json  %O", l_json);
// END DBK<commit_msg>fix house menu<commit_after>/**
 * @name: PyHouse/src/Modules/Web/js/houseMenu.js
 * @author: D. Brian Kimmel
 * @contact: D.BrianKimmel@gmail.com
 * @Copyright (c) 2012-2014 by D. Brian Kimmel
 * @license: MIT License
 * @note: Created about 2012
 * @summary: Displays the house menu element
 *
 */
// import Nevow.Athena
// import globals
// import helpers

/**
 * The house menu widget.
 *
 */
helpers.Widget.subclass(houseMenu, 'HouseMenuWidget').methods(

    function __init__(self, node) {
        houseMenu.HouseMenuWidget.upcall(self, "__init__", node);
    },

	// ============================================================================
    /**
     * Startup - Place the widget in the workspace and hide it.
     *
     * Override the ready function in C{ helpers.Widget.ready() }
     */
	function ready(self) {
		function cb_widgetready(res) {
			// do whatever init needs here, show for the widget is handled in superclass
			self.hideWidget();
		}
		var uris = collectIMG_src(self.node, null);
		var l_defer = loadImages(uris);
		l_defer.addCallback(cb_widgetready);
		return l_defer;
	},
	function startWidget(self) {
		showSelectionButtons(self);
		self.buildLcarSelectScreen();
	},

// ============================================================================
		/**
		 * Build a screen full of buttons - One for each menu item and some actions.
		 */
	function menuItems(self){
		var l_list = [
		    // Key,           Caption,               Widget Name
			['Location' ,    'House Information',   'House'           ],
			['Rooms',        'Rooms',               'Rooms'           ],
			['Lights',       'Lights',              'Lights'          ],
			['Buttons',      'Buttons',             'Buttons'         ],
			['Controllers',  'Controllers',         'Controllers'     ],
			['Schedules',    'Scheduling',          'Schedules'       ],
			['Levels',       'Lighting Control',    'ControlLighting' ],
			['Internet',     'Network Addressing',  'Internet'        ],
			['Thermo',       'Thermostat',          'Thermostat'      ],
			['Weather',      'Weather',             'Weather'         ],
			['Nodes',        'Nodes',               'Nodes'           ]
			];
		return l_list;
	},
	function buildLcarSelectScreen(self){
		var l_menu_html = "
\n";
		l_menu_html += buildLcarMenuButtons(self.menuItems(), 'doHandleOnClick');
		l_menu_html += "
\n";
		l_menu_html += "
\n";
		l_obj = {'Name' : 'Back', 'Key' : 'Back'};
		l_menu_html += buildLcarButton(l_obj, 'doHandleOnClick', 'lcars-salmon-bg');
		l_menu_html += "
\n";

		var l_html = build_lcars_top('House Menu', 'lcars-salmon-color');
		l_html += build_lcars_middle_menu(10, l_menu_html);
		l_html += build_lcars_bottom();
		self.nodeById('SelectionButtonsDiv').innerHTML = l_html;
	},

// ============================================================================
	/**
	 * @param self is <"Instance" of undefined.houseMenu.HouseMenuWidget>
	 * @param p_node is node <button> of the button clicked
	 */
	function doHandleOnClick(self, p_node) {
		var l_key = p_node.name;
		var l_node;
		switch (l_key) {
		case 'Location':
			self.showWidget('House');
			break;
		case 'Levels':
			self.showWidget('ControlLighting');
			break;
		case 'Lights':
			self.showWidget('Lights');
			break;
		case 'Buttons':
			self.showWidget('Buttons');
			break;
		case 'Controllers':
			self.showWidget('Controllers');
			break;
		case 'Schedules':
			self.showWidget('Schedules');
			break;
		case 'Internet':
			self.showWidget('Internet');
			break;
		case 'Nodes':
			self.showWidget('Nodes');
			break;
		case 'Rooms':
			self.showWidget('Rooms');
			break;
		case 'Thermo':
			self.showWidget('Thermostat');
			break;
		case 'Back':
			self.showWidget('RootMenu');
			break;
		default:
			Divmod.debug('---', 'houseMenu.doHandleOnClick(Default) was called.');
			break;
		}
	}
);
// Divmod.debug('---', 'houseMenu.doHandleOnClick(Default) was called.');
// console.log("houseMenu.handleDataOnClick()  json  %O", l_json);
// END DBK<|endoftext|>


<commit_before>/*global Arenite:true*/
/*jshint evil:true*/
// Collection of utility functions to handle loading resources.
Arenite.Loader = function (arenite) {

  var _createCORSRequest = function (method, url) {
    var xhr = new XMLHttpRequest();
    xhr.open(method, url, true);
    xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
    xhr.setRequestHeader("Access-Control-Allow-Origin", window.location.origin);
    if (arenite.config.withCredentials){
      if ('withCredentials' in xhr) {
        xhr.withCredentials = true;
      } else if (typeof XDomainRequest !== 'undefined') {
        xhr = new XDomainRequest();
        xhr.open(method, url);
      } else {
        xhr=null
      }
    }
    return xhr;
  };

  var _loadResource = function (url, callback, error) {
    var req = _createCORSRequest('GET', url);
    req.onreadystatechange = function () {
      if (req.readyState === 4) {
        if (req.status % 100 < 4) {
          callback(req);
        } else if (typeof error === 'function') {
          error(req);
        }
      }
    };
    req.send();
  };

  var _loadScriptWithTag = function (url, callback) {
    var head = document.getElementsByTagName('head')[0];
    var script = document.createElement('script');
    script.async = true;
    script.type = 'text/javascript';
    if (navigator.appVersion.indexOf("MSIE 9") === -1) { //IE 9 calls the callback twice
      script.onreadystatechange = function () {
        if (this.readyState === 'complete') {
          callback();
        }
      };
    }
    script.onload = callback;
    script.src = url;
    head.appendChild(script);
  };

  var _loadScriptAsResource = function (url, callback) {
    _loadResource(url, function (req) {
      //analyze the script for "annotation" type configurations
      arenite.annotation.processAnnotations(req.responseText);
      var file_tag = '\n//@ sourceURL=' + window.location.origin + '/' + url + '\n//# sourceURL=' + window.location.origin + '/' + url;
      eval(req.responseText + file_tag);
      callback();
    });
  };

  var _sameOrigin = function (url) {
    var loc = window.location;
    var a = document.createElement('a');
    a.href = url;
    return a.hostname === loc.hostname &&
      a.port === loc.port &&
      a.protocol === loc.protocol;
  };

  var _loadScriptFrom = function (url, callback) {
    if (_sameOrigin(url)) {
      _loadScriptAsResource(url, callback);
    } else {
      _loadScriptWithTag(url, callback);
    }
  };

  var _loadScript = function (script, done) {
    if (typeof script === 'string') {
      _loadScriptFrom(script, done);
    } else {
      _loadScriptFrom(script.url, function () {
        arenite.object.keys(script.instances).forEach(function (instance) {
          arenite.context.add(instance, window[script.instances[instance]]);
          if (typeof script.init === 'function') {
            script.init(arenite);
          }
          delete window[script.instances[instance]];
        });
        if (typeof done === 'function') {
          done();
        }
      });
    }
  };

  return {
    loader: {
      //###loader.loadResource
      // Load a given resource using ajax.
      //

      // loadResource(url, callback, error)
      //

      //where *url* is the url to fetch from,  *callback* is a function called with the ajax request after
      // it's succesful completion and *error* is an optional callback to handle errors when fetching the resource
      loadResource: _loadResource,
      //###loader.loadScript
      // Load a script. This method will choose the best method to load the script (using tag or ajax) depending on the
      // origin of the script. Additionally it can extract variables exposed in the window object and register them as
      // instances in arenite.
      //

      // loadScript(script, callback)
      //

      //where *script* is either a url string or a structure defining a url and instances to be extracted from
      // the window object into arenite and *callback* is the callback for when the script is loaded.
      loadScript: _loadScript
    }
  };
};
<commit_msg>improving for IE<commit_after>/*global Arenite:true*/
/*jshint evil:true*/
// Collection of utility functions to handle loading resources.
Arenite.Loader = function (arenite) {

  var _createCORSRequest = function (method, url) {
    var xhr = new XMLHttpRequest();
    xhr.open(method, url, true);
    xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
    xhr.setRequestHeader("Access-Control-Allow-Origin", window.location.origin);
    if (arenite.config.withCredentials){
      if ('withCredentials' in xhr) {
        xhr.withCredentials = true;
      } else if (typeof XDomainRequest !== 'undefined') {
        xhr = new XDomainRequest();
        xhr.open(method, url);
      } else {
        xhr=null
      }
    }
    return xhr;
  };

  var _loadResource = function (url, callback, error) {
    var req = _createCORSRequest('GET', url);
    req.onreadystatechange = req.onload = function () {
      if (req.readyState === 4) {
        if (req.status % 100 < 4) {
          callback(req);
        } else if (typeof error === 'function') {
          error(req);
        }
      }
    };
    req.send();
  };

  var _loadScriptWithTag = function (url, callback) {
    var head = document.getElementsByTagName('head')[0];
    var script = document.createElement('script');
    script.async = true;
    script.type = 'text/javascript';
    if (navigator.appVersion.indexOf("MSIE 9") === -1) { //IE 9 calls the callback twice
      script.onreadystatechange = function () {
        if (this.readyState === 'complete') {
          callback();
        }
      };
    }
    script.onload = callback;
    script.src = url;
    head.appendChild(script);
  };

  var _loadScriptAsResource = function (url, callback) {
    _loadResource(url, function (req) {
      //analyze the script for "annotation" type configurations
      arenite.annotation.processAnnotations(req.responseText);
      var file_tag = '\n//@ sourceURL=' + window.location.origin + '/' + url + '\n//# sourceURL=' + window.location.origin + '/' + url;
      eval(req.responseText + file_tag);
      callback();
    });
  };

  var _sameOrigin = function (url) {
    var loc = window.location;
    var a = document.createElement('a');
    a.href = url;
    return a.hostname === loc.hostname &&
      a.port === loc.port &&
      a.protocol === loc.protocol;
  };

  var _loadScriptFrom = function (url, callback) {
    if (_sameOrigin(url)) {
      _loadScriptAsResource(url, callback);
    } else {
      _loadScriptWithTag(url, callback);
    }
  };

  var _loadScript = function (script, done) {
    if (typeof script === 'string') {
      _loadScriptFrom(script, done);
    } else {
      _loadScriptFrom(script.url, function () {
        arenite.object.keys(script.instances).forEach(function (instance) {
          arenite.context.add(instance, window[script.instances[instance]]);
          if (typeof script.init === 'function') {
            script.init(arenite);
          }
          delete window[script.instances[instance]];
        });
        if (typeof done === 'function') {
          done();
        }
      });
    }
  };

  return {
    loader: {
      //###loader.loadResource
      // Load a given resource using ajax.
      //

      // loadResource(url, callback, error)
      //

      //where *url* is the url to fetch from,  *callback* is a function called with the ajax request after
      // it's succesful completion and *error* is an optional callback to handle errors when fetching the resource
      loadResource: _loadResource,
      //###loader.loadScript
      // Load a script. This method will choose the best method to load the script (using tag or ajax) depending on the
      // origin of the script. Additionally it can extract variables exposed in the window object and register them as
      // instances in arenite.
      //

      // loadScript(script, callback)
      //

      //where *script* is either a url string or a structure defining a url and instances to be extracted from
      // the window object into arenite and *callback* is the callback for when the script is loaded.
      loadScript: _loadScript
    }
  };
};
<|endoftext|>


<commit_before>var gulp = require('gulp');
var fs = require('fs');
var merge = require('merge2');
var concat = require('gulp-concat');
var rename = require('gulp-rename');
var less = require('gulp-less');
var sass = require('gulp-sass');
var cleancss = require('gulp-clean-css');
var autoprefixer = require('gulp-autoprefixer');
var sourcemaps = require('gulp-sourcemaps');
var svgstore = require('gulp-svgstore');
var svgmin = require('gulp-svgmin');
var cheerio = require('gulp-cheerio');
var jshint = require('gulp-jshint');
var stylish = require('jshint-stylish');
var uglify = require('gulp-uglify');
var livereload = require('gulp-livereload');
var config = require('js-yaml').safeLoad(fs.readFileSync('rockety.yml', 'utf8'));
var sources = [];

gulp.task('config', function () {
    console.log(JSON.stringify(config, null, 4));
});

function css(config) {
    var stream, vendors = [], vendor, css;

    (config.css.vendor || []).forEach(function (item) {
        vendors.push('./src/vendor/' + item);
    });
    vendor = gulp.src(vendors);

    if (config.css.styles) {
        css = merge(
            gulp.src(config.css.styles.less ? config.source + '/less/' + config.css.styles.less : []).pipe(less()),
            gulp.src(config.css.styles.sass ? config.source + '/sass/' + config.css.styles.sass : []).pipe(sass())
        ).pipe(autoprefixer({
            browsers: ['last 2 versions'],
            cascade: false
        }));
    }

    stream = merge(vendor, css || gulp.src([]));
    if (config.css.sourcemap) {
        stream = stream.pipe(sourcemaps.init());
    }
    if (config.css.minify) {
        stream = stream.pipe(cleancss());
    }
    stream = stream.pipe(concat('style.css'));
    if (config.css.sourcemap) {
        stream = stream.pipe(sourcemaps.write());
    }
    stream = stream.pipe(gulp.dest(config.dest + '/css'));
    stream.pipe(livereload());
}

function svg(config) {
    return gulp.src(config.source + '/svg/*.svg')
        .pipe(rename({prefix: 'shape-'}))
        .pipe(svgmin())
        .pipe(svgstore())
        .pipe(cheerio({
            run: function ($) {
                $('svg').attr('style', 'display:none');
            },
            parserOptions: {xmlMode: true}
        }))
        .pipe(rename('shapes.svg'))
        .pipe(gulp.dest(config.dest + '/svg'))
        .pipe(livereload());
}

function js(config) {
    var stream, vendors = [], vendor, scripts = [], script;

    (config.js.vendor || []).forEach(function (item) {
        vendors.push('./src/vendor/' + item);
    });
    vendor = gulp.src(vendors);

    (config.js.scripts || []).forEach(function (item) {
        scripts.push(config.source + '/js/' + item);
    });
    script = gulp.src(scripts);

    if (scripts.length) {
        script = script.pipe(jshint()).pipe(jshint.reporter('jshint-stylish', {beep: true}));
    }

    stream = merge(vendor, script);
    if (config.js.sourcemap) {
        stream = stream.pipe(sourcemaps.init());
    }
    if (config.js.minify) {
        stream = stream.pipe(uglify());
    }
    stream = stream.pipe(concat('scripts.js', {newLine: ';'}));
    if (config.js.sourcemap) {
        stream = stream.pipe(sourcemaps.write());
    }
    stream = stream.pipe(gulp.dest(config.dest + '/js'));
    stream.pipe(livereload());
}

config.forEach(function (source) {
    sources.push(source.source);
    gulp.task('css:' + source.source, function () {
        return css(source)
    });
    gulp.task('svg:' + source.source, function () {
        return svg(source)
    });
    gulp.task('js:' + source.source, function () {
        return js(source)
    });

    gulp.task('reload:' + source.source, function () {
        gulp.src(source.watch).pipe(livereload());
    });

    gulp.task('copy:' + source.source, function () {
        source.copy.forEach(function(files) {
            Object.keys(files).forEach(function(src) {
                gulp.src(src).pipe(gulp.dest(files[src])).pipe(livereload());
            });
        });
    });
});

gulp.task('css', (sources.map(function(source) {
    return 'css:' + source;
})), function () {});
gulp.task('svg', (sources.map(function(source) {
    return 'svg:' + source;
})), function () {});
gulp.task('js', (sources.map(function(source) {
    return 'js:' + source;
})), function () {});
gulp.task('reload', (sources.map(function(source) {
    return 'reload:' + source;
})), function () {});
gulp.task('copy', (sources.map(function(source) {
    return 'copy:' + source;
})), function () {});

gulp.task('build', ['css', 'svg', 'js'], function () {});

gulp.task('watch', function () {
    livereload.listen();
    config.forEach(function(source) {
        gulp.watch(source.source + '/less/*.less', ['css:' + source.source]);
        gulp.watch(source.source + '/sass/*.sass', ['css:' + source.source]);
        gulp.watch(source.source + '/sass/*.scss', ['css:' + source.source]);
        gulp.watch(source.source + '/svg/*.svg', ['svg:' + source.source]);
        gulp.watch(source.source + '/js/*.js', ['js:' + source.source]);
        gulp.watch(source.watch, ['reload:' + source.source]);
        var copySources = [];
        (source.copy || []).forEach(function(files) {
            Object.keys(files).forEach(function(src) {
                copySources.push(src);
            });
        });
        gulp.watch(copySources, ['copy:' + source.source]);
    });
});<commit_msg>Allow smaller rockety.yml file by removing configurations which are not needed. For example you may not need any "copy" directive, or "watch". There are project which do not require JavaScript (or CSS, lol). It is possible to comment/remove these rows from the config file and it will not break the build/watch process<commit_after>var gulp = require('gulp');
var fs = require('fs');
var merge = require('merge2');
var concat = require('gulp-concat');
var rename = require('gulp-rename');
var less = require('gulp-less');
var sass = require('gulp-sass');
var cleancss = require('gulp-clean-css');
var autoprefixer = require('gulp-autoprefixer');
var sourcemaps = require('gulp-sourcemaps');
var svgstore = require('gulp-svgstore');
var svgmin = require('gulp-svgmin');
var cheerio = require('gulp-cheerio');
var jshint = require('gulp-jshint');
var stylish = require('jshint-stylish');
var uglify = require('gulp-uglify');
var livereload = require('gulp-livereload');
var config = require('js-yaml').safeLoad(fs.readFileSync('rockety.yml', 'utf8'));
var sources = [];

gulp.task('config', function () {
    console.log(JSON.stringify(config, null, 4));
});

function css(config) {
    var stream, vendors = [], vendor, css;

    if (!config.css) {
        return;
    }

    (config.css.vendor || []).forEach(function (item) {
        vendors.push('./src/vendor/' + item);
    });
    vendor = gulp.src(vendors);

    if (config.css.styles) {
        css = merge(
            gulp.src(config.css.styles.less ? config.source + '/less/' + config.css.styles.less : []).pipe(less()),
            gulp.src(config.css.styles.sass ? config.source + '/sass/' + config.css.styles.sass : []).pipe(sass())
        ).pipe(autoprefixer({
            browsers: ['last 2 versions'],
            cascade: false
        }));
    }

    stream = merge(vendor, css || gulp.src([]));
    if (config.css.sourcemap) {
        stream = stream.pipe(sourcemaps.init());
    }
    if (config.css.minify) {
        stream = stream.pipe(cleancss());
    }
    stream = stream.pipe(concat('style.css'));
    if (config.css.sourcemap) {
        stream = stream.pipe(sourcemaps.write());
    }
    stream = stream.pipe(gulp.dest(config.dest + '/css'));
    stream.pipe(livereload());
}

function svg(config) {
    return gulp.src(config.source + '/svg/*.svg')
        .pipe(rename({prefix: 'shape-'}))
        .pipe(svgmin())
        .pipe(svgstore())
        .pipe(cheerio({
            run: function ($) {
                $('svg').attr('style', 'display:none');
            },
            parserOptions: {xmlMode: true}
        }))
        .pipe(rename('shapes.svg'))
        .pipe(gulp.dest(config.dest + '/svg'))
        .pipe(livereload());
}

function js(config) {
    var stream, vendors = [], vendor, scripts = [], script;

    if (!config.js) {
        return;
    }

    (config.js.vendor || []).forEach(function (item) {
        vendors.push('./src/vendor/' + item);
    });
    vendor = gulp.src(vendors);

    (config.js.scripts || []).forEach(function (item) {
        scripts.push(config.source + '/js/' + item);
    });
    script = gulp.src(scripts);

    if (scripts.length) {
        script = script.pipe(jshint()).pipe(jshint.reporter('jshint-stylish', {beep: true}));
    }

    stream = merge(vendor, script);
    if (config.js.sourcemap) {
        stream = stream.pipe(sourcemaps.init());
    }
    if (config.js.minify) {
        stream = stream.pipe(uglify());
    }
    stream = stream.pipe(concat('scripts.js', {newLine: ';'}));
    if (config.js.sourcemap) {
        stream = stream.pipe(sourcemaps.write());
    }
    stream = stream.pipe(gulp.dest(config.dest + '/js'));
    stream.pipe(livereload());
}

config.forEach(function (source) {
    sources.push(source.source);
    gulp.task('css:' + source.source, function () {
        return css(source)
    });
    gulp.task('svg:' + source.source, function () {
        return svg(source)
    });
    gulp.task('js:' + source.source, function () {
        return js(source)
    });

    gulp.task('reload:' + source.source, function () {
        gulp.src(source.watch).pipe(livereload());
    });

    gulp.task('copy:' + source.source, function () {
        (source.copy || []).forEach(function(files) {
            Object.keys(files).forEach(function(src) {
                gulp.src(src).pipe(gulp.dest(files[src])).pipe(livereload());
            });
        });
    });
});

gulp.task('css', (sources.map(function(source) {
    return 'css:' + source;
})), function () {});
gulp.task('svg', (sources.map(function(source) {
    return 'svg:' + source;
})), function () {});
gulp.task('js', (sources.map(function(source) {
    return 'js:' + source;
})), function () {});
gulp.task('reload', (sources.map(function(source) {
    return 'reload:' + source;
})), function () {});
gulp.task('copy', (sources.map(function(source) {
    return 'copy:' + source;
})), function () {});

gulp.task('build', ['css', 'svg', 'js'], function () {});

gulp.task('watch', function () {
    livereload.listen();
    config.forEach(function(source) {
        gulp.watch(source.source + '/less/*.less', ['css:' + source.source]);
        gulp.watch(source.source + '/sass/*.sass', ['css:' + source.source]);
        gulp.watch(source.source + '/sass/*.scss', ['css:' + source.source]);
        gulp.watch(source.source + '/svg/*.svg', ['svg:' + source.source]);
        gulp.watch(source.source + '/js/*.js', ['js:' + source.source]);
        gulp.watch(source.watch || [], ['reload:' + source.source]);
        var copySources = [];
        (source.copy || []).forEach(function(files) {
            Object.keys(files).forEach(function(src) {
                copySources.push(src);
            });
        });
        gulp.watch(copySources, ['copy:' + source.source]);
    });
});<|endoftext|>


<commit_before>var people = [
 {
   "title": "Mayor",
   "district": "n/a",
   "name": {
     "first": "John ",
     "last": "Giles",
     "fullname": "John Giles"
   },
   "bio": "John Giles was elected the 40th Mayor of Mesa, Arizona in August, 2014.   Giles earned degrees from Brigham Young University in Political Science and Arizona State University's Sandra Day O'Connor College of Law.  He has managed  his own law firm in downtown Mesa for the past 20 years.  In 1996, Giles was elected to the Mesa City Council and from 1998 to 2000,  he served as Vice Mayor.  Mayor Giles is committed to leading the way to build  upon Mesa's strengths in economic development, education, community livability,  smart growth and accessibility and participation in City government.",
   "social": [
     {
       "platform": "facebook",
       "name": "MesaMayorsOffice"
     },
     {
       "platform": "twitter",
       "name": "MesaMayorOffice"
     }
   ],
   "phone": "480-644-2388",
   "email": "mayor@Mesaaz.gov",
   "website_url": "http://www.mesaaz.gov/mayor/",
   "photo_url": "https://techieshark.github.io/council-info/img/John_Giles_sm.jpg"
 },
 {
   "title": "City Councilmember",
   "district": "1",
   "name": {
     "first": "Dave",
     "last": "Richins",
     "fullname": "Dave Richins"
   },
   "bio": "Dave Richins was elected as the Councilmember representing Mesa’s District 1 in June of 2008 and was re-elected to a second term in August of 2012. Richins has been active on both a state and national level during his time on the City Council, representing the city on the National League of Cities’ Community and Economic Development steering committee.  He also serves on the Advisory Board of Smart Growth America's Local Leaders Council and sits on the U.S. Environmental Protection Agency's Local Government Advisory Council and the Arizona Power Plant and Line Sitting Commission.  Councilmember Richins earned his Bachelor of Arts degree in Sustainable Community Development from Prescott College. ",
   "social": [
     {
       "platform": "facebook",
       "name": "CouncilmemberDaveRichins"
     },
     {
       "platform": "twitter",
       "name": "dlrichins",
       "widget": "465935532589993984"
     }
   ],
   "phone": "480-644-4002",
   "email": "District1@mesaaz.gov",
   "website_url": "http://www.mesaaz.gov/council/richins/default.aspx",
   "photo_url": "https://techieshark.github.io/council-info/img/Dave_Richins_sm.jpg"
 },
 {
   "title": "City Councilmember",
   "district": "2",
   "name": {
     "first": "Alex",
     "last": "Finter",
     "fullname": "Alex Finter"
   },
   "bio": "Elected to the Mesa City Council in June of 2008 and re-elected in August of 2012, Alex Finter is in his second term as the Councilmember for District 2. Finter was chosen as Vice Mayor of the City Council in January 2013, holding that title until he became the Mayor of Mesa in April 2014.   He served as Mesa’s Mayor until September 18, 2014, when he resumed his role as the District 2 Councilmember. During his time in the Mayor’s office, Finter helped implement both the Falcon Field Strategic Visioning Commission and the Downtown Vision Committee, as well as the Hometown Heroes banner program. In the private-sector, Finter is a businessman and partner at Worldwide Investments LLC. ",
   "social": [
     {
       "platform": "facebook",
       "name": "CouncilmemberAlexFinter"
     },
     {
       "platform": "twitter",
       "name": "MesaDistrict2",
       "widget": "465941398470922240"
     }
   ],
   "phone": "480-644-3772",
   "email": "councilmember.finter@Mesaaz.gov",
   "website_url": "http://www.mesaaz.gov/council/finter/",
   "photo_url": "https://techieshark.github.io/council-info/img/Alex_Finter_sm.jpg"
 },
 {
   "title": "City Councilmember",
   "district": "3",
   "name": {
     "first": "Dennis",
     "last": "Kavanaugh ",
     "fullname": "Dennis Kavanaugh "
   },
   "bio": "Dennis Kavanaugh was elected to serve as the Mesa City Councilmember for District 3 in June of 2008 and was re-elected in August of 2012. Kavanaugh also was a member of the City Council from 1996 until 2004, serving as Vice Mayor from 2002 to 2004. Kavanaugh sits on several different committees and boards, including serving as the chairperson of the Council Public Safety committee. He currently sits on the Mesa Community College Commission on Excellence in Education and is the Vice Chair of the Valley Metro Rail board.  Councilmember Kavanaugh received his J.D. degree in from Arizona State University and a B.A. in Political Science from St. Louis University.",
   "social": [
     {
       "platform": "facebook",
       "name": "councilmember.kavanaugh"
     },
     {
       "platform": "twitter",
       "name": "MesaDistrict3",
       "widget": "465941592985968641"
     }
   ],
   "phone": "480-644-3003",
   "email": "District3@mesaaz.gov",
   "website_url": "http://www.mesaaz.gov/council/kavanaugh/default.aspx",
   "photo_url": "https://techieshark.github.io/council-info/img/Dennis_Kavanaugh_sm.jpg"
 },
 {
   "title": "City Councilmember",
   "district": "4",
   "name": {
     "first": "Chris",
     "last": "Glover",
     "fullname": "Chris Glover"
   },
   "bio": "Serving his first term representing Mesa's District 4, Vice Mayor Chris Glover became the youngest person ever to serve on the Mesa City Council following his election in 2011. Glover is a native of Mesa, attending Mesa Public Schools, graduating with honors from Mesa High School and he was a member of the Mayor's Youth Committee.  Vice Mayor Glover earned a degree in Political Science with minors in  History and Spanish and a Master of Science in Management from   Arizona State University.",
   "social": [
     {
       "platform": "facebook",
       "name": "CouncilmemberChrisGlover"
     },
     {
       "platform": "twitter",
       "name": "MesaDistrict4",
       "widget": "465941739635613696"
     }
   ],
   "phone": "480-644- 3004",
   "email": "councilmember.glover@Mesaaz.gov",
   "website_url": "http://www.mesaaz.gov/council/glover/",
   "photo_url": "https://techieshark.github.io/council-info/img/Chris_Glover_sm.jpg"
 },
 {
   "title": "City Councilmember",
   "district": "5",
   "name": {
     "first": "David",
     "last": "Luna",
     "fullname": "David Luna"
   },
   "bio": "David Luna was appointed to fill the vacant District 5 seat on the Mesa City Council in September of 2013. Luna has been recognized for his community involvement with numerous awards, including the Mesa United Way Volunteer of the Year Award in 2006, the City of Mesa National Emergency Preparedness Recognition in 2007, the Valle del Sol Hall of Fame Award in 2011 and the Mesa United Way Spirit of Mesa Award in 2012 and the City of Mesa's Citizen of the Year in 2012.  Luna was also inducted into the Silver Circle Society (National Academy of Arts and Science) Rocky Mountain Chapter  Councilmember Luna earned his Bachelor of Arts in Radio/Television from the University of Arizona, a Master of Mass Communication from Arizona State University and his Doctorate in Educational Leadership from Northern Arizona University in 2012. ",
   "social": [
     {
       "platform": "facebook",
       "name": "CouncilmemberDavidLuna"
     },
     {
       "platform": "twitter",
       "name": "MesaDistrict5",
       "widget": "465941843922792448"
     }
   ],
   "phone": "480-644-3771",
   "email": "councilmember.luna@Mesaaz.gov",
   "website_url": "http://www.mesaaz.gov/council/luna/default.aspx",
   "photo_url": "https://techieshark.github.io/council-info/img/David_Luna_sm.jpg"
 },
 {
   "title": "City Councilmember",
   "district": "6",
   "name": {
     "first": "Scott",
     "last": "Somers",
     "fullname": "Scott Somers"
   },
   "bio": "Scott Somers was first elected to represent District 6 on the Mesa City Council in 2006 and was re-elected in 2010. He spent two years serving Mesa as Vice Mayor from 2011 to 2013. Somers has worked to make District 6 a hub for economic development in Mesa, with companies like Apple, Able Engineering, Bridgestone America, CMC Steel and Matheson Gas calling the area home. Somers serves as the Chair of the ValleyMetro Regional Public Transportation Authority and is the Chairman of the NLC Public Safety & Crime Prevention committee. He represents the interests of cities on the National EMS Advisory Council (NEMSAC), the National Homeland Security Consortium, and FirstNet's Public Safety Advisory Committee.  Councilmember Somers earned a Ph.D. in public administration from Arizona State University. He holds Bachelor of Applied Science and Master of Science in Technology degrees from the ASU Polytechnic campus.",
   "social": [
     {
       "platform": "facebook",
       "name": "DrScottCSomers"
     },
     {
       "platform": "twitter",
       "name": "MesaDistrict6",
       "widget": "465941964072828928"
     }
   ],
   "phone": "480-644-4003",
   "email": "councilmember.somers@Mesaaz.gov",
   "website_url": "http://www.mesaaz.gov/council/somers/default.aspx",
   "photo_url": "https://techieshark.github.io/council-info/img/Scott_Somers_sm.jpg"
 },
 {
   "title": "City Manager",
   "district": "n/a",
   "name": {
     "first": "Chris",
     "last": "Brady",
     "fullname": "Chris Brady"
   },
   "bio": "The City Manager, as the City's chief administrative officer, administers the functions of the City in accordance with the City Charter, Ordinances, and established policies.  The City Manager’s Office provides centralized direction and leadership for the effective administration and operations of all municipal services for the City of Mesa as directed by the City Council and serves as the focal point for the management of the City staff departments.  The City Manager’s Office prepares and submits to the City Council a balanced budget of municipal services in adherence with the policy goals and objectives by the City Council while employing such managerial techniques as needed to assure efficient and effective utilization of the City’s resources.",
   "social": [
     {
       "platform": "facebook",
       "name": "CityofMesa"
     },
     {
       "platform": "twitter",
       "name": "MesaCityManager"
     }
    ],
   "phone": "480-644-2066",
   "email": "COMmanager@Mesaaz.gov",
   "website_url": "http://www.mesaaz.gov/mayor/",
   "photo_url": "https://techieshark.github.io/council-info/img/Chris_Brady_sm.jpg"
  },
]
<commit_msg>Update people.js (content for Glover & Kavanaugh)<commit_after>var people = [
 {
   "title": "Mayor",
   "district": "n/a",
   "name": {
     "first": "John ",
     "last": "Giles",
     "fullname": "John Giles"
   },
   "bio": "John Giles was elected the 40th Mayor of Mesa, Arizona in August, 2014.   Giles earned degrees from Brigham Young University in Political Science and Arizona State University's Sandra Day O'Connor College of Law.  He has managed  his own law firm in downtown Mesa for the past 20 years.  In 1996, Giles was elected to the Mesa City Council and from 1998 to 2000,  he served as Vice Mayor.  Mayor Giles is committed to leading the way to build  upon Mesa's strengths in economic development, education, community livability,  smart growth and accessibility and participation in City government.",
   "social": [
     {
       "platform": "facebook",
       "name": "MesaMayorsOffice"
     },
     {
       "platform": "twitter",
       "name": "MesaMayorOffice"
     }
   ],
   "phone": "480-644-2388",
   "email": "mayor@Mesaaz.gov",
   "website_url": "http://www.mesaaz.gov/mayor/",
   "photo_url": "https://techieshark.github.io/council-info/img/John_Giles_sm.jpg"
 },
 {
   "title": "City Councilmember",
   "district": "1",
   "name": {
     "first": "Dave",
     "last": "Richins",
     "fullname": "Dave Richins"
   },
   "bio": "Dave Richins was elected as the Councilmember representing Mesa’s District 1 in June of 2008 and was re-elected to a second term in August of 2012. Richins has been active on both a state and national level during his time on the City Council, representing the city on the National League of Cities’ Community and Economic Development steering committee.  He also serves on the Advisory Board of Smart Growth America's Local Leaders Council and sits on the U.S. Environmental Protection Agency's Local Government Advisory Council and the Arizona Power Plant and Line Sitting Commission.  Councilmember Richins earned his Bachelor of Arts degree in Sustainable Community Development from Prescott College. ",
   "social": [
     {
       "platform": "facebook",
       "name": "CouncilmemberDaveRichins"
     },
     {
       "platform": "twitter",
       "name": "dlrichins",
       "widget": "465935532589993984"
     }
   ],
   "phone": "480-644-4002",
   "email": "District1@mesaaz.gov",
   "website_url": "http://www.mesaaz.gov/council/richins/default.aspx",
   "photo_url": "https://techieshark.github.io/council-info/img/Dave_Richins_sm.jpg"
 },
 {
   "title": "City Councilmember",
   "district": "2",
   "name": {
     "first": "Alex",
     "last": "Finter",
     "fullname": "Alex Finter"
   },
   "bio": "Elected to the Mesa City Council in June of 2008 and re-elected in August of 2012, Alex Finter is in his second term as the Councilmember for District 2. Finter was chosen as Vice Mayor of the City Council in January 2013, holding that title until he became the Mayor of Mesa in April 2014.   He served as Mesa’s Mayor until September 18, 2014, when he resumed his role as the District 2 Councilmember. During his time in the Mayor’s office, Finter helped implement both the Falcon Field Strategic Visioning Commission and the Downtown Vision Committee, as well as the Hometown Heroes banner program. In the private-sector, Finter is a businessman and partner at Worldwide Investments LLC. ",
   "social": [
     {
       "platform": "facebook",
       "name": "CouncilmemberAlexFinter"
     },
     {
       "platform": "twitter",
       "name": "MesaDistrict2",
       "widget": "465941398470922240"
     }
   ],
   "phone": "480-644-3772",
   "email": "councilmember.finter@Mesaaz.gov",
   "website_url": "http://www.mesaaz.gov/council/finter/",
   "photo_url": "https://techieshark.github.io/council-info/img/Alex_Finter_sm.jpg"
 },
 {
   "title": "City Councilmember",
   "district": "3",
   "name": {
     "first": "Dennis",
     "last": "Kavanaugh ",
     "fullname": "Dennis Kavanaugh "
   },
   "bio": "Dennis Kavanaugh was elected to serve as the Mesa City Councilmember for District 3 in June of 2008 and was re-elected in August of 2012.  He was named the Vice Mayor of Mesa in January of 2015.  Kavanaugh also was a member of the City Council from 1996 until 2004, serving as Vice Mayor from 2002 to 2004.  Kavanaugh sits on several different committees and boards, including serving as the chairperson of the Council Public Safety committee. He currently sits on the Mesa Community College Commission on Excellence in Education and is the Vice Chair of the Valley Metro Rail board. Councilmember Kavanaugh received his J.D. degree in from Arizona State University and a B.A. in Political Science from St. Louis University.",
   "social": [
     {
       "platform": "facebook",
       "name": "councilmember.kavanaugh"
     },
     {
       "platform": "twitter",
       "name": "MesaDistrict3",
       "widget": "465941592985968641"
     }
   ],
   "phone": "480-644-3003",
   "email": "District3@mesaaz.gov",
   "website_url": "http://www.mesaaz.gov/council/kavanaugh/default.aspx",
   "photo_url": "https://techieshark.github.io/council-info/img/Dennis_Kavanaugh_sm.jpg"
 },
 {
   "title": "City Councilmember",
   "district": "4",
   "name": {
     "first": "Chris",
     "last": "Glover",
     "fullname": "Chris Glover"
   },
   "bio": "Serving his first term representing Mesa's District 4, Chris Glover became the youngest person ever to serve on the Mesa City Council following his election in 2011.  He was named Vice Mayor in April 2014, serving in the position until January of 2015. Glover is a native of Mesa, attending Mesa Public Schools, graduating with honors from Mesa High School and he was a member of the Mayor's Youth Committee. Vice Mayor Glover earned a degree in Political Science with minors in History and Spanish and a Master of Science in Management from Arizona State University.",
   "social": [
     {
       "platform": "facebook",
       "name": "CouncilmemberChrisGlover"
     },
     {
       "platform": "twitter",
       "name": "MesaDistrict4",
       "widget": "465941739635613696"
     }
   ],
   "phone": "480-644- 3004",
   "email": "councilmember.glover@Mesaaz.gov",
   "website_url": "http://www.mesaaz.gov/council/glover/",
   "photo_url": "https://techieshark.github.io/council-info/img/Chris_Glover_sm.jpg"
 },
 {
   "title": "City Councilmember",
   "district": "5",
   "name": {
     "first": "David",
     "last": "Luna",
     "fullname": "David Luna"
   },
   "bio": "David Luna was appointed to fill the vacant District 5 seat on the Mesa City Council in September of 2013. Luna has been recognized for his community involvement with numerous awards, including the Mesa United Way Volunteer of the Year Award in 2006, the City of Mesa National Emergency Preparedness Recognition in 2007, the Valle del Sol Hall of Fame Award in 2011 and the Mesa United Way Spirit of Mesa Award in 2012 and the City of Mesa's Citizen of the Year in 2012.  Luna was also inducted into the Silver Circle Society (National Academy of Arts and Science) Rocky Mountain Chapter  Councilmember Luna earned his Bachelor of Arts in Radio/Television from the University of Arizona, a Master of Mass Communication from Arizona State University and his Doctorate in Educational Leadership from Northern Arizona University in 2012. ",
   "social": [
     {
       "platform": "facebook",
       "name": "CouncilmemberDavidLuna"
     },
     {
       "platform": "twitter",
       "name": "MesaDistrict5",
       "widget": "465941843922792448"
     }
   ],
   "phone": "480-644-3771",
   "email": "councilmember.luna@Mesaaz.gov",
   "website_url": "http://www.mesaaz.gov/council/luna/default.aspx",
   "photo_url": "https://techieshark.github.io/council-info/img/David_Luna_sm.jpg"
 },
 {
   "title": "City Councilmember",
   "district": "6",
   "name": {
     "first": "Scott",
     "last": "Somers",
     "fullname": "Scott Somers"
   },
   "bio": "Scott Somers was first elected to represent District 6 on the Mesa City Council in 2006 and was re-elected in 2010. He spent two years serving Mesa as Vice Mayor from 2011 to 2013. Somers has worked to make District 6 a hub for economic development in Mesa, with companies like Apple, Able Engineering, Bridgestone America, CMC Steel and Matheson Gas calling the area home. Somers serves as the Chair of the ValleyMetro Regional Public Transportation Authority and is the Chairman of the NLC Public Safety & Crime Prevention committee. He represents the interests of cities on the National EMS Advisory Council (NEMSAC), the National Homeland Security Consortium, and FirstNet's Public Safety Advisory Committee.  Councilmember Somers earned a Ph.D. in public administration from Arizona State University. He holds Bachelor of Applied Science and Master of Science in Technology degrees from the ASU Polytechnic campus.",
   "social": [
     {
       "platform": "facebook",
       "name": "DrScottCSomers"
     },
     {
       "platform": "twitter",
       "name": "MesaDistrict6",
       "widget": "465941964072828928"
     }
   ],
   "phone": "480-644-4003",
   "email": "councilmember.somers@Mesaaz.gov",
   "website_url": "http://www.mesaaz.gov/council/somers/default.aspx",
   "photo_url": "https://techieshark.github.io/council-info/img/Scott_Somers_sm.jpg"
 },
 {
   "title": "City Manager",
   "district": "n/a",
   "name": {
     "first": "Chris",
     "last": "Brady",
     "fullname": "Chris Brady"
   },
   "bio": "The City Manager, as the City's chief administrative officer, administers the functions of the City in accordance with the City Charter, Ordinances, and established policies.  The City Manager’s Office provides centralized direction and leadership for the effective administration and operations of all municipal services for the City of Mesa as directed by the City Council and serves as the focal point for the management of the City staff departments.  The City Manager’s Office prepares and submits to the City Council a balanced budget of municipal services in adherence with the policy goals and objectives by the City Council while employing such managerial techniques as needed to assure efficient and effective utilization of the City’s resources.",
   "social": [
     {
       "platform": "facebook",
       "name": "CityofMesa"
     },
     {
       "platform": "twitter",
       "name": "MesaCityManager"
     }
    ],
   "phone": "480-644-2066",
   "email": "COMmanager@Mesaaz.gov",
   "website_url": "http://www.mesaaz.gov/mayor/",
   "photo_url": "https://techieshark.github.io/council-info/img/Chris_Brady_sm.jpg"
  },
]
<|endoftext|>


<commit_before>'use strict';

angular.module('eMarketApp').directive('sellerProfile', function(Restangular, SellerInfo, User, Helper) {
  return {
    templateUrl: 'views/sellerProfile.html',
    restrict: 'E',
    scope: {},
    replace: true,
    controller: function($scope, Product) {

      $scope.setItem = Product.setItem;

    },
    link: function(scope, elem) {

      var page = $(elem[0]);

      var sellerProductList = page.find('#sellerProfile-sellerProductList');
      var sellerRatingList = page.find('#sellerProfile-sellerRatingList');

      var sellerAvgRate = page.find('#sellerProfile-sellerAvgRate');
      var rateSellerBox = page.find('#sellerProfile-rateSeller');

      page.on('pagebeforeshow', function() {

        Restangular.one('users', SellerInfo.sellerId).getList('unsoldProducts').then(function(products) {
          scope.products = products;
          Helper.refreshList(sellerProductList);
        });

        scope.sellerName = SellerInfo.sellerName;
        scope.sellerAvgRate = SellerInfo.sellerAvgRate;

        setTimeout(function() {

          sellerAvgRate.raty({
            score: function() {
              return $(this).attr('data-score');
            },
            size: 12,
            readOnly: true,
            path: '../lib/raty/lib/img'
          });

          rateSellerBox.raty({
            size: 16,
            path: '../lib/raty/lib/img',
            click: function() {
              var score = $(this).raty('score');
              console.log('clicked star', $(this).raty('score'));
              Restangular.one('users', SellerInfo.sellerId).all('ratings')
                  .post({ratedId: SellerInfo.sellerId, raterId: User.userId, value: score});
            }
          });

          scope.$watch(function() {
            return rateSellerBox.raty('score');
          }, function() {
            console.log('rating val', arguments);
          });

          Helper.refreshList(sellerRatingList);

        });

      });

      page.on('pagehide', function() {

        sellerAvgRate.raty('destroy');
        rateSellerBox.raty('destroy');

      });

    }
  };
});
<commit_msg>Removing unneeded watcher!<commit_after>'use strict';

angular.module('eMarketApp').directive('sellerProfile', function(Restangular, SellerInfo, User, Helper) {
  return {
    templateUrl: 'views/sellerProfile.html',
    restrict: 'E',
    scope: {},
    replace: true,
    controller: function($scope, Product) {

      $scope.setItem = Product.setItem;

    },
    link: function(scope, elem) {

      var page = $(elem[0]);

      var sellerProductList = page.find('#sellerProfile-sellerProductList');
      var sellerRatingList = page.find('#sellerProfile-sellerRatingList');

      var sellerAvgRate = page.find('#sellerProfile-sellerAvgRate');
      var rateSellerBox = page.find('#sellerProfile-rateSeller');

      page.on('pagebeforeshow', function() {

        Restangular.one('users', SellerInfo.sellerId).getList('unsoldProducts').then(function(products) {
          scope.products = products;
          Helper.refreshList(sellerProductList);
        });

        scope.sellerName = SellerInfo.sellerName;
        scope.sellerAvgRate = SellerInfo.sellerAvgRate;

        setTimeout(function() {

          sellerAvgRate.raty({
            score: function() {
              return $(this).attr('data-score');
            },
            size: 12,
            readOnly: true,
            path: '../lib/raty/lib/img'
          });

          rateSellerBox.raty({
            size: 16,
            path: '../lib/raty/lib/img',
            click: function() {
              var score = $(this).raty('score');
              console.log('clicked star', $(this).raty('score'));
              Restangular.one('users', SellerInfo.sellerId).all('ratings')
                  .post({ratedId: SellerInfo.sellerId, raterId: User.userId, value: score});
            }
          });

          Helper.refreshList(sellerRatingList);

        });

      });

      page.on('pagehide', function() {

        sellerAvgRate.raty('destroy');
        rateSellerBox.raty('destroy');

      });

    }
  };
});
<|endoftext|>


<commit_before>import React from 'react';
import Relay from 'react-relay';
import DocumentTitle from 'react-document-title';

import Icon from '../shared/Icon';
import Panel from '../shared/Panel';
import PageHeader from '../shared/PageHeader';
import Spinner from '../shared/Spinner';

class SSOIndex extends React.PureComponent {
  static propTypes = {
    organization: React.PropTypes.shape({
      name: React.PropTypes.string.isRequired,
      slug: React.PropTypes.string.isRequired,
      sso: React.PropTypes.object
    }).isRequired,
    relay: React.PropTypes.object.isRequired
  };

  componentDidMount() {
    this.props.relay.forceFetch({ isMounted: true });
  }

  render() {
    return (
      <DocumentTitle title={`SSO · ${this.props.organization.name}`}>

          {/* this is a custom PageHeader body. *
            * you may not like it,              *
            * but this is what that looks like  */}

              <Icon
                icon="sso"
                className="align-middle mr2"
                style={{ width: 40, height: 40 }}
              />

              <PageHeader.Title>
                Single Sign On
              </PageHeader.Title>
              <PageHeader.Description>
                SSO enables you to automatically onboard users without having to manually invite them via email. SSO is available via SAML (Okta, Bitium, etc) or Google Apps (GSuite).
              </PageHeader.Description>

          {this.renderDetailsPanel()}

      </DocumentTitle>
    );
  }

  renderDetailsPanel() {
    if (!this.props.organization.sso) {
      return (
        <Panel>
          <Panel.Section className="center">
            <Spinner />
          </Panel.Section>
        </Panel>
      );
    }

    if (this.props.organization.sso.isEnabled) {
      return (
        <Panel>
          <Panel.Section>

✔ SSO has been enabled for your organization using {this.props.organization.sso.provider.name}. Users will be automatically added to your organization when they successfully authenticate using {this.props.organization.sso.provider.name} and their {this.props.organization.sso.provider.emailDomain} email address.

If you need to update your SSO settings or have it disabled, please get in touch with Buildkite Support.

          </Panel.Section>
        </Panel>
      );
    } else {
      return (
        <Panel>
          <Panel.Section>

SSO has not yet been enabled for your organization.

If you want to find out more about SSO or have it enabled, please get in touch with Buildkite Support.

          </Panel.Section>
        </Panel>
      );
    }
  }
}

export default Relay.createContainer(SSOIndex, {
  initialVariables: {
    isMounted: false
  },

  fragments: {
    organization: () => Relay.QL`
      fragment on Organization {
        name
        slug
        sso @include(if: $isMounted) {
          isEnabled
          provider {
            name
            ...on SSOProviderGoogle {
              emailDomain
            }
            ...on SSOProviderSAML {
              emailDomain
            }
          }
        }
      }
    `
  }
});
<commit_msg>Update text on SSO page<commit_after>import React from 'react';
import Relay from 'react-relay';
import DocumentTitle from 'react-document-title';

import Button from '../shared/Button';
import Icon from '../shared/Icon';
import Panel from '../shared/Panel';
import PageHeader from '../shared/PageHeader';
import Spinner from '../shared/Spinner';

class SSOIndex extends React.PureComponent {
  static propTypes = {
    organization: React.PropTypes.shape({
      name: React.PropTypes.string.isRequired,
      slug: React.PropTypes.string.isRequired,
      sso: React.PropTypes.object
    }).isRequired,
    relay: React.PropTypes.object.isRequired
  };

  componentDidMount() {
    this.props.relay.forceFetch({ isMounted: true });
  }

  render() {
    return (
      <DocumentTitle title={`SSO · ${this.props.organization.name}`}>

          {/* this is a custom PageHeader body. *
            * you may not like it,              *
            * but this is what that looks like  */}

              <Icon
                icon="sso"
                className="align-middle mr2"
                style={{ width: 40, height: 40 }}
              />

              <PageHeader.Title>
                Single Sign On
              </PageHeader.Title>
              <PageHeader.Description>
                Manage your organization’s Single Sign On settings
              </PageHeader.Description>

          {this.renderDetailsPanel()}

      </DocumentTitle>
    );
  }

  renderLoginLink() {
    const url = `/login?org=${this.props.organization.slug}`;

    return {url};
  }

  renderDetailsPanel() {
    if (!this.props.organization.sso) {
      return (
        <Panel>
          <Panel.Section className="center">
            <Spinner />
          </Panel.Section>
        </Panel>
      );
    }

    if (this.props.organization.sso.isEnabled) {
      return (
        <Panel>
          <Panel.Section>

Single Sign On is enabled using {this.props.organization.sso.provider.name}

Anyone with {this.props.organization.sso.provider.emailDomain} email address address can login to Buildkite by entering their email address on the login page.

Your organization specific login URL is: {this.renderLoginLink()}

          </Panel.Section>
        </Panel>
      );
    } else {
      return (

          <Panel>
            <Panel.Section>

Single Sign On allows you require users to login to Buildkite using your own third-party authentication server. Once enabled, you’ll no longer have to invite users, as they’ll be automatically added to your organization when they go to login.

Supported SSO systems:

Bitium

Okta

Google Apps

SAML

ADFS (SAML)

              <Button href="mailto:support@buildkite.com?subject=Please enable SSO for my account!">Contact Support to Enable SSO</Button>
            </Panel.Section>
          </Panel>
          <Panel className="mt4">
            <Panel.Section>

Frequently Asked SSO Questions

How does user billing work with SSO?

When a user signs in with SSO, the additional user is added to your account and will be charged immediately, just as if you had invited them to the account.

What type of encryption is supported?

We support AE256 and all types of great encryption. In addition, you can use the ROT13 algorithm for extra security.

Can I use multiple email domains?

We currently only support a single email domain (e.g. example.com) for an organization.

Can I set up SSO for additional organizations?

We support setting up SSO for additional organizations, but one of the organizations will be the default. To login to the secondary organizations, you can add ?asd to your organization’s login URL.

            </Panel.Section>
          </Panel>

      );
    }
  }
}

export default Relay.createContainer(SSOIndex, {
  initialVariables: {
    isMounted: false
  },

  fragments: {
    organization: () => Relay.QL`
      fragment on Organization {
        name
        slug
        sso @include(if: $isMounted) {
          isEnabled
          provider {
            name
            ...on SSOProviderGoogle {
              emailDomain
            }
            ...on SSOProviderSAML {
              emailDomain
            }
          }
        }
      }
    `
  }
});
<|endoftext|>