<commit_before>import React from 'react';

const SearchBar = () => {
    return <input />;
};

export default SearchBar;
<commit_msg>create class based component<commit_after>import React, { Component } from 'react';

class SearchBar extends Component {
    render() {
        return <input />;
    }
}

export default SearchBar;
<|endoftext|>


<commit_before>import React from 'react'
import Relay from 'react-relay'
import {BernieColors, BernieText} from './styles/bernie-css'
import {Paper, Styles, FlatButton} from 'material-ui'
import GCForm from './forms/GCForm'
import Form from 'react-formal'
import EventPreview from './EventPreview'
import Dropzone from 'react-dropzone'
import yup from 'yup'
import moment from 'moment'
import MuiThemeProvider from 'material-ui/lib/MuiThemeProvider'
import {BernieTheme} from './styles/bernie-theme'
import stripScripts from '../helpers/stripScripts'

const momentWithTimezone = (startDate, timeZone) => {
  return moment(startDate).tz(timeZone)
}

class EventDataUpload extends React.Component {
  styles = {
    detailsContainer: {
      float: 'left',
      marginTop: '1rem',
      padding: 10,
      width: '50%'
    },

    formContainer: {
      float: 'right',
      marginTop: '1rem',
      padding: 10,
      width: '40%'
    },

    pageContainer: {
      margin: '1rem'
    },

    dropzoneStyle: {
      font: BernieText.default,
      fontSize: '1.5em',
      color: BernieColors.green,
      margin: '0 auto',
      width: '100%',
      minHeight: 300,
      borderWidth: 2,
      borderColor: BernieColors.green,
      borderStyle: 'dashed',
      borderRadius: 5,
      position: 'relative',
      textAlign: 'center',
      overflow: 'scroll'
    },

    dropzoneActiveStyle: {
      borderStyle: 'solid',
      backgroundColor: '#eee'
    },

    dropzoneRejectStyle: {
      borderStyle: 'solid',
      backgroundColor: '#ffdddd'
    },

    fileStatus: {
      ...BernieText.secondaryTitle,
      fontSize: '0.75em',
      textAlign: 'left',
      paddingLeft: 20
    }
  }

  formSchema = yup.object({
    notes: yup.string().required(),
  })

  onDrop = (files) => {
    files.forEach((file) => {
      // Upload files
    })
  }

  renderFileProgress() {
    let count = 0
    let renderErrors = (fileObj) => {
      if (fileObj.errors.length === 0)
        return

      return (

          {fileObj.errors.map((error) => {
            return (

                {`${error.email}, Zip: ${error.zip}, Phone: ${error.phone}`}

                {error.error}

            )
          })}

      )
    }
    let fileNodes = Object.keys(this.state.filesProcessed).map((fileName) => {
      count = count + 1
      let fileObj = this.state.filesProcessed[fileName]
      let color = (fileObj.errors.length === 0 ? (fileObj.totalRows === fileObj.processedRows ? BernieColors.green : BernieColors.gray) : BernieColors.red)

      return (

          {fileName}: {fileObj.processedRows}/{fileObj.totalRows}
          {renderErrors(fileObj)}

      )
    })
    return (

        {fileNodes}

    )
  }

  render() {
    const event = this.props.event
    let formattedDateTime = momentWithTimezone(event.startDate, event.localTimezone)
    formattedDateTime = formattedDateTime ? formattedDateTime.format('LLLL') : event.startDate

    if (!event)
      return

Invalid Event

This event does not exist. If you've just recently created your event.
                this error may resolve itself in a short period of time. It's also
                possible your event was deleted. Please email help@berniesanders.com if you need help.

    return (
      <MuiThemeProvider muiTheme={Styles.getMuiTheme(BernieTheme)}>

{event.name}

{formattedDateTime}

              <GCForm
                schema={this.formSchema}
                defaultValue={{
                  notes: null
                }}
                onSubmit={(formValues) => {
                  this.refs.mutationHandler.send({
                    eventId: this.props.event.id,
                    ...formValues
                  })
                }}
              >

Upload Event Data

                <Form.Field
                  name='notes'
                  multiLine={true}
                  fullWidth={true}
                  label="Notes"
                />

                <Dropzone
                  ref="dropzone"
                  onDrop={this.onDrop}
                  style={this.styles.dropzoneStyle}
                  activeStyle={this.styles.dropzoneActiveStyle}
                  rejectStyle={this.styles.dropzoneRejectStyle}
                  disableClick={true}
                >

                      Drop your Event Files here!

                      <FlatButton
                        label="Select Files to Upload"
                        onTouchTap={() => this.refs.dropzone.open()}
                      />

                </Dropzone>

                <Form.Button type='submit' label='Submit' fullWidth={true} />
              </GCForm>

      </MuiThemeProvider>
    )
  }
}

export default Relay.createContainer(EventDataUpload, {
  fragments: {
    currentUser: () => Relay.QL`
      fragment on User {
        id
        email
      }
    `,
    event: () => Relay.QL`
      fragment on Event {
        attendeesCount
        attendeeVolunteerMessage
        attendeeVolunteerShow
        fastFwdRequest{
          hostMessage
        }
        capacity
        contactPhone
        createDate
        description
        duration
        eventIdObfuscated
        eventType {
          id
          name
        }
        flagApproval
        host {
          id
          firstName
          lastName
          email
        }
        hostReceiveRsvpEmails
        id
        isSearchable
        latitude
        localTimezone
        localUTCOffset
        longitude
        name
        nearbyPeople {
          id
          firstName
          lastName
          email
        }
        publicPhone
        rsvpEmailReminderHours
        rsvpUseReminderEmail
        startDate
        venueAddr1
        venueAddr2
        venueCity
        venueCountry
        venueDirections
        venueName
        venueState
        venueZip
      }
    `
  }
})
<commit_msg>Add filetype select<commit_after>import React from 'react'
import Relay from 'react-relay'
import {BernieColors, BernieText} from './styles/bernie-css'
import {Paper, Styles, FlatButton} from 'material-ui'
import GCForm from './forms/GCForm'
import Form from 'react-formal'
import EventPreview from './EventPreview'
import Dropzone from 'react-dropzone'
import yup from 'yup'
import moment from 'moment'
import MuiThemeProvider from 'material-ui/lib/MuiThemeProvider'
import {BernieTheme} from './styles/bernie-theme'
import stripScripts from '../helpers/stripScripts'

const momentWithTimezone = (startDate, timeZone) => {
  return moment(startDate).tz(timeZone)
}

class EventDataUpload extends React.Component {
  styles = {
    detailsContainer: {
      float: 'left',
      marginTop: '1rem',
      padding: 10,
      width: '50%'
    },

    formContainer: {
      float: 'right',
      marginTop: '1rem',
      padding: 10,
      width: '40%'
    },

    pageContainer: {
      margin: '1rem'
    },

    dropzoneStyle: {
      font: BernieText.default,
      fontSize: '1.5em',
      color: BernieColors.green,
      margin: '0 auto',
      width: '100%',
      minHeight: 300,
      borderWidth: 2,
      borderColor: BernieColors.green,
      borderStyle: 'dashed',
      borderRadius: 5,
      position: 'relative',
      textAlign: 'center',
      overflow: 'scroll'
    },

    dropzoneActiveStyle: {
      borderStyle: 'solid',
      backgroundColor: '#eee'
    },

    dropzoneRejectStyle: {
      borderStyle: 'solid',
      backgroundColor: '#ffdddd'
    },

    fileStatus: {
      ...BernieText.secondaryTitle,
      fontSize: '0.75em',
      textAlign: 'left',
      paddingLeft: 20
    }
  }

  formSchema = yup.object({
    fileType: yup.string().required()
  })

  onDrop = (files) => {
    files.forEach((file) => {
      // Upload files
    })
  }

  renderFileProgress() {
    let count = 0
    let renderErrors = (fileObj) => {
      if (fileObj.errors.length === 0)
        return

      return (

          {fileObj.errors.map((error) => {
            return (

                {`${error.email}, Zip: ${error.zip}, Phone: ${error.phone}`}

                {error.error}

            )
          })}

      )
    }
    let fileNodes = Object.keys(this.state.filesProcessed).map((fileName) => {
      count = count + 1
      let fileObj = this.state.filesProcessed[fileName]
      let color = (fileObj.errors.length === 0 ? (fileObj.totalRows === fileObj.processedRows ? BernieColors.green : BernieColors.gray) : BernieColors.red)

      return (

          {fileName}: {fileObj.processedRows}/{fileObj.totalRows}
          {renderErrors(fileObj)}

      )
    })
    return (

        {fileNodes}

    )
  }

  render() {
    const event = this.props.event
    let formattedDateTime = momentWithTimezone(event.startDate, event.localTimezone)
    formattedDateTime = formattedDateTime ? formattedDateTime.format('LLLL') : event.startDate

    if (!event)
      return

Invalid Event

This event does not exist. If you've just recently created your event.
                this error may resolve itself in a short period of time. It's also
                possible your event was deleted. Please email help@berniesanders.com if you need help.

    return (
      <MuiThemeProvider muiTheme={Styles.getMuiTheme(BernieTheme)}>

{event.name}

{formattedDateTime}

              <GCForm
                schema={this.formSchema}
                defaultValue={{
                  fileType: null
                }}
                onSubmit={(formValues) => {
                  this.refs.mutationHandler.send({
                    eventId: this.props.event.id,
                    ...formValues
                  })
                }}
              >

Upload Event Data

                <Form.Field
                  name='fileType'
                  type='select'
                  label='What are you uploading?'
                  fullWidth={true}
                  choices={{
                    eventPhotos: 'Event Photos',
                    signInSheets: 'Sign-In Sheets',
                    phonebankEventForms: 'Phonebank Event Forms'
                  }}
                />

                <Dropzone
                  ref="dropzone"
                  onDrop={this.onDrop}
                  style={this.styles.dropzoneStyle}
                  activeStyle={this.styles.dropzoneActiveStyle}
                  rejectStyle={this.styles.dropzoneRejectStyle}
                  disableClick={true}
                >

                      Drop your Event Files here!

                      <FlatButton
                        label="Select Files to Upload"
                        onTouchTap={() => this.refs.dropzone.open()}
                      />

                </Dropzone>

                <Form.Button type='submit' label='Submit' fullWidth={true} />
              </GCForm>

      </MuiThemeProvider>
    )
  }
}

export default Relay.createContainer(EventDataUpload, {
  fragments: {
    currentUser: () => Relay.QL`
      fragment on User {
        id
        email
      }
    `,
    event: () => Relay.QL`
      fragment on Event {
        attendeesCount
        attendeeVolunteerMessage
        attendeeVolunteerShow
        fastFwdRequest{
          hostMessage
        }
        capacity
        contactPhone
        createDate
        description
        duration
        eventIdObfuscated
        eventType {
          id
          name
        }
        flagApproval
        host {
          id
          firstName
          lastName
          email
        }
        hostReceiveRsvpEmails
        id
        isSearchable
        latitude
        localTimezone
        localUTCOffset
        longitude
        name
        nearbyPeople {
          id
          firstName
          lastName
          email
        }
        publicPhone
        rsvpEmailReminderHours
        rsvpUseReminderEmail
        startDate
        venueAddr1
        venueAddr2
        venueCity
        venueCountry
        venueDirections
        venueName
        venueState
        venueZip
      }
    `
  }
})
<|endoftext|>


<commit_before>'use strict';

var mongojs = require('mongojs');
var config = require('../config');
var db = mongojs(config.DB);
var departments = db.collection('departments');

function getDepartments(request, reply){
  departments.find(request.query, function (err, data) {
    if(err){
      reply(err);
    } else {
      reply(data);
    }
  });
}

function getDepartment(request, reply){
  departments.findOne({departmentId:request.params.departmentId}, function (err, data) {
    if(err){
      reply(err);
    } else {
      reply(data);
    }
  });
}

module.exports.getDepartments = getDepartments;

module.exports.getDepartment = getDepartment;<commit_msg>Changes to please jscs<commit_after>'use strict';

var mongojs = require('mongojs');
var config = require('../config');
var db = mongojs(config.DB);
var departments = db.collection('departments');

function getDepartments(request, reply) {
  departments.find(request.query, function(err, data) {
    if (err) {
      reply(err);
    } else {
      reply(data);
    }
  });
}

function getDepartment(request, reply) {
  departments.findOne({departmentId:request.params.departmentId}, function(err, data) {
    if (err) {
      reply(err);
    } else {
      reply(data);
    }
  });
}

module.exports.getDepartments = getDepartments;

module.exports.getDepartment = getDepartment;
<|endoftext|>


<commit_before><commit_msg>add quote support for offers<commit_after><|endoftext|>


<commit_before>/**
* Created by njmattes on 5/9/16.
*/

var drag_start = function drag_start() {
  total_pan.x = 0;
  total_pan.y = 0;
};

var dragged = function dragged() {

  var λ = d3.event.dx * sens
    , φ = d3.event.dy * sens
    , upper_drag_limit = projection([0, 90])[1]
    , lower_drag_limit = projection([0, -90])[1] - height
  ;

  console.log(upper_drag_limit, lower_drag_limit, φ);

  if (Math.abs(total_pan.d) > 10) {
    grid_regions.remove();
  }

  total_pan.x += λ;
  total_pan.y += φ;
  // total_pan.d = Math.sqrt(λ * λ + φ * φ);
  total_pan.d = Math.sqrt(Math.pow(total_pan.x, 2) + Math.pow(total_pan.y, 2));

  // φ = -φ > lower_drag_limit ? -lower_drag_limit
  //   : -φ < upper_drag_limit ? -upper_drag_limit
  //   : φ;

  total_pan.y = -total_pan.y > lower_drag_limit ? -lower_drag_limit
    : -total_pan.y < upper_drag_limit ? -upper_drag_limit
    : total_pan.y;

  var c = projection.invert([
    width / 2 - total_pan.x,
    height / 2 - total_pan.y]);

  projection
    .rotate([-c[0], 0])
    // .center([0, c[1]]);
    .center(c);
  svg.selectAll('.boundary').attr('d', path);
};

var drag_end = function drag_end() {

  if (Math.abs(total_pan.d) > 10) {
    //TODO: last_data_request()

    draw_map_basics();

    if (Options.datatype == 'raster') {
      get_grid_data_by_bbox(Options.dataset);
    } else if (Options.datatype == 'polygon') {
      get_agg_by_regions(Options.dataset, Options.regions);
    }

  }
};

var zoomed = function zoomed() {

  var t = d3.event.translate
    , s = d3.event.scale
    , upper_drag_limit = projection([0, 90])[1]
    , lower_drag_limit = projection([0, -90])[1] - height
    ;

  if (upper_drag_limit > 0) {
    t[1] -= upper_drag_limit;
  } else if (lower_drag_limit < 0) {
    t[1] += lower_drag_limit;
  }

  // t[1] = Math.min(height / 2 * (s - projection.scale()) + window.innerHeight / 2 * s,
  //   Math.max(height / 2 * (projection.scale() - s) - window.innerHeight / 2 * s, t[1]));

  zoom.translate(t);
  // zoom.scale(s);

  var c = projection.invert([
    width / 2 - total_pan.x,
    height / 2 - total_pan.y]);

  c0 = projection.center();
  c1 = projection.invert([
    c0[0] + (c0[0] + t[0]),
    c0[1]
  ]);

  console.log(c0, c1);

  // projection
  //   .rotate([-c1[0], 0])
  //   .center([0, c1[1]])
  //   .scale(s);

  // g.style("stroke-width", 1 / s)
  // svg.attr("transform", "translate(" + t + ")scale(" + s + ")");
  projection.translate(t).scale(s);
  svgroot.selectAll('path').attr('d', path);

  // projection.translate(d3.event.translate).scale(d3.event.scale);
  // svgroot.selectAll('path').attr('d', path);
};

var zoomend = function zoomend() {
  draw_map_basics();

  if (Options.datatype == 'raster') {
    get_grid_data_by_bbox(Options.dataset);
  } else if (Options.datatype == 'polygon') {
    get_agg_by_regions(Options.dataset, Options.regions);
  }

  // Options.scale = projection.scale();
  Options.scale = projection.scale() / d3.max([height, width]);

};

var drag_rotate = d3.behavior.drag()
    .origin(function() {
      var r = projection.rotate();
      return {x: r[0] / sens, y: -r[1] / sens}; })
    .on('dragstart', drag_start)
    .on('drag', dragged)
    .on('dragend', drag_end)
  , zoom = d3.behavior.zoom()
    .translate(projection.translate())
    .scale(projection.scale())
    .scaleExtent([height, 8 * height])
    .on('zoom', zoomed)
    .on('zoomend', zoomend)
;

<commit_msg>Track lonlat on pan/zoom<commit_after>/**
* Created by njmattes on 5/9/16.
*/

var drag_start = function drag_start() {
  total_pan.x = 0;
  total_pan.y = 0;
};

var dragged = function dragged() {

  var λ = d3.event.dx * sens
    , φ = d3.event.dy * sens
    , upper_drag_limit = projection([0, 90])[1]
    , lower_drag_limit = projection([0, -90])[1] - height
  ;

  console.log(upper_drag_limit, lower_drag_limit, φ);

  if (Math.abs(total_pan.d) > 10) {
    grid_regions.remove();
  }

  total_pan.x += λ;
  total_pan.y += φ;
  // total_pan.d = Math.sqrt(λ * λ + φ * φ);
  total_pan.d = Math.sqrt(Math.pow(total_pan.x, 2) + Math.pow(total_pan.y, 2));

  // φ = -φ > lower_drag_limit ? -lower_drag_limit
  //   : -φ < upper_drag_limit ? -upper_drag_limit
  //   : φ;

  total_pan.y = -total_pan.y > lower_drag_limit ? -lower_drag_limit
    : -total_pan.y < upper_drag_limit ? -upper_drag_limit
    : total_pan.y;

  var c = projection.invert([
    width / 2 - total_pan.x,
    height / 2 - total_pan.y]);

  projection
    .rotate([-c[0], 0])
    // .center([0, c[1]]);
    .center(c);
  svg.selectAll('.boundary').attr('d', path);
};

var drag_end = function drag_end() {

  if (Math.abs(total_pan.d) > 10) {
    //TODO: last_data_request()

    draw_map_basics();

    if (Options.datatype == 'raster') {
      get_grid_data_by_bbox(Options.dataset);
    } else if (Options.datatype == 'polygon') {
      get_agg_by_regions(Options.dataset, Options.regions);
    }

  }
};

var zoomed = function zoomed() {

  var t = d3.event.translate
    , s = d3.event.scale
    , upper_drag_limit = projection([0, 90])[1]
    , lower_drag_limit = projection([0, -90])[1] - height
    ;

  if (upper_drag_limit > 0) {
    t[1] -= upper_drag_limit;
  } else if (lower_drag_limit < 0) {
    t[1] += lower_drag_limit;
  }

  // t[1] = Math.min(height / 2 * (s - projection.scale()) + window.innerHeight / 2 * s,
  //   Math.max(height / 2 * (projection.scale() - s) - window.innerHeight / 2 * s, t[1]));

  zoom.translate(t);
  // zoom.scale(s);

  var c = projection.invert([
    width / 2 - total_pan.x,
    height / 2 - total_pan.y]);

  c0 = projection.center();
  c1 = projection.invert([
    c0[0] + (c0[0] + t[0]),
    c0[1]
  ]);

  console.log(c0, c1);

  // projection
  //   .rotate([-c1[0], 0])
  //   .center([0, c1[1]])
  //   .scale(s);

  // g.style("stroke-width", 1 / s)
  // svg.attr("transform", "translate(" + t + ")scale(" + s + ")");
  projection.translate(t).scale(s);
  svgroot.selectAll('path').attr('d', path);

  // projection.translate(d3.event.translate).scale(d3.event.scale);
  // svgroot.selectAll('path').attr('d', path);
};

var zoomend = function zoomend() {
  draw_map_basics();

  if (Options.datatype == 'raster') {
    get_grid_data_by_bbox(Options.dataset);
  } else if (Options.datatype == 'polygon') {
    get_agg_by_regions(Options.dataset, Options.regions);
  }

  // Options.scale = projection.scale();
  Options.scale = projection.scale() / d3.max([height, width]);
  var new_center = projection.invert([width/2, height/2]);
  Options.lon = new_center[0];
  Options.lat = new_center[1];

};

var drag_rotate = d3.behavior.drag()
    .origin(function() {
      var r = projection.rotate();
      return {x: r[0] / sens, y: -r[1] / sens}; })
    .on('dragstart', drag_start)
    .on('drag', dragged)
    .on('dragend', drag_end)
  , zoom = d3.behavior.zoom()
    .translate(projection.translate())
    .scale(projection.scale())
    .scaleExtent([height, 8 * height])
    .on('zoom', zoomed)
    .on('zoomend', zoomend)
;

<|endoftext|>


<commit_before>/**
 * Default Configuration
 *
 * Extend the class exported from this module to create your own local
 * configuration objects or use this directly.
 * A configuration file is any ES6 file that exports a single default
 * object containing all of the configuration options.
 *
 * Avoid requiring this file into any file that might need this one.
 * In general game logic should never need this, a config object should
 * be passed around through constructors.
 *
 * Try to keep the structure as flat as possible while grouping things logically
 */

const COLORS = require('../constants/colors');
const GAMES = require('../constants/games');

const Disk = require('../utils/disk');

export default class DefaultConfig {
  constructor({
      username="",
      user0="sculpture0",
      user1="sculpture1",
      user2="sculpture2"
  } = {}) {
    this.user0 = user0;
    this.user1 = user1;
    this.user2 = user2;

    // The username of the current user
    this.username = username || user0;

    // A mapping between usernames and the colors that represent them
    this.USER_COLORS = {
      // username : color
      [this.user0]: COLORS.USER0,
      [this.user1]: COLORS.USER1,
      [this.user2]: COLORS.USER2
    };

    // The sequence of the games to be run. The first game is run on startup
    this.GAMES_SEQUENCE = [
      GAMES.HANDSHAKE,
      GAMES.MOLE,
      GAMES.DISK,
      GAMES.SIMON
    ];

    /******* LIGHTS ********************/
    this.LIGHTS = {
      GAME_STRIPS: ['0','1','2'],
      PERIMETER_STRIP: '3',
      DISK_LIGHT_STRIP: '4'
      HANDSHAKE_STRIP: '5',
      ENVIRONMENT_STRIP: '6'
    }

    /******* GAMES CONFIGURATION *******/

    this.MOLE_GAME = {
      TARGET_PANEL_GROUPS: [
        // Each group will be lit up one at a time
        // When every panel in the group has been pressed, the next group will turn on
        // After the last group the game will end
        // [[stripId, panelId], ...],
        [['0', '3'], ['1', '3'], ['2', '3']],
        [['0', '4'], ['1', '5']],
        [['0', '3'], ['0', '5'], ['2', '4']]
      ],
      // The intensity to use on the lit up panels
      TARGET_PANEL_INTENSITY: 100,
      // The intensity to use once a panel has been pressed
      PANEL_OFF_INTENSITY: 0
    };

    this.DISK_GAME = {
      // The user will wins when they reach these positions for each diskId.
      RELATIVE_TOLERANCE: 3, // degrees tolerance for disks relative to each other
      ABSOLUTE_TOLERANCE: 5, // degrees tolerance for the absolute disk positions
      TARGET_POSITIONS_LEVELS: [
        // level 0
        {
          // diskId: target position
          disk0: 90,
          disk1: 180,
          disk2: 270
        },
        {
          disk0: 45,
          disk1: 225,
          disk2: 90
        },
        {
          disk0: 120,
          disk1: 70,
          disk2: 100
        }
      ],
      CONTROL_MAPPINGS: {
        // stripId
        '0': {
          // panelId -- diskId
          '1': { disk0: Disk.COUNTERCLOCKWISE },
          '2': { disk0: Disk.COUNTERCLOCKWISE },
          '4': { disk1: Disk.COUNTERCLOCKWISE },
          '5': { disk1: Disk.COUNTERCLOCKWISE },
          '7': { disk2: Disk.COUNTERCLOCKWISE },
          '8': { disk2: Disk.COUNTERCLOCKWISE }
        },
        '2': {
          // panelId -- diskId
          '1': { disk0: Disk.CLOCKWISE },
          '2': { disk0: Disk.CLOCKWISE },
          '4': { disk1: Disk.CLOCKWISE },
          '5': { disk1: Disk.CLOCKWISE },
          '7': { disk2: Disk.CLOCKWISE },
          '8': { disk2: Disk.CLOCKWISE }
        }
      }
    };

    this.SIMON_GAME = {
      PATTERN_LEVELS: [
        // level 0 sequence
        {
          stripId: '0',
          // Each array of panel IDs is lit up one at a time
          // Each array within this array is called a "frame" in the "sequence"
          panelSequence: [['3'], ['4'], ['5']]
        },
        // level 1 sequence
        {
          stripId: '1',
          panelSequence: [['3'], ['5'], ['4']]
        },
        // level 2 sequence
        {
          stripId: '2',
          panelSequence: [['3'], ['5'], ['4'], ['6']]
        }
      ],
      // The intensity of the panels when they are pressed or when the sequence is playing
      TARGET_PANEL_INTENSITY: 100,
      // The intensity of the panels that the user can use to play the sequence
      AVAILABLE_PANEL_INTENSITY: 20,
      // The delay in ms between sequence frames
      SEQUENCE_ANIMATION_FRAME_DELAY: 500,
      // The delay in ms to wait before replaying the sequence
      // Only replayed if no input is received from the user
      DELAY_BETWEEN_PLAYS: 5000,
      // The time after input to wait for the user to finish the sequence
      INPUT_TIMEOUT: 10000,
      // The default color to set the panels to when
      DEFAULT_SIMON_PANEL_COLOR: "white"
    };
  }

  getUserColor(username) {
    return this.USER_COLORS[username];
  }
}

<commit_msg>Use symbolic light names<commit_after>/**
 * Default Configuration
 *
 * Extend the class exported from this module to create your own local
 * configuration objects or use this directly.
 * A configuration file is any ES6 file that exports a single default
 * object containing all of the configuration options.
 *
 * Avoid requiring this file into any file that might need this one.
 * In general game logic should never need this, a config object should
 * be passed around through constructors.
 *
 * Try to keep the structure as flat as possible while grouping things logically
 */

const COLORS = require('../constants/colors');
const GAMES = require('../constants/games');

const Disk = require('../utils/disk');

export default class DefaultConfig {
  constructor({
      username="",
      user0="sculpture0",
      user1="sculpture1",
      user2="sculpture2"
  } = {}) {
    this.user0 = user0;
    this.user1 = user1;
    this.user2 = user2;

    // The username of the current user
    this.username = username || user0;

    // A mapping between usernames and the colors that represent them
    this.USER_COLORS = {
      // username : color
      [this.user0]: COLORS.USER0,
      [this.user1]: COLORS.USER1,
      [this.user2]: COLORS.USER2
    };

    // The sequence of the games to be run. The first game is run on startup
    this.GAMES_SEQUENCE = [
      GAMES.HANDSHAKE,
      GAMES.MOLE,
      GAMES.DISK,
      GAMES.SIMON
    ];

    /******* LIGHTS ********************/
    this.LIGHTS = {
      GAME_STRIPS: ['0','1','2'],
      PERIMETER_STRIP: '3',
      DISK_LIGHT_STRIP: '4'
      HANDSHAKE_STRIP: '5',
      ENVIRONMENT_STRIP: '6'
    }

    /******* GAMES CONFIGURATION *******/

    this.MOLE_GAME = {
      TARGET_PANEL_GROUPS: [
        // Each group will be lit up one at a time
        // When every panel in the group has been pressed, the next group will turn on
        // After the last group the game will end
        // [[stripId, panelId], ...],
        [['0', '3'], ['1', '3'], ['2', '3']],
        [['0', '4'], ['1', '5']],
        [['0', '3'], ['0', '5'], ['2', '4']]
      ],
      // The intensity to use on the lit up panels
      TARGET_PANEL_INTENSITY: 100,
      // The intensity to use once a panel has been pressed
      PANEL_OFF_INTENSITY: 0
    };

    this.DISK_GAME = {
      // The user will wins when they reach these positions for each diskId.
      RELATIVE_TOLERANCE: 3, // degrees tolerance for disks relative to each other
      ABSOLUTE_TOLERANCE: 5, // degrees tolerance for the absolute disk positions
      TARGET_POSITIONS_LEVELS: [
        // level 0
        // disks: { diskId: target position }
        // perimeter: { stripId: [panelIds..] }
        { disks:     { disk2: 63, disk1: 111, disk0: 333 },
          perimeter: { this.LIGHTS.PERIMETER: ['0', '2']  }
        },
        // level 1
        { disks:     { disk2: 331,  disk1: 25, disk0: 51 },
          perimeter: { this.LIGHTS.PERIMETER: ['1', '4']  }
        },
        // level 2
        { disks:     { disk2: 0, disk1: 77,  disk0: 314 },
          perimeter: { this.LIGHTS.PERIMETER: ['3', '5']  }
        }
      ],
      LIGHT_MAPPING: {
        // diskId: { stripId: panelId }
        disk0: { this.LIGHTS.DISK_LIGHT_STRIP: '0' },
        disk1: { this.LIGHTS.DISK_LIGHT_STRIP: '1' },
        disk2: { this.LIGHTS.DISK_LIGHT_STRIP: '2' }
      },
      CONTROL_MAPPINGS: {
        // stripId
        '0': {
          // panelId -- diskId
          '1': { disk0: Disk.COUNTERCLOCKWISE },
          '2': { disk0: Disk.COUNTERCLOCKWISE },
          '4': { disk1: Disk.COUNTERCLOCKWISE },
          '5': { disk1: Disk.COUNTERCLOCKWISE },
          '7': { disk2: Disk.COUNTERCLOCKWISE },
          '8': { disk2: Disk.COUNTERCLOCKWISE }
        },
        '2': {
          // panelId -- diskId
          '1': { disk0: Disk.CLOCKWISE },
          '2': { disk0: Disk.CLOCKWISE },
          '4': { disk1: Disk.CLOCKWISE },
          '5': { disk1: Disk.CLOCKWISE },
          '7': { disk2: Disk.CLOCKWISE },
          '8': { disk2: Disk.CLOCKWISE }
        }
      }
    };

    this.SIMON_GAME = {
      PATTERN_LEVELS: [
        // level 0 sequence
        {
          stripId: '0',
          // Each array of panel IDs is lit up one at a time
          // Each array within this array is called a "frame" in the "sequence"
          panelSequence: [['3'], ['4'], ['5']]
        },
        // level 1 sequence
        {
          stripId: '1',
          panelSequence: [['3'], ['5'], ['4']]
        },
        // level 2 sequence
        {
          stripId: '2',
          panelSequence: [['3'], ['5'], ['4'], ['6']]
        }
      ],
      // The intensity of the panels when they are pressed or when the sequence is playing
      TARGET_PANEL_INTENSITY: 100,
      // The intensity of the panels that the user can use to play the sequence
      AVAILABLE_PANEL_INTENSITY: 20,
      // The delay in ms between sequence frames
      SEQUENCE_ANIMATION_FRAME_DELAY: 500,
      // The delay in ms to wait before replaying the sequence
      // Only replayed if no input is received from the user
      DELAY_BETWEEN_PLAYS: 5000,
      // The time after input to wait for the user to finish the sequence
      INPUT_TIMEOUT: 10000,
      // The default color to set the panels to when
      DEFAULT_SIMON_PANEL_COLOR: "white"
    };
  }

  getUserColor(username) {
    return this.USER_COLORS[username];
  }
}

<|endoftext|>


<commit_before>
function WalletController($scope, $q, $http, userService) {
  userService.addAddress( "19P5uCRuqzzi5SDT8Rq6NrNb9dPJNAScjD", "NOPE!" );
  userService.addAddress( "1KRZKBqzcqa4agQbYwN5AuHsjvG9fSo2gW", "NOPE!" );
  userService.addAddress( "1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P", "NOPE!" );

  $scope.addrList = userService.data.addresses.map(function(e,i,a) { return e.address; })
  $scope.addrListBal = []
  $scope.maxCurrencies = [];
  $scope.totals = {}

  $scope.addrList.forEach(function(e,index) {
     $scope.totalsPromise = getData(e);
     $scope.totalsPromise.then(function(successData) {
        $scope.addrListBal[index] = { address: e, balance: successData.balance }

        if(successData.balance.length > 0)
          $scope.maxCurrencies= successData.balance

        for(var i = 0; i < successData.balance.length; i++) {
          var symbolTotal = $scope.totals[successData.balance[i].symbol]
//          console.log(symbolTotal, successData.balance[i].symbol)
          if( ! symbolTotal  )
            $scope.totals[successData.balance[i].symbol] = 0
          $scope.totals[successData.balance[i].symbol] += +successData.balance[i].value
        }
        //console.log($scope)
     },function(errorData) {
        console.log('err', errorData);
     });
  });

  function getData(address) {
    var deferred = $q.defer();

    var file = '/v1/address/addr/' + address + '.json';
    $http.get( file, {} ).success(function(data) {
        return deferred.resolve(data);
    }).error(function(data) {
        return deferred.reject(data);
    });

    return deferred.promise;
  }

}

function WalletHistoryController($scope, $http, userService) {
  $scope.first = userService.data.addresses[0].address
  $scope.addresses = userService.data.addresses

  $scope.getData = function getData(address) {

    var file = '/v1/address/addr/' + address + '.json';
    $http.get( file, {} ).success(
      function(data, status, headers, config) {

        $scope.address = data.address;

        delete data.address;
        delete data.balance;

        var transaction_data = []
        angular.forEach(data[0], function(msc_tx, tx_type ) {
          if( msc_tx instanceof Array && msc_tx.length != 0 ) {
            //DEBUG console.log(tx_type, msc_tx);
            transaction_data = transaction_data.concat(msc_tx);
          }
        });

        angular.forEach(data[1], function(tmsc_tx, tx_type) {
          if( tmsc_tx instanceof Array && tmsc_tx.length != 0 ) {
            //DEBUG console.log(tx_type, tmsc_tx);
            transaction_data = transaction_data.concat(tmsc_tx);
          }
        });

        //sort by date, ascending
        transaction_data = transaction_data.sort(function(a,b) {
            return b.tx_time - a.tx_time;
        });

        angular.forEach(transaction_data, function(transaction, index) {
          //DEBUG console.log(new Date(Number(transaction.tx_time)))
          transaction_data[index].tx_hash = transaction.tx_hash.substring(0,22) + '...'
        });

        $scope.history = transaction_data;
      });
  }
}

function WalletSendController($modal, $scope, $http, $q, userService) {
  //fee tooltip
  $('#fee-tooltip').tooltip({
    title: 'Broadcast Fee: 0.0001 BTC + Dust Fees: 0.00006*4 = 0.00024 Total: 0.00034',
    placement: 'left' });

  $scope.toAddress = ''
 // $scope.isValid = ''

  //a way to add the model to our scope
  $scope.addToScope = function(prop) { }

  //keep errors hidden until user clicks send
  $scope.showErrors = false

  $scope.validateForm = function() {
    var required = [$scope.coin,$scope.address,$scope.sendAmount,$scope.sendTo].map(
      function(val) {
        return angular.isDefined(val);
      });

    var error = 'Please '
    if( required.indexOf(false) != -1) {
       error += 'fill out all given fields, '
    }
    if(( (+$scope.sendAmount + 0.00034) < +$scope.balanceData[0]) == false) {
       error += 'make sure your send amount plus fees isn\'t more than the available count, '
    }
    if( ($scope.coin == 'BTC') &&  (+$scope.sendAmount) < 0.0000543 ) {
       error += 'make sure your send amount is at least 0.00006 (54.3 uBTC minimum) if sending BTC, '
    }
    if( ( ($scope.coin == 'MSC') || ($scope.coin == 'TMSC') ) && +$scope.sendAmount < 0.00000001 ) {
       error += 'make sure your send amount is non-zero, '
    }
    if( validAddress($scope.sendTo) == false) {
       error += 'make sure you are sending to a valid MSC/BTC address, '
    }
    if( error.length < 8) {
      $scope.showErrors = false
      //sendTransaction($scope.sendTo,$scope.address, $scope.sendAmount, $scope.coin, 0.00034)

      // open modal
      var modalInstance = $modal.open({
        template: '\

\

 Confirm send
\

You\'re about to send ' + (+$scope.sendAmount).toFixed(4) + ' ' +
              $scope.coin + ' plus fees to ' + $scope.address + '
\

\
            If the above is correct, please input your passphrase below and press Send Funds.\
            If you encounter an error, feel free to click away from the dialog and try again.\

\
          <input type="password" name=privkey ng-model="privKeyPass.pass" class="form-control"\
            placeholder="enter your private key passphrase">\

\

\

\
              <button ng-disabled="clicked" class="btn btn-primary" ng-click="ok()">Yes, send my funds</button>\
              \

\

\

\

\

 Funds were sent successfully, \
                  check your transaction here.
\

\

\

 Funds could not be sent: \
                   {{error}}
\

\

\

\
        ',
        controller: function($scope,$rootScope, userService,data, sendTransaction, getUnsignedTransaction){
          $scope.sendSuccess = false, $scope.sendError = false, $scope.waiting = false, $scope.privKeyPass = {};
          $scope.ok = function() {
            $scope.clicked = true;
            $scope.waiting = true;
            sendTransaction(data.sendTo, data.sendFrom, data.amt, data.coin,data.fee, $scope.privKeyPass, $scope);
          }
        },
        resolve: {
          data:function(){
            return {
              sendTo: $scope.sendTo,
              sendFrom: $scope.address,
              amt: $scope.sendAmount,
              coin: $scope.coin,
              fee: 0.00034 }
          },
          sendTransaction: function() {
            return sendTransaction;
          },
          getUnsignedTransaction: function() {
            return getUnsignedTransaction;
          },
          sendSignedTransaction: function() {
            return sendSignedTransaction;
          }
        }
      });
    } else {
      error += 'and try again.'
      $scope.error = error
      $scope.showErrors = true
    }
  }

  function validAddress(addr) {
    try{
      var checkValid = new Bitcoin.Address(addr);
      return true
    } catch(e) {
      return false
    }
  }

  $scope.currList = ['MSC', 'TMSC', 'BTC']
  $scope.addrList = getAddressesWithPrivkey()

  function getAddressesWithPrivkey() {
    var addresses = []
    userService.data.addresses.map(
      function(e,i,a) {
        if(e.privkey.length == 58) {
          addresses.push(e.address);
        }
      }
    );
    if( addresses.length == 0)
      addresses = ['Could not find any addresses with attached private keys!']
    return addresses
  }

  $scope.balanceData = ['  -- ']
  var addrListBal = []

  $scope.setCoin = function(coin) {
    $scope.coin = coin;
    if ($scope.address) {
      for(var i = 0; i < addrListBal.length; i++) {
        if( addrListBal[i].address == $scope.address) {
          for(var k = 0; k < addrListBal[i].balance.length; k++) {
            if(addrListBal[i].balance[k].symbol == coin) {
              $scope.balanceData[0] = addrListBal[i].balance[k].value
              //console.log($scope.address, coin, $scope.balanceData, addrListBal[i].balance[k], k)
            }
          }
        }
      }
    }
   }
  $scope.setAddress = function(address) {
    $scope.address = address
    if ($scope.coin) {
      for(var i = 0; i < addrListBal.length; i++) {
        if( addrListBal[i].address == address) {
          for(var k = 0; k < addrListBal[i].balance.length; k++) {
            if(addrListBal[i].balance[k].symbol == $scope.coin) {
              $scope.balanceData[0] = addrListBal[i].balance[k].value
              //console.log($scope.address, $scope.coin, $scope.balanceData, addrListBal[i].balance[k], k)
            }
          }
        }
      }
    }
   }

  $scope.addrList.forEach(function(e,i) {
     var promise = getData(e);
     promise.then(function(successData) {
        addrListBal[i] = { address: e, balance: successData.balance }
     },function(errorData) {
        console.log('Error: not a valid address or address not found, ', e);
     });
  });

  function getData(address) {
    var deferred = $q.defer();

    var file = '/v1/address/addr/' + address + '.json';
    $http.get( file, {} ).success(function(data) {
        return deferred.resolve(data);
    }).error(function(data) {
        return deferred.reject(data);
    });

    return deferred.promise;
  }

  function sendTransaction(to, from, amt, currency, fee, privkeyphrase, $modalScope) {
    $scope.sendTxPromise = getUnsignedTransaction(to, from, amt, currency, fee);
    $scope.sendTxPromise.then(function(successData) {
      var sourceScript = successData.sourceScript;
      var unsignedTransaction = successData.transaction

      var addressData; userService.data.addresses.forEach(function(e,i) { if(e.address == from) addressData = e; });
      try {
        var privKey = new Bitcoin.ECKey.decodeEncryptedFormat(addressData.privkey,privkeyphrase.pass)

        var bytes = Bitcoin.Util.hexToBytes(unsignedTransaction)
        var transaction = Bitcoin.Transaction.deserialize(bytes)
        var script = parseScript(successData.sourceScript)

        transaction.ins[0].script = script

        //DEBUG console.log('before',transaction, Bitcoin.Util.bytesToHex(transaction.serialize()))
        var signedSuccess = transaction.signWithKey(privKey)

        var finalTransaction = Bitcoin.Util.bytesToHex(transaction.serialize())

        //Showing the user the transaction hash doesn't work right now
        //var transactionHash = Bitcoin.Util.bytesToHex(transaction.getHash().reverse())

        sendSignedTransaction(finalTransaction).then(function(successData) {
          if( successData.pushed.match(/submitted|success/gi) != null ) {
            $modalScope.waiting = false
            $modalScope.sendSuccess = true
            $modalScope.url = 'http://blockchain.info/address/' + from + '?sort=0';
          } else {
            $modalScope.waiting = false
            $modalScope.sendError = true
            $modalScope.error = successData.pushed  //Unspecified error, show user
          }
          console.log('server response: ',successData);
        },function(errorData) {
          $modalScope.waiting = false
          $modalScope.sendError = true
          $modalScope.error = 'Could not communicate with server, try again'
          console.log('server error: ',errorData);
        });

        //DEBUG console.log(addressData, privKey, bytes, transaction, script, signedSuccess, finalTransaction );
        function parseScript (script) {
              var newScript = new Bitcoin.Script();
              var s = script.split(" ");
              for (var i = 0; i < s.length; i++) {
                  if (Bitcoin.Opcode.map.hasOwnProperty(s[i])) {
                      newScript.writeOp(Bitcoin.Opcode.map[s[i]]);
                  } else {
                      newScript.writeBytes(Bitcoin.Util.hexToBytes(s[i]));
                  }
              }
              return newScript;
        }
      } catch(e) {
        $modalScope.sendError = true
        $modalScope.error = 'Private key was incorrect'
        console.log('wrong private key',e)
      }
    },function(errorData) {
      $modalScope.sendError = true
      $modalScope.error = 'Could not communicate with server, try again'
      console.log('server error: ', errorData);
    });
  }

  function getUnsignedTransaction(toAddress,fromAddress, amount, currency, fee) {
    var deferred = $q.defer();

    var url = '/v1/transaction/send/';
    $http.post( url, {
      from_address: fromAddress,
      to_address: toAddress,
      amount: amount,
      currency: currency,
      fee: fee
    } ).success(function(data) {
        return deferred.resolve(data);
    }).error(function(data) {
        return deferred.reject(data);
    });

    return deferred.promise;
  }

  function sendSignedTransaction(signedTransaction) {
    var deferred = $q.defer();

    var url = '/v1/transaction/pushtx/';
    $http.post( url, {
      signedTransaction: signedTransaction,
    } ).success(function(data) {
        return deferred.resolve(data);
    }).error(function(data) {
        return deferred.reject(data);
    });

    return deferred.promise;
  }
}
<commit_msg>small privkey/watch addresses fix<commit_after>
function WalletController($scope, $q, $http, userService) {
  userService.addAddress( "19P5uCRuqzzi5SDT8Rq6NrNb9dPJNAScjD", "NOPE!" );
  userService.addAddress( "1KRZKBqzcqa4agQbYwN5AuHsjvG9fSo2gW", "NOPE!" );
  userService.addAddress( "1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P", "NOPE!" );

  $scope.addrList = userService.data.addresses.map(function(e,i,a) { return e.address; })
  $scope.addrListBal = []
  $scope.maxCurrencies = [];
  $scope.totals = {}

  $scope.addrList.forEach(function(e,index) {
     $scope.totalsPromise = getData(e);
     $scope.totalsPromise.then(function(successData) {
        $scope.addrListBal[index] = { address: e, balance: successData.balance }

        if(successData.balance.length > 0)
          $scope.maxCurrencies= successData.balance

        for(var i = 0; i < successData.balance.length; i++) {
          var symbolTotal = $scope.totals[successData.balance[i].symbol]
//          console.log(symbolTotal, successData.balance[i].symbol)
          if( ! symbolTotal  )
            $scope.totals[successData.balance[i].symbol] = 0
          $scope.totals[successData.balance[i].symbol] += +successData.balance[i].value
        }
        //console.log($scope)
     },function(errorData) {
        console.log('err', errorData);
     });
  });

  function getData(address) {
    var deferred = $q.defer();

    var file = '/v1/address/addr/' + address + '.json';
    $http.get( file, {} ).success(function(data) {
        return deferred.resolve(data);
    }).error(function(data) {
        return deferred.reject(data);
    });

    return deferred.promise;
  }

}

function WalletHistoryController($scope, $http, userService) {
  $scope.first = userService.data.addresses[0].address
  $scope.addresses = userService.data.addresses

  $scope.getData = function getData(address) {

    var file = '/v1/address/addr/' + address + '.json';
    $http.get( file, {} ).success(
      function(data, status, headers, config) {

        $scope.address = data.address;

        delete data.address;
        delete data.balance;

        var transaction_data = []
        angular.forEach(data[0], function(msc_tx, tx_type ) {
          if( msc_tx instanceof Array && msc_tx.length != 0 ) {
            //DEBUG console.log(tx_type, msc_tx);
            transaction_data = transaction_data.concat(msc_tx);
          }
        });

        angular.forEach(data[1], function(tmsc_tx, tx_type) {
          if( tmsc_tx instanceof Array && tmsc_tx.length != 0 ) {
            //DEBUG console.log(tx_type, tmsc_tx);
            transaction_data = transaction_data.concat(tmsc_tx);
          }
        });

        //sort by date, ascending
        transaction_data = transaction_data.sort(function(a,b) {
            return b.tx_time - a.tx_time;
        });

        angular.forEach(transaction_data, function(transaction, index) {
          //DEBUG console.log(new Date(Number(transaction.tx_time)))
          transaction_data[index].tx_hash = transaction.tx_hash.substring(0,22) + '...'
        });

        $scope.history = transaction_data;
      });
  }
}

function WalletSendController($modal, $scope, $http, $q, userService) {
  //fee tooltip
  $('#fee-tooltip').tooltip({
    title: 'Broadcast Fee: 0.0001 BTC + Dust Fees: 0.00006*4 = 0.00024 Total: 0.00034',
    placement: 'left' });

  $scope.toAddress = ''
 // $scope.isValid = ''

  //a way to add the model to our scope
  $scope.addToScope = function(prop) { }

  //keep errors hidden until user clicks send
  $scope.showErrors = false

  $scope.validateForm = function() {
    var required = [$scope.coin,$scope.address,$scope.sendAmount,$scope.sendTo].map(
      function(val) {
        return angular.isDefined(val);
      });

    var error = 'Please '
    if( required.indexOf(false) != -1) {
       error += 'fill out all given fields, '
    }
    if(( (+$scope.sendAmount + 0.00034) < +$scope.balanceData[0]) == false) {
       error += 'make sure your send amount plus fees isn\'t more than the available count, '
    }
    if( ($scope.coin == 'BTC') &&  (+$scope.sendAmount) < 0.0000543 ) {
       error += 'make sure your send amount is at least 0.00006 (54.3 uBTC minimum) if sending BTC, '
    }
    if( ( ($scope.coin == 'MSC') || ($scope.coin == 'TMSC') ) && +$scope.sendAmount < 0.00000001 ) {
       error += 'make sure your send amount is non-zero, '
    }
    if( validAddress($scope.sendTo) == false) {
       error += 'make sure you are sending to a valid MSC/BTC address, '
    }
    if( error.length < 8) {
      $scope.showErrors = false
      //sendTransaction($scope.sendTo,$scope.address, $scope.sendAmount, $scope.coin, 0.00034)

      // open modal
      var modalInstance = $modal.open({
        template: '\

\

 Confirm send
\

You\'re about to send ' + (+$scope.sendAmount).toFixed(4) + ' ' +
              $scope.coin + ' plus fees to ' + $scope.address + '
\

\
            If the above is correct, please input your passphrase below and press Send Funds.\
            If you encounter an error, feel free to click away from the dialog and try again.\

\
          <input type="password" name=privkey ng-model="privKeyPass.pass" class="form-control"\
            placeholder="enter your private key passphrase">\

\

\

\
              <button ng-disabled="clicked" class="btn btn-primary" ng-click="ok()">Yes, send my funds</button>\
              \

\

\

\

\

 Funds were sent successfully, \
                  check your transaction here.
\

\

\

 Funds could not be sent: \
                   {{error}}
\

\

\

\
        ',
        controller: function($scope,$rootScope, userService,data, sendTransaction, getUnsignedTransaction){
          $scope.sendSuccess = false, $scope.sendError = false, $scope.waiting = false, $scope.privKeyPass = {};
          $scope.ok = function() {
            $scope.clicked = true;
            $scope.waiting = true;
            sendTransaction(data.sendTo, data.sendFrom, data.amt, data.coin,data.fee, $scope.privKeyPass, $scope);
          }
        },
        resolve: {
          data:function(){
            return {
              sendTo: $scope.sendTo,
              sendFrom: $scope.address,
              amt: $scope.sendAmount,
              coin: $scope.coin,
              fee: 0.00034 }
          },
          sendTransaction: function() {
            return sendTransaction;
          },
          getUnsignedTransaction: function() {
            return getUnsignedTransaction;
          },
          sendSignedTransaction: function() {
            return sendSignedTransaction;
          }
        }
      });
    } else {
      error += 'and try again.'
      $scope.error = error
      $scope.showErrors = true
    }
  }

  function validAddress(addr) {
    try{
      var checkValid = new Bitcoin.Address(addr);
      return true
    } catch(e) {
      return false
    }
  }

  $scope.currList = ['MSC', 'TMSC', 'BTC']
  $scope.addrList = getAddressesWithPrivkey()

  function getAddressesWithPrivkey() {
    var addresses = []
    userService.data.addresses.map(
      function(e,i,a) {
        if(e.privkey && e.privkey.length == 58) {
          addresses.push(e.address);
        }
      }
    );
    if( addresses.length == 0)
      addresses = ['Could not find any addresses with attached private keys!']
    return addresses
  }

  $scope.balanceData = ['  -- ']
  var addrListBal = []

  $scope.setCoin = function(coin) {
    $scope.coin = coin;
    if ($scope.address) {
      for(var i = 0; i < addrListBal.length; i++) {
        if( addrListBal[i].address == $scope.address) {
          for(var k = 0; k < addrListBal[i].balance.length; k++) {
            if(addrListBal[i].balance[k].symbol == coin) {
              $scope.balanceData[0] = addrListBal[i].balance[k].value
              //console.log($scope.address, coin, $scope.balanceData, addrListBal[i].balance[k], k)
            }
          }
        }
      }
    }
   }
  $scope.setAddress = function(address) {
    $scope.address = address
    if ($scope.coin) {
      for(var i = 0; i < addrListBal.length; i++) {
        if( addrListBal[i].address == address) {
          for(var k = 0; k < addrListBal[i].balance.length; k++) {
            if(addrListBal[i].balance[k].symbol == $scope.coin) {
              $scope.balanceData[0] = addrListBal[i].balance[k].value
              //console.log($scope.address, $scope.coin, $scope.balanceData, addrListBal[i].balance[k], k)
            }
          }
        }
      }
    }
   }

  $scope.addrList.forEach(function(e,i) {
     var promise = getData(e);
     promise.then(function(successData) {
        addrListBal[i] = { address: e, balance: successData.balance }
     },function(errorData) {
        console.log('Error: not a valid address or address not found, ', e);
     });
  });

  function getData(address) {
    var deferred = $q.defer();

    var file = '/v1/address/addr/' + address + '.json';
    $http.get( file, {} ).success(function(data) {
        return deferred.resolve(data);
    }).error(function(data) {
        return deferred.reject(data);
    });

    return deferred.promise;
  }

  function sendTransaction(to, from, amt, currency, fee, privkeyphrase, $modalScope) {
    $scope.sendTxPromise = getUnsignedTransaction(to, from, amt, currency, fee);
    $scope.sendTxPromise.then(function(successData) {
      var sourceScript = successData.sourceScript;
      var unsignedTransaction = successData.transaction

      var addressData; userService.data.addresses.forEach(function(e,i) { if(e.address == from) addressData = e; });
      try {
        var privKey = new Bitcoin.ECKey.decodeEncryptedFormat(addressData.privkey,privkeyphrase.pass)

        var bytes = Bitcoin.Util.hexToBytes(unsignedTransaction)
        var transaction = Bitcoin.Transaction.deserialize(bytes)
        var script = parseScript(successData.sourceScript)

        transaction.ins[0].script = script

        //DEBUG console.log('before',transaction, Bitcoin.Util.bytesToHex(transaction.serialize()))
        var signedSuccess = transaction.signWithKey(privKey)

        var finalTransaction = Bitcoin.Util.bytesToHex(transaction.serialize())

        //Showing the user the transaction hash doesn't work right now
        //var transactionHash = Bitcoin.Util.bytesToHex(transaction.getHash().reverse())

        sendSignedTransaction(finalTransaction).then(function(successData) {
          if( successData.pushed.match(/submitted|success/gi) != null ) {
            $modalScope.waiting = false
            $modalScope.sendSuccess = true
            $modalScope.url = 'http://blockchain.info/address/' + from + '?sort=0';
          } else {
            $modalScope.waiting = false
            $modalScope.sendError = true
            $modalScope.error = successData.pushed  //Unspecified error, show user
          }
          console.log('server response: ',successData);
        },function(errorData) {
          $modalScope.waiting = false
          $modalScope.sendError = true
          $modalScope.error = 'Could not communicate with server, try again'
          console.log('server error: ',errorData);
        });

        //DEBUG console.log(addressData, privKey, bytes, transaction, script, signedSuccess, finalTransaction );
        function parseScript (script) {
              var newScript = new Bitcoin.Script();
              var s = script.split(" ");
              for (var i = 0; i < s.length; i++) {
                  if (Bitcoin.Opcode.map.hasOwnProperty(s[i])) {
                      newScript.writeOp(Bitcoin.Opcode.map[s[i]]);
                  } else {
                      newScript.writeBytes(Bitcoin.Util.hexToBytes(s[i]));
                  }
              }
              return newScript;
        }
      } catch(e) {
        $modalScope.sendError = true
        $modalScope.error = 'Private key was incorrect'
        console.log('wrong private key',e)
      }
    },function(errorData) {
      $modalScope.sendError = true
      $modalScope.error = 'Could not communicate with server, try again'
      console.log('server error: ', errorData);
    });
  }

  function getUnsignedTransaction(toAddress,fromAddress, amount, currency, fee) {
    var deferred = $q.defer();

    var url = '/v1/transaction/send/';
    $http.post( url, {
      from_address: fromAddress,
      to_address: toAddress,
      amount: amount,
      currency: currency,
      fee: fee
    } ).success(function(data) {
        return deferred.resolve(data);
    }).error(function(data) {
        return deferred.reject(data);
    });

    return deferred.promise;
  }

  function sendSignedTransaction(signedTransaction) {
    var deferred = $q.defer();

    var url = '/v1/transaction/pushtx/';
    $http.post( url, {
      signedTransaction: signedTransaction,
    } ).success(function(data) {
        return deferred.resolve(data);
    }).error(function(data) {
        return deferred.reject(data);
    });

    return deferred.promise;
  }
}
<|endoftext|>


<commit_before>'use strict';

var _      = require('lodash');
var util   = require('util');
var path   = require('path');
var fs     = require('fs');
var crypto = require('crypto');
var fm     = require('zeon-front-matter');
var fsHelper = require('../helper/file');
var swig   = require('swig');

swig.setDefaults({ varControls: ['{$', '$}'] });

var reg = {
  // sectuib
  section: /(<!--\[section (\S+?)\]\[\/section\]-->)|(<!--\[section (\S+?)\]-->[\s\S]*?<!--\[\/section\]-->)/ig,
  // html body
  body: /<body[^>]*?>([\s\S]*)<\/body>/ig,
  // 匹配link:css标签以及style标签
  css: /(?:[^>\n\r]*)(<link\s*.*href=["'].*\.s?css["'?].*\/?>|<style[^>]*>(?:[\S\s]*?)<\/style>)[\n\r]*/ig,
  // 匹配css文件路径
  cssPath: /href=(?:"|')?([^"' >]+)(?:"|')?/i,
  // 匹配css文件
  cssFile: /(?:[^"' >\/]+)\.s?css(?=["'?])/i,
  // 匹配script标签
  js: /(?:[^>\n\r]*)(<script[^>]*>(?:[\s\S]*?)<\/script\s*>)[\n\r]*/ig,
  // 匹配js文件路径
  jsPath: /^(?:[^>\n\r]*)<script[^>]+src=(?:"|')\s*(\S+)\s*(?:"|')/i,
  // 匹配js文件名
  jsFile: /(?:[^"' >\/]+)\.js(?=["'?])/i,
  // img
  img: /<img\s*.*src=["'].*\.(jpg|png|gif|bmp|jpeg|ico)["'?].*\/?>/ig,
  imgPath: /src=(?:"|')?([^"' >]+)(?:"|')?/i
}

/**
 * 渲染页面
 * @param  {string} filepath 页面路径
 * @return {string}          页面内容
 */
var renderHTML = function (filepath) {
  var baseDir = this.base_dir || '';
  var config = this.user_option || {};

  // get page content
  var fileContent = fs.readFileSync(filepath, 'utf-8');
  var page_data = fm.parse(fileContent);
  var page_content = page_data._content;

  // layout
  var layout = false;
  if (page_data.hasOwnProperty('layout')) {
    layout = page_data.layout;
  } else if (config && config.layout && config.layout.default) {
    layout = config.layout.default;
  }

  // if no layout, just render html
  if (!config.layout.enable || !layout) return page_content;

  // has layout
  var layoutPath = path.join(baseDir, config.dir.layout, layout + '.html');

  if (fs.existsSync(layoutPath)) {
    var layout_data = layoutRenderer(layoutPath, config);
    return pageRendererWithLayout(filepath, page_content, layout_data, config);
  } else {
    return page_content;
  }

};
module.exports = exports = renderHTML;

//==============================================================================================

// 模板渲染
function layoutRenderer (layout_path, config) {
  // 数据对象
  var data = {
    content: '',
    template: '',
    css: {
      md5: [],
      list: [],
      path: []
    },
    js: {
      md5: [],
      list: [],
      path: []
    },
    absolute_path: layout_path
  };
  // 路径参数
  var path_parse = path.parse(layout_path);

  // 获取内容
  data.content = data.template = fs.readFileSync(layout_path, 'utf-8');

  // 替换section节点为swig block
  data.template = data.template.replace(reg.section, function () {
    var type = arguments[2] || arguments[4];
    return '{% block ' + type + ' %}{% endblock %}'
  });

  // 替换img
  data.template = data.template.replace(reg.img, function () {
    var relative_path = arguments[0].match(reg.imgPath)[1];
    var absolute_path = fsHelper.getFilepath(relative_path, config, config.dir._layout);
    var path_with_root = setUrlRootParam(absolute_path, config);
    return arguments[0].replace(relative_path, path_with_root);
  });

  // 提取css信息
  data.template = data.template.replace(reg.css, function () {
    var current_data = {}
    var content = arguments[0];

    var result = '';

    if (reg.cssPath.test(arguments[1])) {
      // 外部样式
      var href = arguments[0].match(reg.cssPath)[1];

      current_data.type = 1;
      current_data.absolute_path = path.join(path_parse.dir, href);

      data.css.path.push(current_data.absolute_path);

      var tmpl_url = setUrlRootParam(current_data.absolute_path, config);

      result = arguments[0].replace(href, tmpl_url);

    } else {
      // 内部样式
      current_data.type = 0;
      current_data.content = content;
      result = content;
    }
    data.css.list.push(current_data);
    return result;
  });

  // 提取js信息
  data.template = data.template.replace(reg.js, function () {
    var current_data = {}
    var content = arguments[0];

    var result = '';

    if (reg.jsPath.test(arguments[1])) {
      // 外部样式
      var href = arguments[0].match(reg.jsPath)[1];

      current_data.type = 1;
      current_data.absolute_path = path.join(path_parse.dir, href);

      data.js.path.push(current_data.absolute_path);

      var tmpl_url = setUrlRootParam(current_data.absolute_path, config);

      result = arguments[0].replace(href, tmpl_url);

    } else {
      // 内部样式
      current_data.type = 0;
      current_data.content = content;
      result = content;
    }
    data.js.list.push(current_data);
    return result;
  });

  return data;
}

// 页面渲染
function pageRendererWithLayout (page_path, page_content, layout_data, config) {
  var path_parse = path.parse(page_path);
  var data = '';
  var temp = page_content;

  // css
  var css_data = [];
  temp = temp.replace(reg.css, function () {
    if (reg.cssPath.test(arguments[1])) {
      // 外部样式
      var relative_path = arguments[0].match(reg.cssPath)[1];
      var absolute_path = path.join(path_parse.dir, relative_path);

      if (!_.includes(layout_data.css.path, absolute_path)) {
        var root_path = setUrlRootParam(absolute_path, config);
        css_data.push(arguments[0].replace(relative_path, root_path));
      }

    } else {
      // 内部样式
      css_data.push(arguments[0]);
    }
    return '';
  });
  data += '{% block style %}\n' + css_data.join('') + '{% endblock %}\n';

  // js
  var js_data = [];
  temp = temp.replace(reg.js, function () {
    if (reg.jsPath.test(arguments[1])) {
      // 外部样式
      var relative_path = arguments[0].match(reg.jsPath)[1];
      var absolute_path = path.join(path_parse.dir, relative_path);

      if (!_.includes(layout_data.js.path, absolute_path)) {
        var root_path = setUrlRootParam(absolute_path, config);
        js_data.push(arguments[0].replace(relative_path, root_path));
      }

    } else {
      // 内部样式
      js_data.push(arguments[0]);
    }
    return '';
  });
  data += '{% block script %}\n' + js_data.join('') + '{% endblock %}\n';

  // body
  var body_content = temp.match(reg.body)[0];
  body_content = body_content.replace(/^<body>/ig, '').replace(/<\/body>$/ig, '');
  data += '{% block content %}\n' + body_content + '\n{% endblock %}\n';

  // swig render
  var layout_code = path.join(config.dir._root, encodeURIComponent(layout_data.absolute_path));

  data = '{% extends "' + layout_code + '" %}\n' + data;

  var template = {};
  template[layout_code] = layout_data.template;
  swig.invalidateCache();
  swig.setDefaults({ loader: swig.loaders.memory(template) });

  var page_relative_path = path.relative(path_parse.dir, config.dir._module);
  page_relative_path == '' ? page_relative_path = '.' : null;
  page_relative_path = page_relative_path.replace(/\\/ig, '/');

  var content = swig.render(data, {
    locals: {
      _root: page_relative_path
    },
    filename: path.join(config.dir._root, encodeURIComponent(page_path))
  });

  return content;
}

//==============================================================================================

// 添加root参数
function setUrlRootParam (target_path, config) {
  var file_uri = target_path;
  if (typeof target_path != 'string') return target_path;
  // 是否在common中
  if (target_path.indexOf(config.dir._common) === 0) {
    file_uri = target_path.replace(config.dir._common, '').replace(/\\/ig, '/');
  }
  else if (target_path.indexOf(config.dir._module) === 0) {
    file_uri = target_path.replace(config.dir._module, '').replace(/\\/ig, '/');
  }
  else if (target_path.indexOf(config.dir._component) === 0) {
    file_uri = '/component' + target_path.replace(config.dir._component, '').replace(/\\/ig, '/');
  }
  else if (target_path.indexOf(config.dir._lib) === 0) {
    file_uri = '/lib' + target_path.replace(config.dir._lib, '').replace(/\\/ig, '/');
  }
  else {
    return target_path;
  }
  return '{$_root$}' + file_uri;
}

function getHash (data) {
  var md5sum = crypto.createHash('md5'),
    encoding = typeof data === 'string' ? 'utf8' : 'binary';
  md5sum.update(data, encoding);
  return md5sum.digest('hex');
};
<commit_msg>update<commit_after>'use strict';

var _        = require('lodash');
var path     = require('path');
var fs       = require('fs');
var util     = require('util');
var crypto   = require('crypto');
var swig     = require('swig');
var fm       = require('zeon-front-matter');
var fsHelper = require('../helper/file');

swig.setDefaults({ varControls: ['{$', '$}'] });

var reg = {
  // section
  section: /(<!--\[section (\S+?)\]\[\/section\]-->)|(<!--\[section (\S+?)\]-->[\s\S]*?<!--\[\/section\]-->)/ig,
  // include
  include: /(<!--\[include (\S+?)\]\[\/include\]-->)|(<!--\[include (\S+?)\]-->[\s\S]*?<!--\[\/include\]-->)/ig,
  // html body
  body: /<body[^>]*?>([\s\S]*)<\/body>/ig,
  // 匹配link:css标签以及style标签
  css: /(?:[^>\n\r]*)(<link\s*.*href=["'].*\.s?css["'?].*\/?>|<style[^>]*>(?:[\S\s]*?)<\/style>)[\n\r]*/ig,
  // 匹配css文件路径
  cssPath: /href=(?:"|')?([^"' >]+)(?:"|')?/i,
  // 匹配css文件
  cssFile: /(?:[^"' >\/]+)\.s?css(?=["'?])/i,
  // 匹配script标签
  js: /(?:[^>\n\r]*)(<script[^>]*>(?:[\s\S]*?)<\/script\s*>)[\n\r]*/ig,
  // 匹配js文件路径
  jsPath: /^(?:[^>\n\r]*)<script[^>]+src=(?:"|')\s*(\S+)\s*(?:"|')/i,
  // 匹配js文件名
  jsFile: /(?:[^"' >\/]+)\.js(?=["'?])/i,
  // img
  img: /<img\s*.*src=["'].*\.(jpg|png|gif|bmp|jpeg|ico)["'?].*\/?>/ig,
  imgPath: /src=(?:"|')?([^"' >]+)(?:"|')?/i
}

/**
 * 渲染页面
 * @param  {string} filepath 页面路径
 * @return {string}          页面内容
 */
var renderHTML = function (filepath) {
  var baseDir = this.base_dir || '';
  var config = this.user_option || {};

  var d = getPageData(filepath, config);

  return getPageContent(d, config);

  // get page content
  var fileContent = fs.readFileSync(filepath, 'utf8');
  var page_data = fm.parse(fileContent);
  var page_content = page_data._content;

  // layout
  var layout = false;
  if (page_data.hasOwnProperty('layout')) {
    layout = page_data.layout;
  } else if (config && config.layout && config.layout.default) {
    layout = config.layout.default;
  }

  // if no layout, just render html
  if (!config.layout.enable || !layout) return page_content;

  // has layout
  var layoutPath = path.join(baseDir, config.dir.layout, layout + '.html');

  if (fs.existsSync(layoutPath)) {
    var layout_data = layoutRenderer(layoutPath, config);
    return pageRendererWithLayout(filepath, page_content, layout_data, config);
  } else {
    return page_content;
  }
};
module.exports = exports = renderHTML;

//==============================================================================================

// 模板渲染
function layoutRenderer (layout_path, config) {
  // 数据对象
  var data = {
    content: '',
    template: '',
    css: {
      md5: [],
      list: [],
      path: []
    },
    js: {
      md5: [],
      list: [],
      path: []
    },
    absolute_path: layout_path
  };
  // 路径参数
  var path_parse = path.parse(layout_path);

  // 获取内容
  data.content = data.template = fs.readFileSync(layout_path, 'utf8');

  // 替换section节点为swig block
  data.template = data.template.replace(reg.section, function () {
    var type = arguments[2] || arguments[4];
    return '{% block ' + type + ' %}{% endblock %}'
  });

  // 替换img
  data.template = data.template.replace(reg.img, function () {
    var relative_path = arguments[0].match(reg.imgPath)[1];
    var absolute_path = fsHelper.getFilepath(relative_path, config, config.dir._layout);
    var path_with_root = setUrlRootParam(absolute_path, config);
    return arguments[0].replace(relative_path, path_with_root);
  });

  // 提取css信息
  data.template = data.template.replace(reg.css, function () {
    var current_data = {}
    var content = arguments[0];

    var result = '';

    if (reg.cssPath.test(arguments[1])) {
      // 外部样式
      var href = arguments[0].match(reg.cssPath)[1];

      current_data.type = 1;
      current_data.absolute_path = path.join(path_parse.dir, href);

      data.css.path.push(current_data.absolute_path);

      var tmpl_url = setUrlRootParam(current_data.absolute_path, config);

      result = arguments[0].replace(href, tmpl_url);

    } else {
      // 内部样式
      current_data.type = 0;
      current_data.content = content;
      result = content;
    }
    data.css.list.push(current_data);
    return result;
  });

  // 提取js信息
  data.template = data.template.replace(reg.js, function () {
    var current_data = {}
    var content = arguments[0];

    var result = '';

    if (reg.jsPath.test(arguments[1])) {
      // 外部样式
      var href = arguments[0].match(reg.jsPath)[1];

      current_data.type = 1;
      current_data.absolute_path = path.join(path_parse.dir, href);

      data.js.path.push(current_data.absolute_path);

      var tmpl_url = setUrlRootParam(current_data.absolute_path, config);

      result = arguments[0].replace(href, tmpl_url);

    } else {
      // 内部样式
      current_data.type = 0;
      current_data.content = content;
      result = content;
    }
    data.js.list.push(current_data);
    return result;
  });

  return data;
}

// 页面渲染
function pageRendererWithLayout (page_path, page_content, layout_data, config) {
  var path_parse = path.parse(page_path);
  var data = '';
  var temp = page_content;

  temp = temp.replace(reg.include, function () {
    var relative_path = arguments[2] ;
    var absolute_path = path.join(path_parse.dir, relative_path);
    var partial_data = getPartialData(absolute_path, config);
    return '';
  });

  // css
  var css_data = [];
  temp = temp.replace(reg.css, function () {
    if (reg.cssPath.test(arguments[1])) {
      // 外部样式
      var relative_path = arguments[0].match(reg.cssPath)[1];
      var absolute_path = path.join(path_parse.dir, relative_path);

      if (!_.includes(layout_data.css.path, absolute_path)) {
        var root_path = setUrlRootParam(absolute_path, config);
        css_data.push(arguments[0].replace(relative_path, root_path));
      }

    } else {
      // 内部样式
      css_data.push(arguments[0]);
    }
    return '';
  });
  data += '{% block style %}\n' + css_data.join('') + '{% endblock %}\n';

  // js
  var js_data = [];
  temp = temp.replace(reg.js, function () {
    if (reg.jsPath.test(arguments[1])) {
      // 外部样式
      var relative_path = arguments[0].match(reg.jsPath)[1];
      var absolute_path = path.join(path_parse.dir, relative_path);

      if (!_.includes(layout_data.js.path, absolute_path)) {
        var root_path = setUrlRootParam(absolute_path, config);
        js_data.push(arguments[0].replace(relative_path, root_path));
      }

    } else {
      // 内部样式
      js_data.push(arguments[0]);
    }
    return '';
  });
  data += '{% block script %}\n' + js_data.join('') + '{% endblock %}\n';

  // body
  var body_content = temp.match(reg.body)[0];
  body_content = body_content.replace(/^<body>/ig, '').replace(/<\/body>$/ig, '');
  data += '{% block content %}\n' + body_content + '\n{% endblock %}\n';

  // swig render
  var layout_code = path.join(config.dir._root, encodeURIComponent(layout_data.absolute_path));

  data = '{% extends "' + layout_code + '" %}\n' + data;

  var template = {};
  template[layout_code] = layout_data.template;
  swig.invalidateCache();
  swig.setDefaults({ loader: swig.loaders.memory(template) });

  var page_relative_path = path.relative(path_parse.dir, config.dir._module);
  page_relative_path == '' ? page_relative_path = '.' : null;
  page_relative_path = page_relative_path.replace(/\\/ig, '/');

  var content = swig.render(data, {
    locals: {
      _root: page_relative_path
    },
    filename: path.join(config.dir._root, encodeURIComponent(page_path))
  });

  return content;
}

function getPageContent (data, config) {
  if (!data.layout) return data._content;

  var path_parse = path.parse(data.path);

  var temp = '';

  // css
  temp += '{% block style %}\n';
  var css_data = unionDataId(data.layout.css, data.css);
  for (var i = 0, l = css_data.length; i < l; i++) {
    temp += css_data[i].content;
  }
  temp += '{% endblock %}\n';

  // js
  temp += '{% block script %}\n';
  var js_data = unionDataId(data.layout.js, data.js);
  for (var i = 0, l = js_data.length; i < l; i++) {
    temp += js_data[i].content;
  }
  temp += '{% endblock %}\n';

  // content
  temp += '{% block content %}\n';
  temp += data.content;
  temp += '{% endblock %}\n';

  // swig render
  var layout_code = path.join(config.dir._root, encodeURIComponent(data.layout.id));
  temp = '{% extends "' + layout_code + '" %}\n' + temp;

  var template = {};
  template[layout_code] = data.layout.template;
  swig.invalidateCache();
  swig.setDefaults({ loader: swig.loaders.memory(template) });

  var page_relative_path = path.relative(path_parse.dir, config.dir._module);
  page_relative_path == '' ? page_relative_path = '.' : null;
  page_relative_path = page_relative_path.replace(/\\/ig, '/');

  var content = swig.render(temp, {
    locals: {
      _root: page_relative_path
    },
    filename: path.join(config.dir._root, encodeURIComponent(data.path))
  });

  return content;
}

//==============================================================================================

function getLayoutData (absolute_path, config) {
  var data = {
    id: absolute_path,
    path: absolute_path,
    template: '',
    js: [],
    css: [],
    content: '',
    _content: ''
  };

  var path_parse = path.parse(absolute_path);

  // read file content
  var temp = data.template = data._content = fs.readFileSync(absolute_path, 'utf8');

  // 替换section节点为swig block
  data.template = data.template.replace(reg.section, function () {
    var type = arguments[2] || arguments[4];
    return '{% block ' + type + ' %}{% endblock %}'
  });

  // css
  data.template = data.template.replace(reg.css, function () {
    var css_data = getStyleData(arguments[1], config, path_parse.dir);
    if (css_data) {
      data.css.push(css_data);
    }
    return css_data.content;
  });

  // js
  data.template = data.template.replace(reg.js, function () {
    var js_data = getScriptData(arguments[1], config, path_parse.dir);
    if (js_data) {
      data.js.push(js_data);
    }
    return js_data.content;
  });

  // body
  data.content = getBodyData(temp);

  return data;
}

function getPartialData (absolute_path, config) {
  var data = {
    id: absolute_path,
    path: absolute_path,
    js: [],
    css: [],
    content: '',
    _content: ''
  };

  var path_parse = path.parse(absolute_path);

  // read file content
  var temp = data._content = fs.readFileSync(absolute_path, 'utf8');

  // css
  temp = temp.replace(reg.css, function () {
    var css_data = getStyleData(arguments[1], config, path_parse.dir);
    if (css_data) {
      data.css.push(css_data);
    }
    return '';
  });

  // js
  temp = temp.replace(reg.js, function () {
    var js_data = getScriptData(arguments[1], config, path_parse.dir);
    if (js_data) {
      data.js.push(js_data);
    }
    return '';
  });

  // partial
  temp = temp.replace(reg.include, function () {
    var relative_path = arguments[2] ;
    var absolute_path = path.join(path_parse.dir, relative_path);
    var partial_data = getPartialData(absolute_path, config);

    // data.js = data.js.concat(partial_data.js);
    // data.css = data.css.concat(partial_data.css);

    data.js = unionDataId(data.js, partial_data.js);
    data.css = unionDataId(data.css, partial_data.css);

    return partial_data.content;
  });

  // body
  data.content = getBodyData(temp);

  return data;
}

function getPageData (absolute_path, config) {
  var data = {
    id: absolute_path,
    path: absolute_path,
    layout: null,
    js: [],
    css: [],
    content: '',
    _content: ''
  };

  var path_parse = path.parse(absolute_path);

  // read file content
  var file_content = fs.readFileSync(absolute_path, 'utf8');

  // layout
  var page_data = fm.parse(file_content);
  var temp = data._content = page_data._content;

  // layout
  var layout = false;
  if (page_data.hasOwnProperty('layout')) {
    layout = page_data.layout;
  } else if (config && config.layout && config.layout.default) {
    layout = config.layout.default;
  }

  // has layout
  var layout_path = path.join(config.dir._layout, layout + '.html');

  if (fs.existsSync(layout_path)) {
    data.layout = getLayoutData(layout_path, config);
  } else {
    data.layout = false;
  }

  // css
  temp = temp.replace(reg.css, function () {
    var css_data = getStyleData(arguments[1], config, path_parse.dir);
    if (css_data) {
      data.css.push(css_data);
    }
    return '';
  });

  // js
  temp = temp.replace(reg.js, function () {
    var js_data = getScriptData(arguments[1], config, path_parse.dir);
    if (js_data) {
      data.js.push(js_data);
    }
    return '';
  });

  // partial
  temp = temp.replace(reg.include, function () {
    var relative_path = arguments[2] ;
    var absolute_path = path.join(path_parse.dir, relative_path);
    var partial_data = getPartialData(absolute_path, config);

    // data.js = data.js.concat(partial_data.js);
    // data.css = data.css.concat(partial_data.css);

    data.js = unionDataId(data.js, partial_data.js);
    data.css = unionDataId(data.css, partial_data.css);

    return partial_data.content;
  });

  // body
  data.content = getBodyData(temp);

  return data;
}

//==============================================================================================

function getStyleData (content, config, page_path) {
  var data = {
    id: '',
    path: '',
    content: '',
    is_external: true
  };

  if (reg.cssPath.test(content)) {
    data.is_external = true;

    var relative_path = content.match(reg.cssPath)[1];
    var absolute_path = data.path = path.join(page_path, relative_path);

    data.id = getHash(absolute_path);
    // data.content = content.replace(relative_path, setUrlRootParam(absolute_path, config));
    data.content = '<link rel="stylesheet" href="' + setUrlRootParam(absolute_path, config) + '">';

  } else {
    data.is_external = false;

    data.id = getHash(content);
    data.content = content;
  }

  return data;
}
function getScriptData (content, config, page_path) {
  var data = {
    id: '',
    path: '',
    content: '',
    is_external: true
  };

  if (reg.jsPath.test(content)) {
    data.is_external = true;

    var relative_path = content.match(reg.jsPath)[1];
    var absolute_path = data.path = path.join(page_path, relative_path);

    data.id = getHash(absolute_path);
    // data.content = content.replace(relative_path, setUrlRootParam(absolute_path, config));
    data.content = '<script src="' + setUrlRootParam(absolute_path, config) + '"></script>';

  } else {
    data.is_external = false;

    data.id = getHash(content);
    data.content = content;
  }

  return data;
}
function getBodyData (content) {
  var body_content = content.match(reg.body)[0];
  body_content = body_content.replace(/^<body>/ig, '').replace(/<\/body>$/ig, '');
  return body_content;
}

//==============================================================================================

// 添加root参数
function setUrlRootParam (target_path, config) {
  var file_uri = target_path;
  if (typeof target_path != 'string') return target_path;
  // 是否在common中
  if (target_path.indexOf(config.dir._common) === 0) {
    file_uri = target_path.replace(config.dir._common, '').replace(/\\/ig, '/');
  }
  else if (target_path.indexOf(config.dir._module) === 0) {
    file_uri = target_path.replace(config.dir._module, '').replace(/\\/ig, '/');
  }
  else if (target_path.indexOf(config.dir._component) === 0) {
    file_uri = '/component' + target_path.replace(config.dir._component, '').replace(/\\/ig, '/');
  }
  else if (target_path.indexOf(config.dir._lib) === 0) {
    file_uri = '/lib' + target_path.replace(config.dir._lib, '').replace(/\\/ig, '/');
  }
  else {
    return target_path;
  }
  return '{$_root$}' + file_uri;
}

// 过滤重复的id对象
function unionDataId () {
  var new_data = [];
  if (arguments.length == 0) {
    return [];
  }
  else if (arguments.length == 1) {
    return arguments[0];
  }
  else {
    var temp1 = arguments[0].concat();
    var temp2 = arguments[1].concat();
    var temp = [];
    var ids = [];

    for (var i = 0, l1 = temp1.length; i < l1; i++) {
      ids.push(temp1[i].id);
    }

    for (var j = 0, l2 = temp2.length; j < l2; j++) {
      if (_.indexOf(ids, temp2[j].id) == -1) {
        temp.push(temp2[j]);
        ids.push(temp2[j].id);
      }
    }

    new_data = temp1.concat(temp);

    var eventData = Array.prototype.slice.call(arguments, 2);
    eventData.unshift(new_data);

    new_data = unionDataId.apply(unionDataId, eventData);
  }
  return new_data;
}

// 获取内容MD5
function getHash (data) {
  var md5sum = crypto.createHash('md5'),
    encoding = typeof data === 'string' ? 'utf8' : 'binary';
  md5sum.update(data, encoding);
  return md5sum.digest('hex');
}
<|endoftext|>


<commit_before>const pibrary = {};

pibrary.pi = function () {
  return Math.PI;
};

pibrary.digitAt = function () {
  return 3;
};

export default pibrary;
<commit_msg>pibrary.digitAt is almost real<commit_after>// HELPER FUNCTIONS

function getMathPIStringNoDecimal () {
  // divide by 10 to get decimal on left
  const mathPIDivTen = Math.PI / 10;

  // convert to string
  const mathPIString = '' + mathPIDivTen;

  // leave out decimal
  return mathPiString.substring(1);
};

function lengthOfMathPI () {
  return getMathPIStringNoDecimal().length;
};

function getDigitFromMathPI (index) {
  return getMathPIStringNoDecimal.charat(index);
};

// PIBRARY
const pibrary = {};

pibrary.pi = function () {
  return Math.PI;
};

/*
 * zero-indexed
 * 0 would return 3, 1 would return 1, 2 would return 4, etc
 */
pibrary.digitAt = function (index) {
  if ( index < lengthOfMathPI() ) {
    return getDigitFromMathPI(index);
  }

  // otherwise need to actually calculate digit of pi
  return -1;
};

export default pibrary;
<|endoftext|>