<commit_before>const list = `
abits
acx
aex.com
allcoin.com
appreciater
apreciator
ausbitban
ausbltbank
battrex
bbittrex
bcex
bellyrub
berniesandlers
bernieslanders
berniestandards
bernlesanders
bettrex
biitrex
biittrex
binan
binanc
binance
binance.com
binanced
binancee
binances
binanse
binnance
bit-z
bitex
bitfinex
bitfinex.com
bitfinix
bitflip
bithumb
bithumb.com
bitifinex
bitkrx
bitnaru
bitre
bitreex
bitrex
bitrexx
bitrix
bitrrex
bitrtex
bitrx
bitsane
bitsane.com
bitstamp
bitstamp.net
bitt
bitteex
bitter
bitterex
bitterx
bittex
bitthai
bittr
bittrax
bittre
bittrec
bittrecs
bittred
bittreex
bittrek
bittres
bittresx
bittret
bittrev
bittrex-deposit
bittrex.com
bittrexchange
bittrexe
bittrexs
bittrext
bittrexx
bittrexxx
bittrez
bittrix
bittrrex
bittrrx
bittrx
bittrxe
bitttec
bitttex
bitttrex
bittylicious
bittylicious.com
blcktrades
blcoktrades
bleutrade
bleutrade.com
block-trades
block-trades-com
blockrade
blockrades
blockrtades
blocktades
blocktardes
blocktraades
blocktrad
blocktrade
blocktraded
blocktradee
blocktradees
blocktrader
blocktraders
blocktrades-com
blocktrades-info
blocktrades-us
blocktrades.com
blocktrades.info
blocktrades.us
blocktradess
blocktradesss
blocktradez
blocktrading
blocktrads
blocktradse
blocktraeds
blocktraes
blocktrdaes
blocktrdes
blocktredes
blockttrades
bloctkrades
bloctrades
blokctrades
bloktrades
bloocktrades
bocktrades
bolcktrades
bomerang
boooster
boostar
booste
boosterr
boostr
boostre
boostter
boster
btc38
btc-alpha
btc-alpha.com
btcalpha
btcmarkets
btcmarkets.net
btitrex
btrex
bttrex
bttrx
buildawale
buildawhile
buildwhale
c-cex
c-cex.com
canadiancoconut
ccex
cexio
changellly
changelly.com
changely
coin-room
coinbas
coinbase
coinbase.com
coinbased
coinegg
coinegg.com
coinpayment
coinpayments
coinpia
coinroom.com
coinsmarkets
coinsmarkets.com
coinspot
coinzest
community-coin
coolcoin.com
curi
curied
curies
curing
d-tube
dcrypto8
decrypto8
deep8
deepcripto8
deepcrpto8
deepcrypo8
deepcrypt8
deepcrypto0
deepcrypto7
deepcrypto9
deepcrypto88
deepcrypto-8
deepcryptoo8
deepcryptos
deepcryptos8
deepcryto8
deepcrytpo8
deepcypto8
deeprypto8
depcrypto8
donkeypon
eepcrypto8
etherdelta
etherdelta.com
exrates
exx.com
freeewallet
freewalet.org
freewaller
frewallet
fyrstiken
gatecoin.com
gatehub
gatehub.net
gdax.com
gemini.com
gtg.witnesses
hitbtc.com
hitbtcexchange
huobi.pro
idex.market
inance
ittrex
ittrexx
kcx
kevinwon
kocostock
koinex
kraken
kraken.com
kucoi
kucoin
kucoinn
kucoins
linkcoin
litebit
little-pepper
livecoin.com
livecoinnet
livingroomofsato
localtrade
localtrade.pro
locktrades
mercatox.com
minnnowbooster
minnobooster
minnooboster
minnoowbooster
minnowboooster
minnowboost
minnowbooste
minnowboosted
minnowboosteer
minnowboosterr
minnowboosters
minnowboostr
minnowboostre
minnowbootser
minnowboster
minnowbuster
minnowhelp
minnowpooster
minnows
minnowsuport
minnowsupports
minnowwbooster
minobooster
minowbooster
minowboster
minowhelper
minowsupport
myupblt
neraex
neraex.com
nextgencrypted
nextgencryptos
okex.com
olonie
oloniex
openledgerdex
p-funk
paloniex
paypals
pextokens
pfuck
piloniex
plolniex
ploniex
plooniex
pokoniex
polaniex
poleniex
poliniex
polionex
pollniex
polloniex
polloniexx
pollonix
polniex
polnoiex
polobiex
poloex
poloiex
poloinex
pololniex
polomiex
polon
poloneex
poloneiex
poloneix
polonex
poloni
poloniax
polonie
poloniec
poloniecs
polonied
poloniee
polonieex
poloniek
polonieks
polonies
poloniet
poloniets
poloniew
poloniex.com
poloniexcold
poloniexcom
poloniexe
poloniexs
poloniext
poloniexwalle
poloniexwallet
poloniexx
poloniexxx
poloniey
poloniez
poloniiex
poloniix
poloniks
poloniox
polonium
polonix
polonixe
polonixx
polonniex
polonoiex
polonox
polonx
polonyex
polooniex
poluniex
pononiex
poolniex
pooloniex
pooniex
poooniex
poponiex
postpromote
postpromotor
pse
ptunk
puloniex
qryptos
qryptos.com
randomwhale
randowale
randowhal
randwhale
rendowhale
scoin
shapeshif
shapeshift
steampunks
steemitpay
steempay
steempays
steemupbit
sweetsj
sweetssj
sweetsss
sweetsssjs
sweetssssj
swetsssj
tdax
tdax.com
teamsteam
techno-comanche
technocommander
thealien
thebiton
therocktrading
tidex.com
topbtc
ttrex
upbbit
upbi
upbit
upbit.com
upbits
upbitt
upblt
upm
upmee
uppme
uppmee
viabtc
vittrex
wallet.bitshares
whaleshare
www.aex.com
www.binance.com
www.bit-z.com
www.bitfinex.com
www.bithumb.com
www.bitstamp.net
www.bittrex.com
www.coinbase.com
www.coinegg.com
www.coolcoin.com
www.exx.com
www.gatecoin.com
www.gatehub.net
www.gdax.com
www.huobi.pro
www.kraken.com
www.livecoin.net
www.okex.com
www.poloniex.com
www.qryptos.com
www.xbtce.com
xbtce.com
yobit
yobit.net
youbit
yunbi
zeniex
`
    .trim()
    .split('\n');

export default list;
<commit_msg>Update BadActorList.js (#2912)<commit_after>const list = `
abits
acx
aex.com
allcoin.com
appreciater
appreiator
apreciator
ausbitban
ausbltbank
battrex
bbittrex
bbuildawhale
bcex
bellyrub
berniesandlers
bernieslanders
berniestandards
bernlesanders
bettrex
biitrex
biittrex
binan
binanc
binance
binance.com
binanced
binancee
binances
binanse
binnance
bitex
bitfinex
bitfinex.com
bitfinix
bitflip
bithumb
bithumb.com
bitifinex
bitkrx
bitnaru
bitre
bitreex
bitrex
bitrexx
bitrix
bitrrex
bitrtex
bitrx
bitsane
bitsane.com
bitstamp
bitstamp.net
bitt
bitteex
bitter
bitterex
bitterx
bittex
bitthai
bittr
bittrax
bittre
bittrec
bittrecs
bittred
bittreex
bittrek
bittres
bittresx
bittret
bittrev
bittrexchange
bittrex.com
bittrex-deposit
bittrexe
bittrexs
bittrext
bittrexx
bittrexxx
bittrez
bittrix
bittrrex
bittrrx
bittrx
bittrxe
bitttec
bitttex
bitttrex
bittylicious
bittylicious.com
bit-z
blcktrades
blcoktrades
bleutrade
bleutrade.com
blockrade
blockrades
blockrtades
blocktades
blocktardes
blocktraades
blocktrad
blocktrade
blocktraded
blocktradee
blocktradees
blocktrader
blocktraders
block-trades
block-trades-com
blocktrades-com
blocktrades.com
blocktrades-info
blocktrades.info
blocktradess
blocktradesss
blocktrades-us
blocktrades.us
blocktradez
blocktrading
blocktrads
blocktradse
blocktraeds
blocktraes
blocktrdaes
blocktrdes
blocktredes
blockttrades
bloctkrades
bloctrades
blokctrades
bloktrades
bloocktrades
bocktrades
bolcktrades
bomerang
boomeang
boooster
boostar
booste
boosterr
boostr
boostre
boostter
boster
btc38
btcalpha
btc-alpha
btc-alpha.com
btcmarkets
btcmarkets.net
btitrex
btrex
bttrex
bttrx
buildawahle
buildawale
buildawhile
buildwhale
canadiancoconut
ccex
c-cex
c-cex.com
cexio
changellly
changelly.com
changely
coinbas
coinbase
coinbase.com
coinbased
coinegg
coinegg.com
coinpamyents.net
coinpayment
coinpayments
coinpia
coin-room
coinroom.com
coinsmarkets
coinsmarkets.com
coinspot
coinzest
community-coin
coolcoin.com
curi
curied
curies
curing
dcrypto8
decrypto8
deep8
deepcripto8
deepcrpto8
deepcrypo8
deepcryppto8
deepcrypt8
deepcrypto0
deepcrypto7
deepcrypto-8
deepcrypto88
deepcrypto9
deepcryptoo8
deepcryptos
deepcryptos8
deepcryto8
deepcrytpo8
deepcypto8
deeprypto8
depcrypto8
donkeypon
d-tube
eepcrypto8
etherdelta
etherdelta.com
exrates
exx.com
freeewallet
freewalet.org
freewaller
frewallet
fyrstiken
gatecoin.com
gatehub
gatehub.net
gdax.com
gemini.com
gtg.witnesses
hitbtc.com
hitbtcexchange
huobi.pro
idex.market
inance
ittrex
ittrexx
kcx
kevinwon
kocostock
koinex
kraken
kraken.com
kucoi
kucoin
kucoinn
kucoins
linkcoin
litebit
little-pepper
livecoin.com
livecoinnet
livingroomofsato
localtrade
localtrade.pro
locktrades
mercatox.com
minnnowbooster
minnobooster
minnooboster
minnoowbooster
minnowboooster
minnowboost
minnowbooste
minnowboosted
minnowboosteer
minnowboosterr
minnowboosters
minnowboostr
minnowboostre
minnowbootser
minnowboster
minnowbuster
minnowhelp
minnowpooster
minnows
minnowsuport
minnowsupports
minnowwbooster
minobooster
minowbooster
minowboster
minowhelper
minowsupport
myupblt
myuupbit
neraex
neraex.com
nextgencrypted
nextgencryptos
okex.com
olonie
oloniex
openledgerdex
paloniex
paypals
pextokens
pfuck
p-funk
piloniex
plolniex
ploniex
plooniex
pokoniex
polaniex
poleniex
poliniex
polionex
pollniex
polloniex
polloniexx
pollonix
polniex
polnoiex
polobiex
poloex
poloiex
poloinex
pololniex
polomiex
polon
poloneex
poloneiex
poloneix
polonex
poloni
poloniax
polonie
poloniec
poloniecs
polonied
poloniee
polonieex
poloniek
polonieks
polonies
poloniet
poloniets
poloniew
poloniexcold
poloniexcom
poloniex.com
poloniexe
poloniexs
poloniext
poloniexwalle
poloniexwallet
poloniexx
poloniexxx
poloniey
poloniez
poloniiex
poloniix
poloniks
poloniox
polonium
polonix
polonixe
polonixx
polonniex
polonoiex
polonox
polonx
polonyex
polooniex
poluniex
pononiex
poolniex
pooloniex
pooniex
poooniex
poponiex
postpromote
postpromotor
prmoobot
pse
ptunk
puloniex
qryptos
qryptos.com
randomwhale
randowale
randowhal
randwhale
rcky1
rendowhale
rockyy1
scoin
shapeshif
shapeshift
steampunks
steemi2t
steemitpay
steempay
steempays
steemti2
steemupbit
stteemit2
sweetsj
sweetssj
sweetsss
sweetsssjs
sweetssssj
swetsssj
tdax
tdax.com
teamsteam
techno-comanche
technocommander
thealien
thebiton
therocktrading
thersing
tidex.com
topbtc
ttrex
upbbit
upbi
upbit
upbit.com
upbits
upbitt
upblt
upm
upmee
uppme
uppmee
viabtc
vittrex
wallet.bitshares
whaleshare
www.aex.com
www.binance.com
www.bitfinex.com
www.bithumb.com
www.bitstamp.net
www.bittrex.com
www.bit-z.com
www.coinbase.com
www.coinegg.com
www.coolcoin.com
www.exx.com
www.gatecoin.com
www.gatehub.net
www.gdax.com
www.huobi.pro
www.kraken.com
www.livecoin.net
www.okex.com
www.poloniex.com
www.qryptos.com
www.xbtce.com
xbtce.com
yobit
yobit.net
youbit
yunbi
zenieix
`
    .trim()
    .split('\n');

export default list;
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import _ from 'lodash';
import moment from 'moment';
import spahql from 'spahql';
import MasonryCtl from 'react-masonry-component';
import Radium from 'radium';
import { connect } from 'react-redux';
import { ActionCreators } from 'redux-undo';
import DashboardComponentSmall from '../components/DashboardComponentSmall';
import DashboardMediumGraph from '../components/DashboardMediumGraph';
import ReactGridLayout from 'react-grid-layout';
import Paper from 'material-ui/lib/paper';
import Styles from 'material-ui/lib/styles';
import Card from 'material-ui/lib/card/card';
import CardHeader from 'material-ui/lib/card/card-header';
import CardTitle from 'material-ui/lib/card/card-title';
import CardMedia from 'material-ui/lib/card/card-media';
import CardText from 'material-ui/lib/card/card-text';
import CardActions from 'material-ui/lib/card/card-actions';
import TextField from 'material-ui/lib/text-field';
import Avatar from 'material-ui/lib/avatar';
import Dialog from 'material-ui/lib/dialog';
import Toolbar from 'material-ui/lib/toolbar/toolbar';
import ToolbarGroup from 'material-ui/lib/toolbar/toolbar-group';
import ToolbarSeparator from 'material-ui/lib/toolbar/toolbar-separator';
import ToolbarTitle from 'material-ui/lib/toolbar/toolbar-title';
import FlatButton from 'material-ui/lib/flat-button';
import RaisedButton from 'material-ui/lib/raised-button';
import IconButton from 'material-ui/lib/icon-button';
import CircularProgress from 'material-ui/lib/circular-progress';
import Editor from 'react-medium-editor';
import { Grid, Row, Col } from 'react-bootstrap';
//import 'react-medium-editor/node_modules/medium-editor/dist/css/medium-editor.css';
//import 'react-medium-editor/node_modules/medium-editor/dist/css/themes/default.css';
import { updateClassAttendance, updateNote, addNote, updateClassAttendanceLocal } from '../actions';
let Masonry = MasonryCtl(React);

@Radium
class Dashboard extends Component {
  constructor(props) {
    super(props);
  }

  resize() {
    _.throttle(() => {
      const { masonryOptions } = this.state;
      const graphDiv = this.refs.graphDiv;
      //console.log(graphDiv.clientWidth);
      masonryOptions.updated = true;
      this.setState({
          sparklineWidth: graphDiv.offsetWidth - 40
      });
    }, 30)
  }

  componentDidMount() {
    window.addEventListener('resize', this.resize);
  }

  componentWillReceiveProps(nextProps) {
    //console.log("componentWillReceiveProps", nextProps);
  }

  componentWillMount() {
    const { dispatch, configs } = this.props;
    let db = spahql.db(configs.data),
        today = moment().weekday(),
        attendanceDay = db.select("/*/classMeetingDays/*[/day == "+today+"]").value();

    this.delayedAttendanceUpdate = _.debounce(function (divClass, count, event) {
      //console.log(divClass, event.target.value, attendanceDay);
      dispatch(updateClassAttendance(divClass.id, today, moment().format('YYYY-MM-DD 00:00:00'), count));
    }, 500);

    this.delayedNoteUpdate = _.debounce(function (note, changes) {
      dispatch(updateNote(note, changes));
    }, 500);

    this.setState({
      sparklineWidth: 100,
      attendanceDay: attendanceDay,
      displayAttendance: this.displayAttendance(),
      showDialog: false,
      currentNote: {
        id: null,
        title: null,
        text: null
      },
      masonryOptions: {}
    });
  }

  handleAttendanceUpdate() {
    let currentValue = select(store.getState());
    //console.log("handleAttendance", currentValue);
  }

  displayAttendance() {
    const { configs } = this.props;
    let db = spahql.db(configs.data),
        today = moment().weekday(),
        classDay = db.select("/*/classMeetingDays/*[/day == "+today+"]").value();
    if (!Array.isArray(classDay) && classDay !== null) {
      classDay = [classDay];
    } else if (classDay === null) {
      classDay = [];
    }
    let results = classDay.map(function(day, index){
      let config = db.select("/*[/id == "+day.divisionConfigId+"]"),
          classes = db.select("/*[/id == "+day.divisionConfigId+"]/divisionYears/0/divisions/0/divisionClasses");
      day.classes = classes.value();
      day.config = config.value();
    });
    return classDay;
  }

  attendanceUpdate(divClass, e) {
    const { dispatch } = this.props,
          { attendanceDay } = this.state,
          db = spahql.db(divClass),
          attendance = db.select("//divisionClassAttendances/*[/attendanceDate =~ '^"+moment().format("YYYY-MM-DD")+"']"),
          exists = attendance.values.length,
          count = parseInt(e.target.value, 10);
    let attend = {},
        today = moment().format("YYYY-MM-DD")+"T00:00:00.000Z";
    e.persist();
    if (!exists) {
      attend = {
        attendanceDate: today,
        count: count,
        createdAt: today,
        day: moment().weekday(),
        deletedAt: null,
        divisionClassId: divClass.id,
        id: null,
        revision: null,
        updatedAt: today,
        updating: true
      }
      divClass.divisionClassAttendances.unshift(attend);
    } else {
      attendance.values[0].count = count;
      attendance.values[0].updating = true;
    }
    dispatch(updateClassAttendanceLocal(divClass));
    this.delayedAttendanceUpdate(divClass, count, e);
  }

  getClassAttendance(divClass) {
    let db = spahql.db(divClass),
        attendance = db.select("//divisionClassAttendances/*[/attendanceDate =~ '^"+moment().format("YYYY-MM-DD")+"']").values(),
        isToday = false;
    //console.log("getClassAttendance", divClass, attendance);
    if (attendance) {
      isToday = moment.utc(attendance[0].attendanceDate, "YYYY-MM-DDTHH:mm:ss.SSSZ").isSame(moment(), 'day');
      if (isToday) {
        return attendance.toString();
      } else {
        return "0";
      }
    } else {
      return "0";
    }
  }

  getGraphAttendance() {
    const { attendance } = this.props;
    let labels = attendance.data.latest.map(function(day, index){
          return moment(day.attendanceDate, "YYYY-MM-DD HH:mm:ss").format("MM/DD");
        }).reverse(),
        series = attendance.data.latest.map(function(day, index){
          return parseInt(day.attendance,10);
        }).reverse();
    //console.log("graphAttendance", labels, series);
    return {
      labels: labels,
      series: [series]
    };
  }

  isUpdating(divClass) {
    if (divClass.divisionClassAttendances.length && "updating" in divClass.divisionClassAttendances[0]) {
      console.log("isUpdating", true);
      return true;
    } else {
      console.log("isUpdating", false);
      return false;
    }
  }

  handleCardTouchTap(note, e) {
    this.setState({
      currentNote: note,
      showDialog: true
    });
  }

  handleDialogClose(e) {
    const { dispatch } = this.props;
    if (!this.state.currentNote.id) {
      let title = (this.refs.title.getValue().length) ? this.refs.title.getValue() : null;
      this.setState({
        currentNote: {
          id: this.state.currentNote.id,
          text: this.state.currentNote.text,
          title: title
        }
      });
      dispatch(
        addNote(
          this.state.currentNote
        )
      );
    }
    this.setState({
      showDialog: false
    });
  }

  handleEditorChange(text) {
    if (this.state.currentNote.id) {
      this.delayedNoteUpdate(this.state.currentNote, {text: text});
    } else {
      this.setState({
        currentNote: {
          id: this.state.currentNote.id,
          text: text,
          title: this.state.currentNote.title
        }
      });
    }
  }

  handleTitleChange(e) {
    let title = (this.refs.title.getValue().length) ? this.refs.title.getValue() : null;
    if (this.state.currentNote.id) {
      this.delayedNoteUpdate(this.state.currentNote, {title: title});
    } else {
      this.setState({
        currentNote: {
          id: this.state.currentNote.id,
          text: this.state.currentNote.text,
          title: title
        }
      });
    }
  }

  handleNewNote(e) {
    this.setState({
      currentNote: {
        id: null,
        title: null,
        text: null
      },
      showDialog: true
    });
  }

  handleNoteDelete(e) {
    e.stopPropagation();
    console.log("Delete", e);
  }

  highlightText(e) {
    if (e) {
      e.target.select();
    }
  }

  render() {
    const { dispatch, configs, attendance, notes, ...props } = this.props;
    const { masonryOptions, displayAttendance } = this.state;
    let paperStyle = {
          display: 'flex',
          flexDirection: 'row',
          alignItems: 'center',
          justifyContent: 'center',
          height: '75px',
          backgroundColor: Styles.Colors.cyan300,
          color: 'white'
        },
        grid = {
          className: "layout",
          isDraggable: false,
          isResizable: false,
          cols: 12,
          rowHeight: 50
        },
        lineChartOptions = {
          low: 0,
          showArea: true
        },
        customActions = [
          <FlatButton
            key={0}
            label="Done"
            primary={true}
            onTouchTap={::this.handleDialogClose} />
        ],
        halogenContainer = {
          height: "25px",
          width: "25px"
        },
        halogen = {
          color: '#4DAF7C',
          size: '8px'
        };
    return (

        <Grid fluid={true}>
          {displayAttendance.map((attendance, index) =>
            <Row key={attendance.id}>
              <Col xs={12} sm={12} md={12} lg={12}>
                <Card>
                  <CardHeader
                    title={attendance.config.title+" Attendance"}
                    subtitle={moment().format("dddd MM/DD/YYYY")}
                    avatar={<Avatar>{moment().format("dd")}</Avatar>}>
                  </CardHeader>
                  <CardMedia>
                    <Grid fluid={true}>
                      {attendance.classes.map((divClass, index) =>
                        <Col style={{display: "flex", alignItems: "center", justifyContent: "center"}} key={divClass.id} xs={12} sm={6} md={4} lg={3}>

                            <TextField
                              type="number"
                              hintText="Enter attendance"
                              value={::this.getClassAttendance(divClass)}
                              min="0"
                              max="500"
                              ref={"inputAttendance"+divClass.id}
                              onFocus={((...args)=>this.highlightText(...args))}
                              onChange={((...args)=>this.attendanceUpdate(divClass, ...args))}
                              floatingLabelText={divClass.class.title} />

<CircularProgress style={{display: (this.isUpdating(divClass)) ? "block" : "none"}} size={0.35} mode="indeterminate" />

                        </Col>
                      )}
                    </Grid>
                  </CardMedia>
                </Card>
              </Col>
            </Row>
          )}
          <Masonry className={"row"} options={masonryOptions}>
            <Col xs={12} sm={12} md={6} lg={6}>
              <DashboardMediumGraph
                title={"Attendance"}
                subtitle={"Past 8 weeks"}
                avatar={<Avatar>A</Avatar>}
                lineChartData={::this.getGraphAttendance()}
                lineChartOptions={lineChartOptions}
              />
            </Col>
            <Col xs={12} sm={12} md={6} lg={6}>
              <Toolbar>
                <ToolbarGroup key={0} float="left">
                  <ToolbarTitle text="Notes" />
                </ToolbarGroup>
                <ToolbarGroup key={1} float="right">
                  <RaisedButton
                    label="Add Note"
                    primary={true}
                    onTouchTap={::this.handleNewNote}
                  />
                </ToolbarGroup>
              </Toolbar>
              <Masonry>
                {notes.data.map((note, index) =>
                  <Col key={note.id} xs={12} sm={6} md={6} lg={6} key={index}>
                    <Card>
                      <CardTitle title={note.title} style={(note.title) ? null : {display: 'none'}} />
                      <CardText onClick={((...args)=>this.handleCardTouchTap(note, ...args))}>

                      </CardText>
                      <CardActions style={{float: "right"}}>
                        <IconButton
                          iconClassName="material-icons"
                          tooltipPosition="top-center"
                          tooltip="Delete"
                          onTouchTap={::this.handleNoteDelete}>
                            delete
                        </IconButton>
                      </CardActions>
                    </Card>
                  </Col>
                )}
              </Masonry>
            </Col>
            <Col xs={6} sm={4} md={3} lg={3}>
              <DashboardComponentSmall
                zDepth={1}
                sparkLineData={[5, 10, 5, 20, 5, 30, 25, 10, 18, 32, 22, 28, 30, 21, 45, 29, 33, 18, 10, 15]}
                title={"Avg. Attendance"}
                body={attendance.data.average[0].attendance.toFixed(2)}
                style={paperStyle}
              />
            </Col>
          </Masonry>
        </Grid>
        <Dialog
          title={
            <TextField
              style={{margin: "25px"}}
              ref="title"
              hintText="Title"
              onChange={::this.handleTitleChange}
              defaultValue={this.state.currentNote.title} />
          }
          actions={customActions}
          autoDetectWindowHeight={true}
          autoScrollBodyContent={true}
          open={this.state.showDialog}
          onRequestClose={::this.handleDialogClose}>
          <Editor
            className="editor"
            ref="editor"
            text={this.state.currentNote.text}
            onChange={::this.handleEditorChange}
            options={{toolbar: {buttons: ['bold', 'italic', 'underline', 'unorderedlist']}}}
          />
        </Dialog>

    );
  }
}

Dashboard.propTypes = {
  dispatch: PropTypes.func.isRequired
};

const styles = {
  noteSmall: {
    width: '48%',
    paddingRight: '2%',
    paddingBottom: '1.5em',
    '@media (max-width: 839px)': {
      paddingRight: '0',
      width: '100%'
    }
  },
  smallCell: {
    width: '31%',
    padding:'1% 2% 1% 0',
    '@media (min-width: 480px)': {
      padding: '0',
      width: '%'
    }
  }
};

function select(state) {
  return {
    configs: state.divisionConfigs.present,
    attendance: state.attendance.present,
    notes: state.notes.present
  };
}

export default connect(select)(Dashboard);
<commit_msg>debug<commit_after>import React, { Component, PropTypes } from 'react';
import _ from 'lodash';
import moment from 'moment';
import spahql from 'spahql';
import MasonryCtl from 'react-masonry-component';
import Radium from 'radium';
import { connect } from 'react-redux';
import { ActionCreators } from 'redux-undo';
import DashboardComponentSmall from '../components/DashboardComponentSmall';
import DashboardMediumGraph from '../components/DashboardMediumGraph';
import ReactGridLayout from 'react-grid-layout';
import Paper from 'material-ui/lib/paper';
import Styles from 'material-ui/lib/styles';
import Card from 'material-ui/lib/card/card';
import CardHeader from 'material-ui/lib/card/card-header';
import CardTitle from 'material-ui/lib/card/card-title';
import CardMedia from 'material-ui/lib/card/card-media';
import CardText from 'material-ui/lib/card/card-text';
import CardActions from 'material-ui/lib/card/card-actions';
import TextField from 'material-ui/lib/text-field';
import Avatar from 'material-ui/lib/avatar';
import Dialog from 'material-ui/lib/dialog';
import Toolbar from 'material-ui/lib/toolbar/toolbar';
import ToolbarGroup from 'material-ui/lib/toolbar/toolbar-group';
import ToolbarSeparator from 'material-ui/lib/toolbar/toolbar-separator';
import ToolbarTitle from 'material-ui/lib/toolbar/toolbar-title';
import FlatButton from 'material-ui/lib/flat-button';
import RaisedButton from 'material-ui/lib/raised-button';
import IconButton from 'material-ui/lib/icon-button';
import CircularProgress from 'material-ui/lib/circular-progress';
import Editor from 'react-medium-editor';
import { Grid, Row, Col } from 'react-bootstrap';
//import 'react-medium-editor/node_modules/medium-editor/dist/css/medium-editor.css';
//import 'react-medium-editor/node_modules/medium-editor/dist/css/themes/default.css';
import { updateClassAttendance, updateNote, addNote, updateClassAttendanceLocal } from '../actions';
let Masonry = MasonryCtl(React);

@Radium
class Dashboard extends Component {
  constructor(props) {
    super(props);
  }

  resize() {
    _.throttle(() => {
      const { masonryOptions } = this.state;
      const graphDiv = this.refs.graphDiv;
      //console.log(graphDiv.clientWidth);
      masonryOptions.updated = true;
      this.setState({
          sparklineWidth: graphDiv.offsetWidth - 40
      });
    }, 30)
  }

  componentDidMount() {
    window.addEventListener('resize', this.resize);
  }

  componentWillReceiveProps(nextProps) {
    //console.log("componentWillReceiveProps", nextProps);
  }

  componentWillMount() {
    const { dispatch, configs } = this.props;
    let db = spahql.db(configs.data),
        today = moment().weekday(),
        attendanceDay = db.select("/*/classMeetingDays/*[/day == "+today+"]").value();

    this.delayedAttendanceUpdate = _.debounce(function (divClass, count, event) {
      //console.log(divClass, event.target.value, attendanceDay);
      dispatch(updateClassAttendance(divClass.id, today, moment().format('YYYY-MM-DD 00:00:00'), count));
    }, 500);

    this.delayedNoteUpdate = _.debounce(function (note, changes) {
      dispatch(updateNote(note, changes));
    }, 500);

    this.setState({
      sparklineWidth: 100,
      attendanceDay: attendanceDay,
      displayAttendance: this.displayAttendance(),
      showDialog: false,
      currentNote: {
        id: null,
        title: null,
        text: null
      },
      masonryOptions: {}
    });
  }

  handleAttendanceUpdate() {
    let currentValue = select(store.getState());
    //console.log("handleAttendance", currentValue);
  }

  displayAttendance() {
    const { configs } = this.props;
    let db = spahql.db(configs.data),
        today = moment().weekday(),
        classDay = db.select("/*/classMeetingDays/*[/day == "+today+"]").value();
    if (!Array.isArray(classDay) && classDay !== null) {
      classDay = [classDay];
    } else if (classDay === null) {
      classDay = [];
    }
    let results = classDay.map(function(day, index){
      let config = db.select("/*[/id == "+day.divisionConfigId+"]"),
          classes = db.select("/*[/id == "+day.divisionConfigId+"]/divisionYears/0/divisions/0/divisionClasses");
      day.classes = classes.value();
      day.config = config.value();
    });
    return classDay;
  }

  attendanceUpdate(divClass, e) {
    const { dispatch } = this.props,
          { attendanceDay } = this.state,
          db = spahql.db(divClass),
          attendance = db.select("//divisionClassAttendances/*[/attendanceDate =~ '^"+moment().format("YYYY-MM-DD")+"']"),
          exists = attendance.values.length,
          count = parseInt(e.target.value, 10);
    let attend = {},
        today = moment().format("YYYY-MM-DD")+"T00:00:00.000Z";
    e.persist();
    if (!exists) {
      attend = {
        attendanceDate: today,
        count: count,
        createdAt: today,
        day: moment().weekday(),
        deletedAt: null,
        divisionClassId: divClass.id,
        id: null,
        revision: null,
        updatedAt: today,
        updating: true
      }
      divClass.divisionClassAttendances.unshift(attend);
    } else {
      attendance.values[0].count = count;
      attendance.values[0].updating = true;
    }
    dispatch(updateClassAttendanceLocal(divClass));
    this.delayedAttendanceUpdate(divClass, count, e);
  }

  getClassAttendance(divClass) {
    let db = spahql.db(divClass),
        attendance = db.select("//divisionClassAttendances/*[/attendanceDate =~ '^"+moment().format("YYYY-MM-DD")+"']").values(),
        isToday = false;
    console.log("getClassAttendance", divClass, attendance);
    if (attendance) {
      isToday = moment.utc(attendance[0].attendanceDate, "YYYY-MM-DDTHH:mm:ss.SSSZ").isSame(moment(), 'day');
      if (isToday) {
        return attendance.toString();
      } else {
        return "0";
      }
    } else {
      return "0";
    }
  }

  getGraphAttendance() {
    const { attendance } = this.props;
    let labels = attendance.data.latest.map(function(day, index){
          return moment(day.attendanceDate, "YYYY-MM-DD HH:mm:ss").format("MM/DD");
        }).reverse(),
        series = attendance.data.latest.map(function(day, index){
          return parseInt(day.attendance,10);
        }).reverse();
    //console.log("graphAttendance", labels, series);
    return {
      labels: labels,
      series: [series]
    };
  }

  isUpdating(divClass) {
    if (divClass.divisionClassAttendances.length && "updating" in divClass.divisionClassAttendances[0]) {
      console.log("isUpdating", true);
      return true;
    } else {
      console.log("isUpdating", false);
      return false;
    }
  }

  handleCardTouchTap(note, e) {
    this.setState({
      currentNote: note,
      showDialog: true
    });
  }

  handleDialogClose(e) {
    const { dispatch } = this.props;
    if (!this.state.currentNote.id) {
      let title = (this.refs.title.getValue().length) ? this.refs.title.getValue() : null;
      this.setState({
        currentNote: {
          id: this.state.currentNote.id,
          text: this.state.currentNote.text,
          title: title
        }
      });
      dispatch(
        addNote(
          this.state.currentNote
        )
      );
    }
    this.setState({
      showDialog: false
    });
  }

  handleEditorChange(text) {
    if (this.state.currentNote.id) {
      this.delayedNoteUpdate(this.state.currentNote, {text: text});
    } else {
      this.setState({
        currentNote: {
          id: this.state.currentNote.id,
          text: text,
          title: this.state.currentNote.title
        }
      });
    }
  }

  handleTitleChange(e) {
    let title = (this.refs.title.getValue().length) ? this.refs.title.getValue() : null;
    if (this.state.currentNote.id) {
      this.delayedNoteUpdate(this.state.currentNote, {title: title});
    } else {
      this.setState({
        currentNote: {
          id: this.state.currentNote.id,
          text: this.state.currentNote.text,
          title: title
        }
      });
    }
  }

  handleNewNote(e) {
    this.setState({
      currentNote: {
        id: null,
        title: null,
        text: null
      },
      showDialog: true
    });
  }

  handleNoteDelete(e) {
    e.stopPropagation();
    console.log("Delete", e);
  }

  highlightText(e) {
    if (e) {
      e.target.select();
    }
  }

  render() {
    const { dispatch, configs, attendance, notes, ...props } = this.props;
    const { masonryOptions, displayAttendance } = this.state;
    let paperStyle = {
          display: 'flex',
          flexDirection: 'row',
          alignItems: 'center',
          justifyContent: 'center',
          height: '75px',
          backgroundColor: Styles.Colors.cyan300,
          color: 'white'
        },
        grid = {
          className: "layout",
          isDraggable: false,
          isResizable: false,
          cols: 12,
          rowHeight: 50
        },
        lineChartOptions = {
          low: 0,
          showArea: true
        },
        customActions = [
          <FlatButton
            key={0}
            label="Done"
            primary={true}
            onTouchTap={::this.handleDialogClose} />
        ],
        halogenContainer = {
          height: "25px",
          width: "25px"
        },
        halogen = {
          color: '#4DAF7C',
          size: '8px'
        };
    return (

        <Grid fluid={true}>
          {displayAttendance.map((attendance, index) =>
            <Row key={attendance.id}>
              <Col xs={12} sm={12} md={12} lg={12}>
                <Card>
                  <CardHeader
                    title={attendance.config.title+" Attendance"}
                    subtitle={moment().format("dddd MM/DD/YYYY")}
                    avatar={<Avatar>{moment().format("dd")}</Avatar>}>
                  </CardHeader>
                  <CardMedia>
                    <Grid fluid={true}>
                      {attendance.classes.map((divClass, index) =>
                        <Col style={{display: "flex", alignItems: "center", justifyContent: "center"}} key={divClass.id} xs={12} sm={6} md={4} lg={3}>

                            <TextField
                              type="number"
                              hintText="Enter attendance"
                              value={::this.getClassAttendance(divClass)}
                              min="0"
                              max="500"
                              ref={"inputAttendance"+divClass.id}
                              onFocus={((...args)=>this.highlightText(...args))}
                              onChange={((...args)=>this.attendanceUpdate(divClass, ...args))}
                              floatingLabelText={divClass.class.title} />

<CircularProgress style={{display: (this.isUpdating(divClass)) ? "block" : "none"}} size={0.35} mode="indeterminate" />

                        </Col>
                      )}
                    </Grid>
                  </CardMedia>
                </Card>
              </Col>
            </Row>
          )}
          <Masonry className={"row"} options={masonryOptions}>
            <Col xs={12} sm={12} md={6} lg={6}>
              <DashboardMediumGraph
                title={"Attendance"}
                subtitle={"Past 8 weeks"}
                avatar={<Avatar>A</Avatar>}
                lineChartData={::this.getGraphAttendance()}
                lineChartOptions={lineChartOptions}
              />
            </Col>
            <Col xs={12} sm={12} md={6} lg={6}>
              <Toolbar>
                <ToolbarGroup key={0} float="left">
                  <ToolbarTitle text="Notes" />
                </ToolbarGroup>
                <ToolbarGroup key={1} float="right">
                  <RaisedButton
                    label="Add Note"
                    primary={true}
                    onTouchTap={::this.handleNewNote}
                  />
                </ToolbarGroup>
              </Toolbar>
              <Masonry>
                {notes.data.map((note, index) =>
                  <Col key={note.id} xs={12} sm={6} md={6} lg={6} key={index}>
                    <Card>
                      <CardTitle title={note.title} style={(note.title) ? null : {display: 'none'}} />
                      <CardText onClick={((...args)=>this.handleCardTouchTap(note, ...args))}>

                      </CardText>
                      <CardActions style={{float: "right"}}>
                        <IconButton
                          iconClassName="material-icons"
                          tooltipPosition="top-center"
                          tooltip="Delete"
                          onTouchTap={::this.handleNoteDelete}>
                            delete
                        </IconButton>
                      </CardActions>
                    </Card>
                  </Col>
                )}
              </Masonry>
            </Col>
            <Col xs={6} sm={4} md={3} lg={3}>
              <DashboardComponentSmall
                zDepth={1}
                sparkLineData={[5, 10, 5, 20, 5, 30, 25, 10, 18, 32, 22, 28, 30, 21, 45, 29, 33, 18, 10, 15]}
                title={"Avg. Attendance"}
                body={attendance.data.average[0].attendance.toFixed(2)}
                style={paperStyle}
              />
            </Col>
          </Masonry>
        </Grid>
        <Dialog
          title={
            <TextField
              style={{margin: "25px"}}
              ref="title"
              hintText="Title"
              onChange={::this.handleTitleChange}
              defaultValue={this.state.currentNote.title} />
          }
          actions={customActions}
          autoDetectWindowHeight={true}
          autoScrollBodyContent={true}
          open={this.state.showDialog}
          onRequestClose={::this.handleDialogClose}>
          <Editor
            className="editor"
            ref="editor"
            text={this.state.currentNote.text}
            onChange={::this.handleEditorChange}
            options={{toolbar: {buttons: ['bold', 'italic', 'underline', 'unorderedlist']}}}
          />
        </Dialog>

    );
  }
}

Dashboard.propTypes = {
  dispatch: PropTypes.func.isRequired
};

const styles = {
  noteSmall: {
    width: '48%',
    paddingRight: '2%',
    paddingBottom: '1.5em',
    '@media (max-width: 839px)': {
      paddingRight: '0',
      width: '100%'
    }
  },
  smallCell: {
    width: '31%',
    padding:'1% 2% 1% 0',
    '@media (min-width: 480px)': {
      padding: '0',
      width: '%'
    }
  }
};

function select(state) {
  return {
    configs: state.divisionConfigs.present,
    attendance: state.attendance.present,
    notes: state.notes.present
  };
}

export default connect(select)(Dashboard);
<|endoftext|>


<commit_before>/* @flow */

import React, { PureComponent } from 'react';

import type {
  NavigationScreenProp,
  NavigationState,
  NavigationRoute,
  NavigationAction,
} from '../TypeDefinition';

type Props = {
  screenProps?: {};
  navigation: NavigationScreenProp<NavigationRoute, NavigationAction>;
  component: ReactClass<*>;
};

let screenPropsWarningShown = false;

export default class SceneView extends PureComponent<void, Props, void> {
  static childContextTypes = {
    navigation: React.PropTypes.object.isRequired,
  };

  props: Props;

  getChildContext() {
    return {
      navigation: this.props.navigation,
    };
  }

  componentWillMount() {
    if (this.props.screenProps !== undefined && !screenPropsWarningShown) {
      console.warn(
        'Behaviour of screenProps has changed from initial beta. ' +
        'Components will now receive it as `this.props.screenProps` instead.\n' +
        'This warning will be removed in future.'
      );
      screenPropsWarningShown = true;
    }
  }

  render() {
    const {
      screenProps,
      navigation,
      component: Component,
    } = this.props;

    return (
      <Component
        screenProps={screenProps}
        navigation={navigation}
      />
    );
  }
}
<commit_msg>screen props warning removed<commit_after>/* @flow */

import React, { PureComponent } from 'react';

import type {
  NavigationScreenProp,
  NavigationState,
  NavigationRoute,
  NavigationAction,
} from '../TypeDefinition';

type Props = {
  screenProps?: {};
  navigation: NavigationScreenProp<NavigationRoute, NavigationAction>;
  component: ReactClass<*>;
};

export default class SceneView extends PureComponent<void, Props, void> {
  static childContextTypes = {
    navigation: React.PropTypes.object.isRequired,
  };

  props: Props;

  getChildContext() {
    return {
      navigation: this.props.navigation,
    };
  }

  render() {
    const {
      screenProps,
      navigation,
      component: Component,
    } = this.props;

    return (
      <Component
        screenProps={screenProps}
        navigation={navigation}
      />
    );
  }
}
<|endoftext|>


<commit_before>var fs = require('fs'),
	path = require('path'),
	util = require('./lib/util')

module.exports = {
	compile: compileFile,
	compileHTML: compileHTMLFile,
	compileCode: compileCode,
	dontAddClosureForModule: dontAddClosureForModule,
	dontIncludeModule: dontIncludeModule,
	addPath: addPath,
	addFile: addFile,
	addReplacement: addReplacement
}

var _ignoreClosuresFor = []
function dontAddClosureForModule(searchFor) {
	_ignoreClosuresFor.push(searchFor)
	return module.exports
}

var _ignoreModules = []
function dontIncludeModule(module) {
	_ignoreModules.push(module)
	return module.exports
}

function addReplacement(searchFor, replaceWith) {
	util.addReplacement.apply(util, arguments)
	return module.exports
}

function addPath() {
	util.addPath.apply(util, arguments)
	return module.exports
}

function addFile() {
	util.addFile.apply(util, arguments)
	return module.exports
}

/* api
 *****/
function compileFile(filePath, opts) {
	filePath = path.resolve(filePath)
	opts = util.extend(opts, { basePath:path.dirname(filePath), toplevel:true })
	var code = util.getCode(filePath)
	return _compile(code, opts, filePath)
}

function compileCode(code, opts) {
	opts = util.extend(opts, { basePath:process.cwd(), toplevel:true })
	return _compile(code, opts, '<code passed into compiler.compile()>')
}

function compileHTMLFile(filePath, opts) {
	var html = fs.readFileSync(filePath).toString()
	while (match = html.match(/<script src="\/require\/([\/\w\.]+)"><\/script>/)) {
		var js = compileFile(match[1].toString(), opts)

		var BACKREFERENCE_WORKAROUND = '____________backreference_workaround________'
		js = js.replace('\$\&', BACKREFERENCE_WORKAROUND)
		html = html.replace(match[0], '<script>'+js+'</script>')
		html = html.replace(BACKREFERENCE_WORKAROUND, '\$\&')
	}
	return html
}

var _compile = function(code, opts, mainModule) {
	var code = 'var __require__ = {}\n' + _compileModule(code, opts.basePath, mainModule)
	if (opts.minify === false) { return code } // TODO use uglifyjs' beautifier?

	if (opts.max_line_length == null) {
		opts.max_line_length = 200
	}

	var uglifyJS = require('uglify-js')

	var ast = uglifyJS.parser.parse(code, opts.strict_semicolons),
	ast = uglifyJS.uglify.ast_mangle(ast, opts)
	ast = uglifyJS.uglify.ast_squeeze(ast, opts)

	return uglifyJS.uglify.gen_code(ast, opts)
}

/* util
 ******/
var _compileModule = function(code, pathBase, mainModule) {
	var modules = [mainModule]
	_replaceRequireStatements(mainModule, code, modules, pathBase)
	code = _concatModules(modules)
	code = _minifyRequireStatements(code, modules)
	return code
}

var _minifyRequireStatements = function(code, modules) {
	for (var i=0, modulePath; modulePath = modules[i]; i++) {
		var escapedPath = modulePath.replace(/\//g, '\\/').replace('(','\\(').replace(')','\\)'),
			regex = new RegExp('__require__\\["'+ escapedPath +'"\\]', 'g')

		code = code.replace(regex, '__require__["_'+ i +'"]')
	}
	return code
}

var _pathnameGroupingRegex = /require\s*\(['"]([\w\/\.-]*)['"]\)/

var _replaceRequireStatements = function(modulePath, code, modules, pathBase) {
	var requireStatements = util.getRequireStatements(code)

	if (!requireStatements.length) {
		modules[modulePath] = code
		return
	}

	for (var i=0, requireStatement; requireStatement = requireStatements[i]; i++) {
		var rawModulePath = requireStatement.match(_pathnameGroupingRegex)[1],
			subModulePath = util.resolve(rawModulePath, pathBase).replace(/\.js$/, '')

		if (!subModulePath) {
			throw new Error("Require Compiler Error: Cannot find module '"+ rawModulePath +"' (in '"+ modulePath +"')")
		}

		code = code.replace(requireStatement, '__require__["' + subModulePath + '"].exports')

		if (!modules[subModulePath]) {
			modules[subModulePath] = true
			var newPathBase = path.dirname(subModulePath),
				newModuleCode = util.getCode(subModulePath + '.js')
			_replaceRequireStatements(subModulePath, newModuleCode, modules, newPathBase)
			modules.push(subModulePath)
		}
	}

	modules[modulePath] = code
}

var _concatModules = function(modules) {
	var code = function(modulePath) {
		for (var i=0; i<_ignoreModules.length; i++) {
			if (modulePath.match(_ignoreModules[i])) {
				return ''
			}
		}

		var ignoreClosure = false
		for (var i=0; i<_ignoreClosuresFor.length; i++) {
			if (modulePath.match(_ignoreClosuresFor[i])) {
				ignoreClosure = true
				break
			}
		}

		return [
			ignoreClosure ? '' : ';(function() {',
			'	// ' + modulePath,
			'	var module = __require__["'+modulePath+'"] = {exports:{}}, exports = module.exports;',
			modules[modulePath],
			ignoreClosure ? '' : '})()'
		].join('\n')
	}

	var moduleDefinitions = []
	for (var i=1, modulePath; modulePath = modules[i]; i++) {
		moduleDefinitions.push(code(modulePath))
	}
	moduleDefinitions.push(code(modules[0])) // __main__

	return moduleDefinitions.join('\n\n')
}

var _repeat = function(str, times) {
	if (times < 0) { return '' }
	return new Array(times + 1).join(str)
}
<commit_msg>make the default max line length shorter<commit_after>var fs = require('fs'),
	path = require('path'),
	util = require('./lib/util')

module.exports = {
	compile: compileFile,
	compileHTML: compileHTMLFile,
	compileCode: compileCode,
	dontAddClosureForModule: dontAddClosureForModule,
	dontIncludeModule: dontIncludeModule,
	addPath: addPath,
	addFile: addFile,
	addReplacement: addReplacement
}

var _ignoreClosuresFor = []
function dontAddClosureForModule(searchFor) {
	_ignoreClosuresFor.push(searchFor)
	return module.exports
}

var _ignoreModules = []
function dontIncludeModule(module) {
	_ignoreModules.push(module)
	return module.exports
}

function addReplacement(searchFor, replaceWith) {
	util.addReplacement.apply(util, arguments)
	return module.exports
}

function addPath() {
	util.addPath.apply(util, arguments)
	return module.exports
}

function addFile() {
	util.addFile.apply(util, arguments)
	return module.exports
}

/* api
 *****/
function compileFile(filePath, opts) {
	filePath = path.resolve(filePath)
	opts = util.extend(opts, { basePath:path.dirname(filePath), toplevel:true })
	var code = util.getCode(filePath)
	return _compile(code, opts, filePath)
}

function compileCode(code, opts) {
	opts = util.extend(opts, { basePath:process.cwd(), toplevel:true })
	return _compile(code, opts, '<code passed into compiler.compile()>')
}

function compileHTMLFile(filePath, opts) {
	var html = fs.readFileSync(filePath).toString()
	while (match = html.match(/<script src="\/require\/([\/\w\.]+)"><\/script>/)) {
		var js = compileFile(match[1].toString(), opts)

		var BACKREFERENCE_WORKAROUND = '____________backreference_workaround________'
		js = js.replace('\$\&', BACKREFERENCE_WORKAROUND)
		html = html.replace(match[0], '<script>'+js+'</script>')
		html = html.replace(BACKREFERENCE_WORKAROUND, '\$\&')
	}
	return html
}

var _compile = function(code, opts, mainModule) {
	var code = 'var __require__ = {}\n' + _compileModule(code, opts.basePath, mainModule)
	if (opts.minify === false) { return code } // TODO use uglifyjs' beautifier?

	if (opts.max_line_length == null) {
		opts.max_line_length = 100
	}

	var uglifyJS = require('uglify-js')

	var ast = uglifyJS.parser.parse(code, opts.strict_semicolons),
	ast = uglifyJS.uglify.ast_mangle(ast, opts)
	ast = uglifyJS.uglify.ast_squeeze(ast, opts)

	return uglifyJS.uglify.gen_code(ast, opts)
}

/* util
 ******/
var _compileModule = function(code, pathBase, mainModule) {
	var modules = [mainModule]
	_replaceRequireStatements(mainModule, code, modules, pathBase)
	code = _concatModules(modules)
	code = _minifyRequireStatements(code, modules)
	return code
}

var _minifyRequireStatements = function(code, modules) {
	for (var i=0, modulePath; modulePath = modules[i]; i++) {
		var escapedPath = modulePath.replace(/\//g, '\\/').replace('(','\\(').replace(')','\\)'),
			regex = new RegExp('__require__\\["'+ escapedPath +'"\\]', 'g')

		code = code.replace(regex, '__require__["_'+ i +'"]')
	}
	return code
}

var _pathnameGroupingRegex = /require\s*\(['"]([\w\/\.-]*)['"]\)/

var _replaceRequireStatements = function(modulePath, code, modules, pathBase) {
	var requireStatements = util.getRequireStatements(code)

	if (!requireStatements.length) {
		modules[modulePath] = code
		return
	}

	for (var i=0, requireStatement; requireStatement = requireStatements[i]; i++) {
		var rawModulePath = requireStatement.match(_pathnameGroupingRegex)[1],
			subModulePath = util.resolve(rawModulePath, pathBase).replace(/\.js$/, '')

		if (!subModulePath) {
			throw new Error("Require Compiler Error: Cannot find module '"+ rawModulePath +"' (in '"+ modulePath +"')")
		}

		code = code.replace(requireStatement, '__require__["' + subModulePath + '"].exports')

		if (!modules[subModulePath]) {
			modules[subModulePath] = true
			var newPathBase = path.dirname(subModulePath),
				newModuleCode = util.getCode(subModulePath + '.js')
			_replaceRequireStatements(subModulePath, newModuleCode, modules, newPathBase)
			modules.push(subModulePath)
		}
	}

	modules[modulePath] = code
}

var _concatModules = function(modules) {
	var code = function(modulePath) {
		for (var i=0; i<_ignoreModules.length; i++) {
			if (modulePath.match(_ignoreModules[i])) {
				return ''
			}
		}

		var ignoreClosure = false
		for (var i=0; i<_ignoreClosuresFor.length; i++) {
			if (modulePath.match(_ignoreClosuresFor[i])) {
				ignoreClosure = true
				break
			}
		}

		return [
			ignoreClosure ? '' : ';(function() {',
			'	// ' + modulePath,
			'	var module = __require__["'+modulePath+'"] = {exports:{}}, exports = module.exports;',
			modules[modulePath],
			ignoreClosure ? '' : '})()'
		].join('\n')
	}

	var moduleDefinitions = []
	for (var i=1, modulePath; modulePath = modules[i]; i++) {
		moduleDefinitions.push(code(modulePath))
	}
	moduleDefinitions.push(code(modules[0])) // __main__

	return moduleDefinitions.join('\n\n')
}

var _repeat = function(str, times) {
	if (times < 0) { return '' }
	return new Array(times + 1).join(str)
}
<|endoftext|>


<commit_before>'use strict';
/* global google, ga */

const config = require('../../../shared/config');
const helpers = require('../../../shared/helpers');

const Snackbar = require('../snackbar');
const contributionCounter = require('./contribution-counter');
const expandable = require('./expandable');

const GEO_TAGGING_MINI_MAP = '.geo-tagging-mini-map';
const GEO_TAGGING_SELECTOR = '.geo-tagging';
const INPUT_SELECTOR = '.geo-tagging__input';
const MAP_ELEMENT_SELECTOR = '.geo-tagging__map-element';
const OVERLAY_SELECTOR = '.geo-tagging__overlay';
const PLAYER_SELECTOR = '.geo-tagging__player';

const GEO_TAGGING_VISIBLE_CLASS = 'geo-tagging--visible';
const OVERLAY_VISIBLE_CLASS = 'geo-tagging__overlay--visible';

const BACK_TO_MAP_SELECTOR = '[data-action="back-to-map"]';
const SAVE_GEO_TAG_SELECTOR = '[data-action="save-geo-tag"]';
const START_GEO_TAGGING_SELECTOR = '[data-action="start-geo-tagging"]';
const STOP_GEOTAGGING_SELECTOR = '[data-action="stop-geo-tagging"]';
const CLOSE_OVERLAY_SELECTOR = '[data-action="close-overlay"]';

const LOCATION_SET_ZOOM = 16;
const GA_EVENT_CATEGORY = 'Geotagging';

const defaults = config.geoTagging.default || {};
defaults.position = defaults.position || {
  latitude: 55.6747,
  longitude: 12.5747
};
defaults.zoom = defaults.zoom || 16;

// TODO: Re-introduce the use of Google Analytics events
// TODO: Add pretty errors instead of silent fails
// TODO: Use the "require('./contribution-counter')"

// Precondition on the availability of the helpers
if(!helpers.geoTagging ||
   typeof(helpers.geoTagging.getLocation) !== 'function') {
  throw new Error('Missing helpers.geoTagging.* helpers');
}

function generateMapOptions(latitude, longitude) {
  return {
    center: new google.maps.LatLng(latitude, longitude),
    zoom: defaults.zoom,
    mapTypeControlOptions: {
      style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR,
      mapTypeIds: [
        google.maps.MapTypeId.ROADMAP,
        google.maps.MapTypeId.SATELLITE
      ]
    },
    styles: [{
      featureType: 'transit',
      stylers: [{
        visibility: 'off'
      }]
    }]
  };
}

(function($) {

  class GeoTaggingController {

    constructor($geoTagging) {
      this.$geoTagging = $geoTagging;
      this.state = {
        saving: false,
        address: '',
        heading: 0,
        latitude: defaults.position.latitude,
        longitude: defaults.position.longitude
      };

      // Fetch the location metadata and then initialize the map
      // TODO: Perform a call to /json to get raw metadata about the asset
      // instead of saving this in the markup, as it makes the templates less
      // independent of the metadata schema used.
      // this.latitude = $('.asset').data('latitude');
      // this.longitude = $('.asset').data('longitude');
      // this.heading = $('.asset').data('heading');
      // this.address = $('.asset').data('full-address');

      this.initialize();
      // Bind some of the method, so they can be used as a callbacks directly
      this.resize = this.resize.bind(this);
      this.stop = this.stop.bind(this);

      // Register the listeners
      this.registerListeners();
    }

    initialize() {
      this.initializeMap();
      this.initializeStreetView();
      this.initializeMarkers();
      this.initializeSearchBox();
    }

    initializeMap() {
      const options = generateMapOptions(this.state.latitude,
                                         this.state.longitude);
      // TODO: Consider throwing an error if there is more than one map element
      const element = this.$geoTagging.find(MAP_ELEMENT_SELECTOR)[0];
      // Initialize the map
      this.map = new google.maps.Map(element, options);

      // Register listener
      this.map.addListener('click', (e) => {
        // Ensure that distance between markers is the same on every zoom level
        const headingOffset = 100 * Math.pow(0.5, this.map.getZoom());
        const lat = e.latLng.lat() + headingOffset;
        const lng = e.latLng.lng();
        const headingMarkerLatLng = new google.maps.LatLng(lat, lng);

        this.marker.setPosition(e.latLng);
        this.headingMarker.setPosition(headingMarkerLatLng);
        this.state.heading = this.calculateHeading();
        this.recalculateLine();
      });
    }

    initializeStreetView() {
      this.streetView = this.map.getStreetView();
      // https://developers.google.com/maps/documentation/javascript/controls
      // https://developers.google.com/maps/documentation/javascript/examples/
      // streetview-controls
      this.streetView.setOptions({
        addressControl: false,
        panControl: false,
        zoomControl: false,
        scrollwheel: false
      });

      this.streetView.addListener('pov_changed', () => {
        this.state.heading = this.streetView.getPov().heading;
      });

      this.streetView.addListener('visible_changed', () => {
        const computeOffset = google.maps.geometry.spherical.computeOffset;
        const inStreetView = this.streetView.getVisible();

        this.marker.setVisible(!inStreetView);
        this.headingMarker.setVisible(!inStreetView);

        this.$geoTagging.find(STOP_GEOTAGGING_SELECTOR).toggle(!inStreetView);
        this.$geoTagging.find(SAVE_GEO_TAG_SELECTOR).toggle(!inStreetView);
        this.$geoTagging.find(BACK_TO_MAP_SELECTOR).toggle(inStreetView);

        const position = this.streetView.getPosition();
        if (position) {
          var offset = computeOffset(position, 100, this.state.heading);
          this.marker.setPosition(position);
          this.headingMarker.setPosition(offset);
          this.recalculateLine();
        }

        // If no longer in streetview, set the maps position
        if (!inStreetView && position) {
          this.map.setZoom(LOCATION_SET_ZOOM);
          this.map.setCenter(position);
        }
      });

      // When clicking back to map
      this.$geoTagging.on('click', BACK_TO_MAP_SELECTOR, () => {
        this.map.streetView.setVisible(false);
      });
    }

    initializeMarkers() {
      // TODO: Lets use symbols instead
      // https://developers.google.com/maps/documentation/javascript/examples/
      // overlay-symbol-custom
      this.marker = new google.maps.Marker({
        map: this.map,
        icon: '/images/camera_pin_green.png',
        draggable: true
      });

      this.headingMarker = new google.maps.Marker({
        map: this.map,
        icon: '/images/heading_pin_red.png',
        draggable: true
      });

      this.headingLine = new google.maps.Polyline({
        map: this.map,
        strokeColor: '#333333'
      });

      this.marker.addListener('drag', () => {
        this.state.heading = this.calculateHeading();
        this.recalculateLine();
      });

      this.headingMarker.addListener('drag', () => {
        this.state.heading = this.calculateHeading();
        this.recalculateLine();
      });
    }

    initializeSearchBox() {
      const input = $(INPUT_SELECTOR)[0];
      const searchBox = new google.maps.places.SearchBox(input);
      this.map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);

      searchBox.addListener('places_changed', () => {
        var places = searchBox.getPlaces();

        if (places.length === 0) {
          return;
        }
        // For each place, get the icon, name and location.
        var bounds = new google.maps.LatLngBounds();
        places.forEach((place) => {
          if (place.geometry.viewport) {
            // Only geocodes have viewport.
            bounds.union(place.geometry.viewport);
          } else {
            bounds.extend(place.geometry.location);
          }
        });
        this.map.fitBounds(bounds);
        this.map.setZoom(16);
      });

      this.map.addListener('bounds_changed', () => {
        searchBox.setBounds(this.map.getBounds());
      });
    }

    calculateHeading() {
      const p1 = this.marker.getPosition();
      const p2 = this.headingMarker.getPosition();
      return google.maps.geometry.spherical.computeHeading(p1, p2);
    }

    recalculateLine() {
      // Inject the heading into the POV
      var tempPov = this.streetView.getPov();
      tempPov.heading = this.state.heading || 0;
      this.streetView.setPov(tempPov);
      this.headingLine.setPath([
        this.marker.getPosition(),
        this.headingMarker.getPosition()
      ]);
    }

    updateMarkersFromState() {
      const computeOffset = google.maps.geometry.spherical.computeOffset;
      const latitude = this.state.latitude;
      const longitude = this.state.longitude;
      const heading = this.state.heading;

      if(latitude && longitude) {
        const latLng = new google.maps.LatLng(latitude, longitude);
        this.marker.setPosition(latLng);
        this.map.setCenter(latLng);

        if (heading) {
          var headingLatLng = computeOffset(latLng, 100, heading);
          this.headingMarker.setPosition(headingLatLng);
          this.recalculateLine();
        }
        this.map.setZoom(LOCATION_SET_ZOOM);
      }
    }

    geocodeSuggestedLocation(address) {
      const geocoder = new google.maps.Geocoder();
      geocoder.geocode({
        address
      }, (results, status) => {
        if (status === google.maps.GeocoderStatus.OK) {
          const location = results[0].geometry.location;
          const latLng = new google.maps.LatLng(location.lat(), location.lng());
          this.map.setCenter(latLng);
          // TODO: Consider if we really need this resize?
          this.resize();
        }
        // Let's show the user that we have searched for this address
        $(INPUT_SELECTOR).val(address);
      });
    }

    fetchAndReset() {
      const url = location.pathname + '/json';
      $.get(url, this.state.metadata, (metadata) => {
        const location = helpers.geoTagging.getLocation(metadata);
        // Override values in state with the once we got from the helper
        Object.assign(this.state, location);
        // Once we have them, update the markers and recalculate line
        this.updateMarkersFromState();
        this.streetView.setVisible(false);
        // If the metadata contains an address, use that
        // this.geocodeSuggestedLocation(address)
      }, 'json');
    }

    start() {
      // Show the overlay if it has never been closed
      if (!window.localStorage.getItem('geotagging-overlay-closed')) {
        this.$geoTagging.find(OVERLAY_SELECTOR).addClass(OVERLAY_VISIBLE_CLASS);
      }
      // Disable all buttons that can start geo-tagging
      $(START_GEO_TAGGING_SELECTOR).attr('disabled', true);
      // Expand the expandable
      expandable.expand();
      // Find all .geo-tagging blocks and make them visible
      this.$geoTagging.addClass(GEO_TAGGING_VISIBLE_CLASS);
      // Bind resizing of the map on the window resizing
      $(window).bind('resize', this.resize);
      // Hide the map if the expandable is collapsed
      expandable.bind('collapsed', this.stop);
      // Scroll to the place where the geo-tagging takes place
      // TODO: Consider that their might be multiple of these
      $('html, body').animate({
        scrollTop: this.$geoTagging.offset().top - 100
      }, 400);
      // Fetch the newest metadata and reset from that
      this.fetchAndReset();
      // Trigger a resize of the map, when the animation from adding the class
      // GEOTAGGING_VISIBLE_CLASS completes.
      setTimeout(() => {
        this.resize();
      }, 150); // The same as $anim-duration-fast
    }

    resize() {
      // Set the maps height to the same as the sibling player
      const $player = $('.asset__image', PLAYER_SELECTOR);
      this.$geoTagging.find(MAP_ELEMENT_SELECTOR).height($player.height());
      // Trigger a resize event and reset the center position
      var center = this.map.getCenter();
      google.maps.event.trigger(this.map, 'resize');
      this.map.setCenter(center);
    }

    stop() {
      ga('send', 'event', GA_EVENT_CATEGORY, 'Hide');
      // Unbinding event handlers
      $(window).unbind('resize', this.resize);
      expandable.unbind('collapsed', this.stop);
      // Collapse the expandable
      // TODO: Consider checking the state of expandable when showing the map to
      // be able to return to the state before geotagging started.
      expandable.collapse();
      // Remove disabled attribute from any element that can start geotagging
      $(START_GEO_TAGGING_SELECTOR).removeAttr('disabled');
      // Remove the class that shows the map
      $(GEO_TAGGING_SELECTOR).removeClass(GEO_TAGGING_VISIBLE_CLASS);
    }

    save() {
      // Don't save twice
      if(this.state.saving) {
        return;
      }
      this.state.saving = true;
      // Set the latitude and longitude, based on the markers current position
      const position = this.marker.getPosition();
      if(position) {
        Object.assign(this.state, {
          latitude: position.lat,
          longitude: position.lng,
        });
        // Post to the API
        const url = location.pathname + '/save-geotag';
        $.post(url, this.state, () => {
          Snackbar.info('Gemt! Tak for dit bidrag!');
          contributionCounter.contributionAdded();
          this.state.saving = false;
          window.location.reload();
        }, 'json');
      } else {
        throw new Error('Expected a valid position for the marker');
      }
    }

    registerListeners() {
      // When clicking the edit button
      $(document).on('click', START_GEO_TAGGING_SELECTOR, () => {
        this.start();
      });
      // Clicking stop / cancel
      this.$geoTagging.on('click', STOP_GEOTAGGING_SELECTOR, () => {
        this.stop();
      });
      // Clicking save
      this.$geoTagging.on('click', SAVE_GEO_TAG_SELECTOR, () => {
        this.save();
      });
      this.$geoTagging.on('click', CLOSE_OVERLAY_SELECTOR, () => {
        window.localStorage.setItem('geotagging-overlay-closed', true);
        const $overlay = this.$geoTagging.find(OVERLAY_SELECTOR);
        $overlay.removeClass(OVERLAY_VISIBLE_CLASS);
      })
    }
  }

  // Register a global callback function that the Google Maps sdk will call
  // when it is done loading.
  window.initMap = () => {
    // Initialize geo tagging for every .geo-tagging element on the page
    $(GEO_TAGGING_SELECTOR).each((i, e) => {
      const $geoTagging = $(e);
      // Initialize a controller
      const controller = new GeoTaggingController($geoTagging);
    });
    // Initialize all small maps
    $(GEO_TAGGING_MINI_MAP).each((i, element) => {
      const $map = $(element);
      const latitude = parseFloat($map.data('latitude'), 10);
      const longitude = parseFloat($map.data('longitude'), 10);

      const options = generateMapOptions(latitude, longitude);
      // Initialize the map
      const map = new google.maps.Map(element, options);
      // Add a marker
      const marker = new google.maps.Marker({
        map,
        icon: '/images/map_pin_red.png',
        position: {
          lat: latitude,
          lng: longitude
        }
      });

      google.maps.event.trigger(map, 'resize');
    });
  };
})(jQuery);
<commit_msg>Using the players height instead of the .asset_image inside it<commit_after>'use strict';
/* global google, ga */

const config = require('../../../shared/config');
const helpers = require('../../../shared/helpers');

const Snackbar = require('../snackbar');
const contributionCounter = require('./contribution-counter');
const expandable = require('./expandable');

const GEO_TAGGING_MINI_MAP = '.geo-tagging-mini-map';
const GEO_TAGGING_SELECTOR = '.geo-tagging';
const INPUT_SELECTOR = '.geo-tagging__input';
const MAP_ELEMENT_SELECTOR = '.geo-tagging__map-element';
const OVERLAY_SELECTOR = '.geo-tagging__overlay';
const PLAYER_SELECTOR = '.geo-tagging__player';

const GEO_TAGGING_VISIBLE_CLASS = 'geo-tagging--visible';
const OVERLAY_VISIBLE_CLASS = 'geo-tagging__overlay--visible';

const BACK_TO_MAP_SELECTOR = '[data-action="back-to-map"]';
const SAVE_GEO_TAG_SELECTOR = '[data-action="save-geo-tag"]';
const START_GEO_TAGGING_SELECTOR = '[data-action="start-geo-tagging"]';
const STOP_GEOTAGGING_SELECTOR = '[data-action="stop-geo-tagging"]';
const CLOSE_OVERLAY_SELECTOR = '[data-action="close-overlay"]';

const LOCATION_SET_ZOOM = 16;
const GA_EVENT_CATEGORY = 'Geotagging';

const defaults = config.geoTagging.default || {};
defaults.position = defaults.position || {
  latitude: 55.6747,
  longitude: 12.5747
};
defaults.zoom = defaults.zoom || 16;

// TODO: Re-introduce the use of Google Analytics events
// TODO: Add pretty errors instead of silent fails
// TODO: Use the "require('./contribution-counter')"

// Precondition on the availability of the helpers
if(!helpers.geoTagging ||
   typeof(helpers.geoTagging.getLocation) !== 'function') {
  throw new Error('Missing helpers.geoTagging.* helpers');
}

function generateMapOptions(latitude, longitude) {
  return {
    center: new google.maps.LatLng(latitude, longitude),
    zoom: defaults.zoom,
    mapTypeControlOptions: {
      style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR,
      mapTypeIds: [
        google.maps.MapTypeId.ROADMAP,
        google.maps.MapTypeId.SATELLITE
      ]
    },
    styles: [{
      featureType: 'transit',
      stylers: [{
        visibility: 'off'
      }]
    }]
  };
}

(function($) {

  class GeoTaggingController {

    constructor($geoTagging) {
      this.$geoTagging = $geoTagging;
      this.state = {
        saving: false,
        address: '',
        heading: 0,
        latitude: defaults.position.latitude,
        longitude: defaults.position.longitude
      };

      // Fetch the location metadata and then initialize the map
      // TODO: Perform a call to /json to get raw metadata about the asset
      // instead of saving this in the markup, as it makes the templates less
      // independent of the metadata schema used.
      // this.latitude = $('.asset').data('latitude');
      // this.longitude = $('.asset').data('longitude');
      // this.heading = $('.asset').data('heading');
      // this.address = $('.asset').data('full-address');

      this.initialize();
      // Bind some of the method, so they can be used as a callbacks directly
      this.resize = this.resize.bind(this);
      this.stop = this.stop.bind(this);

      // Register the listeners
      this.registerListeners();
    }

    initialize() {
      this.initializeMap();
      this.initializeStreetView();
      this.initializeMarkers();
      this.initializeSearchBox();
    }

    initializeMap() {
      const options = generateMapOptions(this.state.latitude,
                                         this.state.longitude);
      // TODO: Consider throwing an error if there is more than one map element
      const element = this.$geoTagging.find(MAP_ELEMENT_SELECTOR)[0];
      // Initialize the map
      this.map = new google.maps.Map(element, options);

      // Register listener
      this.map.addListener('click', (e) => {
        // Ensure that distance between markers is the same on every zoom level
        const headingOffset = 100 * Math.pow(0.5, this.map.getZoom());
        const lat = e.latLng.lat() + headingOffset;
        const lng = e.latLng.lng();
        const headingMarkerLatLng = new google.maps.LatLng(lat, lng);

        this.marker.setPosition(e.latLng);
        this.headingMarker.setPosition(headingMarkerLatLng);
        this.state.heading = this.calculateHeading();
        this.recalculateLine();
      });
    }

    initializeStreetView() {
      this.streetView = this.map.getStreetView();
      // https://developers.google.com/maps/documentation/javascript/controls
      // https://developers.google.com/maps/documentation/javascript/examples/
      // streetview-controls
      this.streetView.setOptions({
        addressControl: false,
        panControl: false,
        zoomControl: false,
        scrollwheel: false
      });

      this.streetView.addListener('pov_changed', () => {
        this.state.heading = this.streetView.getPov().heading;
      });

      this.streetView.addListener('visible_changed', () => {
        const computeOffset = google.maps.geometry.spherical.computeOffset;
        const inStreetView = this.streetView.getVisible();

        this.marker.setVisible(!inStreetView);
        this.headingMarker.setVisible(!inStreetView);

        this.$geoTagging.find(STOP_GEOTAGGING_SELECTOR).toggle(!inStreetView);
        this.$geoTagging.find(SAVE_GEO_TAG_SELECTOR).toggle(!inStreetView);
        this.$geoTagging.find(BACK_TO_MAP_SELECTOR).toggle(inStreetView);

        const position = this.streetView.getPosition();
        if (position) {
          var offset = computeOffset(position, 100, this.state.heading);
          this.marker.setPosition(position);
          this.headingMarker.setPosition(offset);
          this.recalculateLine();
        }

        // If no longer in streetview, set the maps position
        if (!inStreetView && position) {
          this.map.setZoom(LOCATION_SET_ZOOM);
          this.map.setCenter(position);
        }
      });

      // When clicking back to map
      this.$geoTagging.on('click', BACK_TO_MAP_SELECTOR, () => {
        this.map.streetView.setVisible(false);
      });
    }

    initializeMarkers() {
      // TODO: Lets use symbols instead
      // https://developers.google.com/maps/documentation/javascript/examples/
      // overlay-symbol-custom
      this.marker = new google.maps.Marker({
        map: this.map,
        icon: '/images/camera_pin_green.png',
        draggable: true
      });

      this.headingMarker = new google.maps.Marker({
        map: this.map,
        icon: '/images/heading_pin_red.png',
        draggable: true
      });

      this.headingLine = new google.maps.Polyline({
        map: this.map,
        strokeColor: '#333333'
      });

      this.marker.addListener('drag', () => {
        this.state.heading = this.calculateHeading();
        this.recalculateLine();
      });

      this.headingMarker.addListener('drag', () => {
        this.state.heading = this.calculateHeading();
        this.recalculateLine();
      });
    }

    initializeSearchBox() {
      const input = $(INPUT_SELECTOR)[0];
      const searchBox = new google.maps.places.SearchBox(input);
      this.map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);

      searchBox.addListener('places_changed', () => {
        var places = searchBox.getPlaces();

        if (places.length === 0) {
          return;
        }
        // For each place, get the icon, name and location.
        var bounds = new google.maps.LatLngBounds();
        places.forEach((place) => {
          if (place.geometry.viewport) {
            // Only geocodes have viewport.
            bounds.union(place.geometry.viewport);
          } else {
            bounds.extend(place.geometry.location);
          }
        });
        this.map.fitBounds(bounds);
        this.map.setZoom(16);
      });

      this.map.addListener('bounds_changed', () => {
        searchBox.setBounds(this.map.getBounds());
      });
    }

    calculateHeading() {
      const p1 = this.marker.getPosition();
      const p2 = this.headingMarker.getPosition();
      return google.maps.geometry.spherical.computeHeading(p1, p2);
    }

    recalculateLine() {
      // Inject the heading into the POV
      var tempPov = this.streetView.getPov();
      tempPov.heading = this.state.heading || 0;
      this.streetView.setPov(tempPov);
      this.headingLine.setPath([
        this.marker.getPosition(),
        this.headingMarker.getPosition()
      ]);
    }

    updateMarkersFromState() {
      const computeOffset = google.maps.geometry.spherical.computeOffset;
      const latitude = this.state.latitude;
      const longitude = this.state.longitude;
      const heading = this.state.heading;

      if(latitude && longitude) {
        const latLng = new google.maps.LatLng(latitude, longitude);
        this.marker.setPosition(latLng);
        this.map.setCenter(latLng);

        if (heading) {
          var headingLatLng = computeOffset(latLng, 100, heading);
          this.headingMarker.setPosition(headingLatLng);
          this.recalculateLine();
        }
        this.map.setZoom(LOCATION_SET_ZOOM);
      }
    }

    geocodeSuggestedLocation(address) {
      const geocoder = new google.maps.Geocoder();
      geocoder.geocode({
        address
      }, (results, status) => {
        if (status === google.maps.GeocoderStatus.OK) {
          const location = results[0].geometry.location;
          const latLng = new google.maps.LatLng(location.lat(), location.lng());
          this.map.setCenter(latLng);
          // TODO: Consider if we really need this resize?
          this.resize();
        }
        // Let's show the user that we have searched for this address
        $(INPUT_SELECTOR).val(address);
      });
    }

    fetchAndReset() {
      const url = location.pathname + '/json';
      $.get(url, this.state.metadata, (metadata) => {
        const location = helpers.geoTagging.getLocation(metadata);
        // Override values in state with the once we got from the helper
        Object.assign(this.state, location);
        // Once we have them, update the markers and recalculate line
        this.updateMarkersFromState();
        this.streetView.setVisible(false);
        // If the metadata contains an address, use that
        // this.geocodeSuggestedLocation(address)
      }, 'json');
    }

    start() {
      // Show the overlay if it has never been closed
      if (!window.localStorage.getItem('geotagging-overlay-closed')) {
        this.$geoTagging.find(OVERLAY_SELECTOR).addClass(OVERLAY_VISIBLE_CLASS);
      }
      // Disable all buttons that can start geo-tagging
      $(START_GEO_TAGGING_SELECTOR).attr('disabled', true);
      // Expand the expandable
      expandable.expand();
      // Find all .geo-tagging blocks and make them visible
      this.$geoTagging.addClass(GEO_TAGGING_VISIBLE_CLASS);
      // Bind resizing of the map on the window resizing
      $(window).bind('resize', this.resize);
      // Hide the map if the expandable is collapsed
      expandable.bind('collapsed', this.stop);
      // Scroll to the place where the geo-tagging takes place
      // TODO: Consider that their might be multiple of these
      $('html, body').animate({
        scrollTop: this.$geoTagging.offset().top - 100
      }, 400);
      // Fetch the newest metadata and reset from that
      this.fetchAndReset();
      // Trigger a resize of the map, when the animation from adding the class
      // GEOTAGGING_VISIBLE_CLASS completes.
      setTimeout(() => {
        this.resize();
      }, 150); // The same as $anim-duration-fast
    }

    resize() {
      // Set the maps height to the same as the sibling player
      const $player = $(PLAYER_SELECTOR);
      this.$geoTagging.find(MAP_ELEMENT_SELECTOR).height($player.height());
      // Trigger a resize event and reset the center position
      var center = this.map.getCenter();
      google.maps.event.trigger(this.map, 'resize');
      this.map.setCenter(center);
    }

    stop() {
      ga('send', 'event', GA_EVENT_CATEGORY, 'Hide');
      // Unbinding event handlers
      $(window).unbind('resize', this.resize);
      expandable.unbind('collapsed', this.stop);
      // Collapse the expandable
      // TODO: Consider checking the state of expandable when showing the map to
      // be able to return to the state before geotagging started.
      expandable.collapse();
      // Remove disabled attribute from any element that can start geotagging
      $(START_GEO_TAGGING_SELECTOR).removeAttr('disabled');
      // Remove the class that shows the map
      $(GEO_TAGGING_SELECTOR).removeClass(GEO_TAGGING_VISIBLE_CLASS);
    }

    save() {
      // Don't save twice
      if(this.state.saving) {
        return;
      }
      this.state.saving = true;
      // Set the latitude and longitude, based on the markers current position
      const position = this.marker.getPosition();
      if(position) {
        Object.assign(this.state, {
          latitude: position.lat,
          longitude: position.lng,
        });
        // Post to the API
        const url = location.pathname + '/save-geotag';
        $.post(url, this.state, () => {
          Snackbar.info('Gemt! Tak for dit bidrag!');
          contributionCounter.contributionAdded();
          this.state.saving = false;
          window.location.reload();
        }, 'json');
      } else {
        throw new Error('Expected a valid position for the marker');
      }
    }

    registerListeners() {
      // When clicking the edit button
      $(document).on('click', START_GEO_TAGGING_SELECTOR, () => {
        this.start();
      });
      // Clicking stop / cancel
      this.$geoTagging.on('click', STOP_GEOTAGGING_SELECTOR, () => {
        this.stop();
      });
      // Clicking save
      this.$geoTagging.on('click', SAVE_GEO_TAG_SELECTOR, () => {
        this.save();
      });
      this.$geoTagging.on('click', CLOSE_OVERLAY_SELECTOR, () => {
        window.localStorage.setItem('geotagging-overlay-closed', true);
        const $overlay = this.$geoTagging.find(OVERLAY_SELECTOR);
        $overlay.removeClass(OVERLAY_VISIBLE_CLASS);
      })
    }
  }

  // Register a global callback function that the Google Maps sdk will call
  // when it is done loading.
  window.initMap = () => {
    // Initialize geo tagging for every .geo-tagging element on the page
    $(GEO_TAGGING_SELECTOR).each((i, e) => {
      const $geoTagging = $(e);
      // Initialize a controller
      const controller = new GeoTaggingController($geoTagging);
    });
    // Initialize all small maps
    $(GEO_TAGGING_MINI_MAP).each((i, element) => {
      const $map = $(element);
      const latitude = parseFloat($map.data('latitude'), 10);
      const longitude = parseFloat($map.data('longitude'), 10);

      const options = generateMapOptions(latitude, longitude);
      // Initialize the map
      const map = new google.maps.Map(element, options);
      // Add a marker
      const marker = new google.maps.Marker({
        map,
        icon: '/images/map_pin_red.png',
        position: {
          lat: latitude,
          lng: longitude
        }
      });

      google.maps.event.trigger(map, 'resize');
    });
  };
})(jQuery);
<|endoftext|>


<commit_before>module.exports = function() {
  'use strict';

  DependencyInjection.service('$DatabaseService', [function() {
    var mongoose = require('mongoose');

    mongoose.connect(
      'mongodb://' +
      (process.env.DATABASE_USER ? process.env.DATABASE_USER + ':' + process.env.DATABASE_PASSWORD + '@' : '') +
      process.env.DATABASE_HOST +
      '/' + process.env.DATABASE_NAME, {
        server: {
          socketOptions: {
            keepAlive: 1
          }
        }
      }
    );

    return mongoose;
  }]);

};
<commit_msg>fix(common database model): add more pool connection<commit_after>module.exports = function() {
  'use strict';

  DependencyInjection.service('$DatabaseService', [function() {
    var mongoose = require('mongoose');

    mongoose.connect(
      'mongodb://' +
      (process.env.DATABASE_USER ? process.env.DATABASE_USER + ':' + process.env.DATABASE_PASSWORD + '@' : '') +
      process.env.DATABASE_HOST +
      '/' + process.env.DATABASE_NAME, {
        server: {
          socketOptions: {
            keepAlive: 1
          },

          // MongDB max connections: 20 - Mongoose monitor 1 = 19
          poolSize: 19
        }
      }
    );

    return mongoose;
  }]);

};
<|endoftext|>


<commit_before>/* eslint-disable react/prefer-stateless-function */
import React from 'react';
import { Actions, Scene } from 'react-native-router-flux';
import Home from '../containers/home/Home';
import AppConfig from '../constants/config';
import AppSizes from '../theme/sizes';
import AppStyles from '../theme/styles';
import Community from '../containers/community/Community';
import UserCenter from '../containers/user-center/UserCenter';
import AboutUs from '../containers/user-center/about-us/AboutUs';
import ContributorProfile from '../containers/user-center/about-us/ContributorProfile';
import Discover from '../containers/discover/Discover';
import RoadmapList from '../containers/discover/roadmap-list/RoadmapList';
import RoadmapDetail from '../containers/discover/roadmap-detail/RoadmapDetail';
import ProjectList from '../containers/discover/project-list/ProjectList';
import ProjectDetail from '../containers/discover/project-detail/ProjectDetail';
import ToolBoxList from '../containers/discover/toolbox-list/ToolBoxList';
import ToolBoxDetail from '../containers/discover/toolbox-detail/ToolBoxDetail';
import ArticleList from '../containers/discover/article-list/ArticleList';
import ArticleDetail from '../containers/discover/article-detail/ArticleDetail';
import ExamList from '../containers/discover/exam-list/ExamList';
import ExamDetail from '../containers/discover/exam-detail/ExamDetail';
import Solution from '../containers/discover/solution/Solution';
import SolutionDetail from '../containers/discover/solution-detail/SolutionDetail';
import ThoughtworksBooks from '../containers/discover/thoughtworks-books/ThoughtworksBooks';
import RecommendBooks from '../containers/discover/recommend-books/RecommendBooks';
import RecommendArticles from '../containers/discover/recommend-articles/RecommendArticles';
import TodoLists from '../containers/discover/todo-lists/TodoLists';
import ChapterList from '../containers/discover/chapter-list/ChapterList';
import SkillTree from '../containers/skill-tree/SkillTree';
import SkillDetailView from '../containers/skill-tree/SkillDetailView';
import ComingSoonView from '../containers/ComingSoonView';
import Helper from '../utils/helper';
import TabIcon from '../components/TabIcon';
import Practises from '../containers/practises/Practises';
import GrEditor from '../components/GrEditor';

const navbarPropsTabs = {
  ...AppConfig.navbarProps,
  sceneStyle: {
    ...AppConfig.navbarProps.sceneStyle,
    paddingBottom: AppSizes.tabbarHeight,
  },
};

export default Actions.create(
  <Scene key="root" {...AppConfig.navbarProps}>
    <Scene key="tabs" initial={'tabBar'} tabs tabBarIconContainerStyle={AppStyles.tabbar} pressOpacity={0.95}>
      <Scene
        {...navbarPropsTabs}
        key={'home'}
        title={'Growth'}
        iconName={'md-home'}
        iconType={'ionicon'}
        leftTitle={'用户中心'}
        renderLeftButton={() => Helper.gotoUserCenter()}
        rightTitle={'购买纸质版'}
        onRight={() => Actions.comingSoon()}
        rightButtonTextStyle={AppStyles.navbarTitle}
        icon={TabIcon}
        component={Home}
      />
      <Scene
        {...navbarPropsTabs}
        key={'discover'}
        title={'探索'}
        iconName={'md-compass'}
        iconType={'ionicon'}
        icon={TabIcon}
        component={Discover}
      />
      <Scene
        {...navbarPropsTabs}
        key={'skillTree'}
        title={'技能树'}
        rightTitle={'获取专业版'}
        onRight={() => Helper.getProfessionalSkilltree()}
        rightButtonTextStyle={AppStyles.navbarTitle}
        iconName={'md-egg'}
        iconType={'ionicon'}
        icon={TabIcon}
        component={SkillTree}
      />
      <Scene
        {...navbarPropsTabs}
        key={'community'}
        title={'社区'}
        iconName={'md-people'}
        iconType={'ionicon'}
        icon={TabIcon}
        component={Community}
      />
      <Scene
        {...navbarPropsTabs}
        key={'practises'}
        title={'练习'}
        iconName={'md-bonfire'}
        iconType={'ionicon'}
        icon={TabIcon}
        rightTitle={'编辑器'}
        onRight={() => Actions.grEditor()}
        rightButtonTextStyle={AppStyles.navbarTitle}
        component={Practises}
      />
    </Scene>

    <Scene
      key={'userCenter'}
      title={'用户中心'}
      component={UserCenter}
    />

    <Scene
      key={'skillDetail'}
      title={'技能'}
      component={SkillDetailView}
    />

    <Scene
      key={'comingSoon'}
      title={'Coming Soon'}
      component={ComingSoonView}
    />

    <Scene
      key={'roadmapList'}
      title={'学习路线'}
      duration={0}
      component={RoadmapList}
    />

    <Scene
      key={'roadmapDetail'}
      duration={0}
      component={RoadmapDetail}
    />

    <Scene
      key={'projectList'}
      duration={0}
      title={'练手项目'}
      component={ProjectList}
    />

    <Scene
      key={'projectDetail'}
      duration={0}
      component={ProjectDetail}
    />

    <Scene
      key={'toolBoxList'}
      duration={0}
      title={'工具箱'}
      component={ToolBoxList}
    />

    <Scene
      key={'toolBoxDetail'}
      duration={0}
      title={'工具箱'}
      component={ToolBoxDetail}
    />

    <Scene
      key={'articleList'}
      duration={0}
      title={'文章推荐'}
      component={ArticleList}
    />

    <Scene
      key={'articleDetail'}
      duration={0}
      title={'文章详情'}
      component={ArticleDetail}
    />

    <Scene
      key={'examList'}
      duration={0}
      title={'技能测验'}
      component={ExamList}
    />

    <Scene
      key={'examDetail'}
      duration={0}
      hideNavBar
      component={ExamDetail}
    />

    <Scene
      key={'solution'}
      duration={0}
      title={'解决方案'}
      component={Solution}
    />

    <Scene
      key={'solutionDetail'}
      duration={0}
      title={'解决方案'}
      component={SolutionDetail}
    />

    <Scene
      key={'thoughtworksBooks'}
      duration={0}
      title={'ThoughtWorks读书路线'}
      component={ThoughtworksBooks}
    />

    <Scene
      key={'recommendBooks'}
      duration={0}
      title={'推荐书籍'}
      component={RecommendBooks}
    />

    <Scene
      key={'recommendArticles'}
      duration={0}
      title={'推荐文章'}
      component={RecommendArticles}
    />

    <Scene
      key={'todoLists'}
      duration={0}
      title={'待办事项'}
      component={TodoLists}
    />

    <Scene
      key={'chapterList'}
      duration={0}
      title={'ChapterList'}
      component={ChapterList}
    />

    <Scene
      key={'aboutUs'}
      title={'关于'}
      component={AboutUs}
    />

    <Scene
      key={'contributorProfile'}
      title={'Contributor Profile'}
      component={ContributorProfile}
    />

    <Scene
      {...navbarPropsTabs}
      key={'grEditor'}
      duration={500}
      title={'编辑器'}
      rightTitle={'Run'}
      rightButtonTextStyle={AppStyles.navbarTitle}
      onRight={() => GrEditor.runCode()}
      component={GrEditor}
    />

  </Scene>,
);
<commit_msg>Revert "[T] hide navbar props"<commit_after>/* eslint-disable react/prefer-stateless-function */
import React from 'react';
import { Actions, Scene } from 'react-native-router-flux';
import Home from '../containers/home/Home';
import AppConfig from '../constants/config';
import AppSizes from '../theme/sizes';
import AppStyles from '../theme/styles';
import Community from '../containers/community/Community';
import UserCenter from '../containers/user-center/UserCenter';
import AboutUs from '../containers/user-center/about-us/AboutUs';
import ContributorProfile from '../containers/user-center/about-us/ContributorProfile';
import Discover from '../containers/discover/Discover';
import RoadmapList from '../containers/discover/roadmap-list/RoadmapList';
import RoadmapDetail from '../containers/discover/roadmap-detail/RoadmapDetail';
import ProjectList from '../containers/discover/project-list/ProjectList';
import ProjectDetail from '../containers/discover/project-detail/ProjectDetail';
import ToolBoxList from '../containers/discover/toolbox-list/ToolBoxList';
import ToolBoxDetail from '../containers/discover/toolbox-detail/ToolBoxDetail';
import ArticleList from '../containers/discover/article-list/ArticleList';
import ArticleDetail from '../containers/discover/article-detail/ArticleDetail';
import ExamList from '../containers/discover/exam-list/ExamList';
import ExamDetail from '../containers/discover/exam-detail/ExamDetail';
import Solution from '../containers/discover/solution/Solution';
import SolutionDetail from '../containers/discover/solution-detail/SolutionDetail';
import ThoughtworksBooks from '../containers/discover/thoughtworks-books/ThoughtworksBooks';
import RecommendBooks from '../containers/discover/recommend-books/RecommendBooks';
import RecommendArticles from '../containers/discover/recommend-articles/RecommendArticles';
import TodoLists from '../containers/discover/todo-lists/TodoLists';
import ChapterList from '../containers/discover/chapter-list/ChapterList';
import SkillTree from '../containers/skill-tree/SkillTree';
import SkillDetailView from '../containers/skill-tree/SkillDetailView';
import ComingSoonView from '../containers/ComingSoonView';
import Helper from '../utils/helper';
import TabIcon from '../components/TabIcon';
import Practises from '../containers/practises/Practises';
import GrEditor from '../components/GrEditor';

const navbarPropsTabs = {
  ...AppConfig.navbarProps,
  sceneStyle: {
    ...AppConfig.navbarProps.sceneStyle,
    paddingBottom: AppSizes.tabbarHeight,
  },
};

export default Actions.create(
  <Scene key="root" {...AppConfig.navbarProps}>
    <Scene key="tabs" initial={'tabBar'} tabs tabBarIconContainerStyle={AppStyles.tabbar} pressOpacity={0.95}>
      <Scene
        {...navbarPropsTabs}
        key={'home'}
        title={'Growth'}
        iconName={'md-home'}
        iconType={'ionicon'}
        leftTitle={'用户中心'}
        renderLeftButton={() => Helper.gotoUserCenter()}
        rightTitle={'购买纸质版'}
        onRight={() => Actions.comingSoon()}
        rightButtonTextStyle={AppStyles.navbarTitle}
        icon={TabIcon}
        component={Home}
      />
      <Scene
        {...navbarPropsTabs}
        key={'discover'}
        title={'探索'}
        iconName={'md-compass'}
        iconType={'ionicon'}
        icon={TabIcon}
        component={Discover}
      />
      <Scene
        {...navbarPropsTabs}
        key={'skillTree'}
        title={'技能树'}
        rightTitle={'获取专业版'}
        onRight={() => Helper.getProfessionalSkilltree()}
        rightButtonTextStyle={AppStyles.navbarTitle}
        iconName={'md-egg'}
        iconType={'ionicon'}
        icon={TabIcon}
        component={SkillTree}
      />
      <Scene
        {...navbarPropsTabs}
        key={'community'}
        title={'社区'}
        iconName={'md-people'}
        iconType={'ionicon'}
        icon={TabIcon}
        component={Community}
      />
      <Scene
        {...navbarPropsTabs}
        key={'practises'}
        title={'练习'}
        iconName={'md-bonfire'}
        iconType={'ionicon'}
        icon={TabIcon}
        rightTitle={'编辑器'}
        onRight={() => Actions.grEditor()}
        rightButtonTextStyle={AppStyles.navbarTitle}
        component={Practises}
      />
    </Scene>

    <Scene
      {...navbarPropsTabs}
      key={'userCenter'}
      title={'用户中心'}
      component={UserCenter}
    />

    <Scene
      {...navbarPropsTabs}
      key={'skillDetail'}
      title={'技能'}
      component={SkillDetailView}
    />

    <Scene
      key={'comingSoon'}
      title={'Coming Soon'}
      component={ComingSoonView}
    />

    <Scene
      key={'roadmapList'}
      title={'学习路线'}
      duration={0}
      component={RoadmapList}
    />

    <Scene
      key={'roadmapDetail'}
      duration={0}
      component={RoadmapDetail}
    />

    <Scene
      key={'projectList'}
      duration={0}
      title={'练手项目'}
      component={ProjectList}
    />

    <Scene
      key={'projectDetail'}
      duration={0}
      component={ProjectDetail}
    />

    <Scene
      key={'toolBoxList'}
      duration={0}
      title={'工具箱'}
      component={ToolBoxList}
    />

    <Scene
      key={'toolBoxDetail'}
      duration={0}
      title={'工具箱'}
      component={ToolBoxDetail}
    />

    <Scene
      key={'articleList'}
      duration={0}
      title={'文章推荐'}
      component={ArticleList}
    />

    <Scene
      key={'articleDetail'}
      duration={0}
      title={'文章详情'}
      component={ArticleDetail}
    />

    <Scene
      key={'examList'}
      duration={0}
      title={'技能测验'}
      component={ExamList}
    />

    <Scene
      key={'examDetail'}
      duration={0}
      hideNavBar
      component={ExamDetail}
    />

    <Scene
      key={'solution'}
      duration={0}
      title={'解决方案'}
      component={Solution}
    />

    <Scene
      key={'solutionDetail'}
      duration={0}
      title={'解决方案'}
      component={SolutionDetail}
    />

    <Scene
      key={'thoughtworksBooks'}
      duration={0}
      title={'ThoughtWorks读书路线'}
      component={ThoughtworksBooks}
    />

    <Scene
      key={'recommendBooks'}
      duration={0}
      title={'推荐书籍'}
      component={RecommendBooks}
    />

    <Scene
      key={'recommendArticles'}
      duration={0}
      title={'推荐文章'}
      component={RecommendArticles}
    />

    <Scene
      key={'todoLists'}
      duration={0}
      title={'待办事项'}
      component={TodoLists}
    />

    <Scene
      key={'chapterList'}
      duration={0}
      title={'ChapterList'}
      component={ChapterList}
    />

    <Scene
      key={'aboutUs'}
      title={'关于'}
      component={AboutUs}
    />

    <Scene
      key={'contributorProfile'}
      title={'Contributor Profile'}
      component={ContributorProfile}
    />

    <Scene
      {...navbarPropsTabs}
      key={'grEditor'}
      duration={500}
      title={'编辑器'}
      rightTitle={'Run'}
      rightButtonTextStyle={AppStyles.navbarTitle}
      onRight={() => GrEditor.runCode()}
      component={GrEditor}
    />

  </Scene>,
);
<|endoftext|>