<commit_before>var common     = require('../common');
var assert     = require('assert');
var Validation = require('../../lib/Validators');
var _; // undefined

Validation.rangeNumber(0, 10)(5, checkValidation());
Validation.rangeNumber(_, 10)(-5, checkValidation());
Validation.rangeNumber(-10, _)(-5, checkValidation());
Validation.rangeNumber(0, 10)(-5, checkValidation('out-of-range-number'));
Validation.rangeNumber(_, 10)(15, checkValidation('out-of-range-number'));
Validation.rangeNumber(0, _)(-5, checkValidation('out-of-range-number'));
Validation.rangeNumber(0, _, 'custom-error')(-5, checkValidation('custom-error'));

Validation.rangeLength(0, 10)('test', checkValidation());
Validation.rangeLength(_, 10)('test', checkValidation());
Validation.rangeLength(0, _)('test', checkValidation());
Validation.rangeLength(4, _)('test', checkValidation());
Validation.rangeLength(0, _)(_, checkValidation('undefined'));
Validation.rangeLength(0, 3)('test', checkValidation('out-of-range-length'));
Validation.rangeLength(5, _)('test', checkValidation('out-of-range-length'));
Validation.rangeLength(_, 3)('test', checkValidation('out-of-range-length'));
Validation.rangeLength(_, 3, 'custom-error')('test', checkValidation('custom-error'));

Validation.insideList([ 1, 2, 3 ])(1, checkValidation());
Validation.insideList([ 1, 2, 3 ])(3, checkValidation());
Validation.insideList([ 1, 2, 3 ])(4, checkValidation('outside-list'));
Validation.insideList([ 1, 2, 3 ])('1', checkValidation('outside-list'));
Validation.insideList([ 1, 2, 3 ])('', checkValidation('outside-list'));
Validation.insideList([ 1, 2, 3 ])([], checkValidation('outside-list'));
Validation.insideList([ 1, 2, 3 ], 'custom-error')([], checkValidation('custom-error'));

Validation.outsideList([ 1, 2, 3 ])(4, checkValidation());
Validation.outsideList([ 1, 2, 3 ])(-2, checkValidation());
Validation.outsideList([ 1, 2, 3 ])('', checkValidation());
Validation.outsideList([ 0, 2, 3 ])(null, checkValidation());
Validation.outsideList([ 1, 2, 3 ])('2', checkValidation());
Validation.outsideList([ 1, 2, 3 ])(2, checkValidation('inside-list'));
Validation.outsideList([ 1, 2, 3 ], 'custom-error')(2, checkValidation('custom-error'));

Validation.notEmptyString()('a', checkValidation());
Validation.notEmptyString()('', checkValidation('empty-string'));
Validation.notEmptyString('custom-error')('', checkValidation('custom-error'));
Validation.notEmptyString()(_, checkValidation('undefined'));
Validation.notEmptyString('custom-error')(_, checkValidation('undefined'));

function checkValidation(ret1) {
	return function (ret2) {
		assert.strictEqual(ret1, ret2);
	};
}
<commit_msg>Fixes deprecated test. For now it needs to keep working. We need to some way avoid de 'deprecated folder'<commit_after>var common     = require('../../common');
var assert     = require('assert');
var Validation = require('../../../lib/Validators');
var _; // undefined

Validation.rangeNumber(0, 10)(5, checkValidation());
Validation.rangeNumber(_, 10)(-5, checkValidation());
Validation.rangeNumber(-10, _)(-5, checkValidation());
Validation.rangeNumber(0, 10)(-5, checkValidation('out-of-range-number'));
Validation.rangeNumber(_, 10)(15, checkValidation('out-of-range-number'));
Validation.rangeNumber(0, _)(-5, checkValidation('out-of-range-number'));
Validation.rangeNumber(0, _, 'custom-error')(-5, checkValidation('custom-error'));

Validation.rangeLength(0, 10)('test', checkValidation());
Validation.rangeLength(_, 10)('test', checkValidation());
Validation.rangeLength(0, _)('test', checkValidation());
Validation.rangeLength(4, _)('test', checkValidation());
Validation.rangeLength(0, _)(_, checkValidation('undefined'));
Validation.rangeLength(0, 3)('test', checkValidation('out-of-range-length'));
Validation.rangeLength(5, _)('test', checkValidation('out-of-range-length'));
Validation.rangeLength(_, 3)('test', checkValidation('out-of-range-length'));
Validation.rangeLength(_, 3, 'custom-error')('test', checkValidation('custom-error'));

Validation.insideList([ 1, 2, 3 ])(1, checkValidation());
Validation.insideList([ 1, 2, 3 ])(3, checkValidation());
Validation.insideList([ 1, 2, 3 ])(4, checkValidation('outside-list'));
Validation.insideList([ 1, 2, 3 ])('1', checkValidation('outside-list'));
Validation.insideList([ 1, 2, 3 ])('', checkValidation('outside-list'));
Validation.insideList([ 1, 2, 3 ])([], checkValidation('outside-list'));
Validation.insideList([ 1, 2, 3 ], 'custom-error')([], checkValidation('custom-error'));

Validation.outsideList([ 1, 2, 3 ])(4, checkValidation());
Validation.outsideList([ 1, 2, 3 ])(-2, checkValidation());
Validation.outsideList([ 1, 2, 3 ])('', checkValidation());
Validation.outsideList([ 0, 2, 3 ])(null, checkValidation());
Validation.outsideList([ 1, 2, 3 ])('2', checkValidation());
Validation.outsideList([ 1, 2, 3 ])(2, checkValidation('inside-list'));
Validation.outsideList([ 1, 2, 3 ], 'custom-error')(2, checkValidation('custom-error'));

Validation.notEmptyString()('a', checkValidation());
Validation.notEmptyString()('', checkValidation('empty-string'));
Validation.notEmptyString('custom-error')('', checkValidation('custom-error'));
Validation.notEmptyString()(_, checkValidation('undefined'));
Validation.notEmptyString('custom-error')(_, checkValidation('undefined'));

function checkValidation(ret1) {
	return function (ret2) {
		assert.strictEqual(ret1, ret2);
	};
}
<|endoftext|>


<commit_before>import React, {Component} from 'react'
import MainComponent from './../Components/MainComponent'
import {
  getEmptyApiDefinition, postApiRequest, getApiRequest, apiCall, formatTestParameters,
  getEmptyUserInfo } from './../Utils'
import { DOMAIN_NAME } from './../Constant'

export default class AuthoringInterfaceContainer extends Component {
  constructor(props) {
    super(props)
    this.state = {
      charts: [],
      selectedChartIndex: 0,
      saveInProgress: false,
      savedStatus: true,
      userInfo: getEmptyUserInfo(),
      currentChartMode: null,
      databases: []
    }
  }

  componentDidMount() {
    getApiRequest(DOMAIN_NAME+'charts/', null,
                    (response)=>this.loadInitialCharts(response),
                     this.loadInitialCharts, null)
    getApiRequest(DOMAIN_NAME+'user/', null,
       (data) => {this.setState({userInfo: data})},
        (error) => console.error(e), null)
    getApiRequest(DOMAIN_NAME+'databases/', null,
                  (data) => {
                    this.setState({databases: data.databases})
                  },
                  (error) => console.error(error), null)
  }

  onChartSaved = () => {
    this.setState({'savedStatus': true, 'saveInProgress': false})
  }

  onChartSaveError = (e) => {
    this.setState({'savedStatus': false, 'saveInProgress': false})
  }

  saveChart = (chart) => {
    if (chart.id && chart.database) {
      this.setState({'saveInProgress': true},
            postApiRequest(DOMAIN_NAME+'charts/', {'chart': chart},
            this.onChartSaved,this.onChartSaveError, null)
      )
    }
  }

  // Updates the selected chart index and updates the selected chart name in the URL
  onChartDeleted = (index, callback) => {
    const {selectedChartIndex, charts} = this.state
    if(charts.length > 1) {
      let charts = JSON.parse(JSON.stringify(this.state.charts)),
        newChartIndex = (selectedChartIndex !== 0)?selectedChartIndex - 1:selectedChartIndex
      charts.splice(index, 1)
      this.setState({
        charts: charts,
        selectedChartIndex: newChartIndex,
        savedStatus: true,
        saveInProgress: false,
        currentChartMode: (charts[newChartIndex].can_edit || false)
      }, () => {
        callback.constructor === 'Function' || callback()
      })
    } else {
      this.setState({
        charts: [],
        selectedChartIndex: 0,
        savedStatus: true,
        saveInProgress: false,
        currentChartMode: false
      }, () => {
        callback.constructor === 'Function' ||callback()
      })
    }
  }

  // Calls the Delete chart API and triggers onChartDelete function if the API
  // is successfull
  chartDeletionHandler = (index, callback) => {
    const chartId = this.state.charts[index].id
    this.setState({'saveInProgress': true},
                  apiCall(DOMAIN_NAME+'charts/', JSON.stringify({'id': chartId}), 'DELETE',
                  () => this.onChartDeleted(index, callback),this.onChartSaveError, null)
    )
  }

  onNewChartSaved = (newChartIndex, id) => {
    let charts = JSON.parse(JSON.stringify(this.state.charts))
    charts[newChartIndex].id = id
    this.setState({'charts': charts, 'savedStatus': true, 'saveInProgress': false},
     ()=> this.saveChart(charts[newChartIndex]))
  }

  saveNewChart = (newChartIndex) => {
    this.setState({'saveInProgress': true},
          postApiRequest(DOMAIN_NAME+'charts/', {'chart': this.state.charts[newChartIndex]},
          (id) => this.onNewChartSaved(newChartIndex, id),this.onChartSaveError, null)
    )
  }

  loadInitialCharts = (response) => {
    let charts = [],
    tempChart = {}
    if (response && response.length !== 0) {
      response.map(chart => {
        tempChart = chart
        tempChart.testParameters = {}
        charts.push(tempChart)
      })
      this.setState({charts: charts}, ()=> {
        const { selectedChartIndex, charts } = this.state
        const currentPath = window.location.pathname.split('/')
        // If there is a string after / , set the selected chart else set the
        // chart name in the URL
        if (currentPath[1] !== '') {
          const chartInUrl = currentPath[1]
          if (charts[selectedChartIndex].name !== decodeURIComponent(chartInUrl)) {
            let chartIndex = undefined
            charts.map((chart, i) => {
              if(chart.name === chartInUrl) {
                chartIndex = i
              }
            })
            if(chartIndex) {
              this.setState({selectedChartIndex: chartIndex, currentChartMode: charts[chartIndex].can_edit || false}, this.setUrlPath)
            } else {
              alert('Chart not found')
              this.setState({selectedChartIndex: 0}, this.setUrlPath)
            }
          } else {
            this.setUrlPath()
          }
        } else {
          this.setUrlPath()
        }
      })
    }
  }

  // Updates the URL with the selected chart name
  setUrlPath() {
    const { selectedChartIndex, charts } = this.state
    const selectedChart = charts[selectedChartIndex]
    const canEditUrl = (charts[selectedChartIndex].can_edit) ? 'edit' : 'view'
    const newUrl = '/' + selectedChart.name + '/' + canEditUrl
    this.setState({currentChartMode: charts[selectedChartIndex].can_edit || false})
    window.history.replaceState('', '', newUrl);
  }

  // A generic function to handle change in any property inside the selected chart
  selectedChartChangeHandler = (key, value, callback=null, index) => {
    let charts = JSON.parse(JSON.stringify(this.state.charts)),
      chartIndex = index ? index : this.state.selectedChartIndex
    charts[chartIndex][key] = value
    if (key === 'name') {
      charts[chartIndex].url = value.replace(/ /g, '-').toLowerCase()
    }
    this.setState({charts: charts}, ()=>{this.saveChart(charts[chartIndex]); (callback) && callback()})
  }

  // Updates the selected chart's chart data with the result set returned by the
  // query written by the user
  onSuccessTest = (data) => {
    let currentChartData = [...this.state.charts]
    currentChartData[this.state.selectedChartIndex]['chartData'] = data
    currentChartData[this.state.selectedChartIndex].apiErrorMsg = null
    this.setState({charts: currentChartData})
  }

  // Updates the selected chart with the error message recieved from the backend
  onErrorTest = (e) => {
    let charts = JSON.parse(JSON.stringify(this.state.charts))
    charts[this.state.selectedChartIndex].apiErrorMsg = e.responseJSON.error
    this.setState({charts: charts})
  }

  // Handles click event on run button. This function makes a POST call to get
  // result set of the query written by the user and triggers onSuccessTest if
  // the API is successfull
  onHandleTestButton = () => {
    const selectedChart = this.state.charts[this.state.selectedChartIndex]
    if(!selectedChart.database) {
      alert('Please select a database to run the query on')
      return
    }

    let payloadObj = formatTestParameters(selectedChart.parameters, 'name', 'test_value')
    postApiRequest(DOMAIN_NAME+'squealy/'+selectedChart.url+'/', payloadObj,
                    this.onSuccessTest, this.onErrorTest, 'table')
  }

  //Appends an empty API definition object to current API Definitions
  chartAdditionHandler = (name) => {
    //TODO: open the addition modal and add the new chart to state also making it the selected chart
    let charts = JSON.parse(JSON.stringify(this.state.charts)),
        newChart = getEmptyApiDefinition()
        newChart.name = name
        newChart.can_edit = true
        newChart.url = name.replace(/ /g, '-').toLowerCase()
    let newChartIndex = charts.push(newChart) - 1
    this.setState({
      charts: charts
    }, ()=>this.saveNewChart(newChartIndex))
  }

  //Changes the selected API index to the one which was clicked from the API list
  chartSelectionHandler = (index) => {
    this.setState({selectedChartIndex: index, currentChartMode: this.state.charts[index].can_edit || false},
      () => this.setUrlPath())
  }

  shouldComponentUpdate(nextProps, nextState) {
    if (nextState !== nextProps) {
      return true
    }
  }

  updateViewMode = (val, editPermission) => {
    if (editPermission) {
      const { selectedChartIndex, charts } = this.state
      const newUrl = '/' + charts[selectedChartIndex].name + '/' + (val ? 'view' : 'edit') + '/'
      this.setState({currentChartMode: !val}, () => {
        window.history.replaceState('', '', newUrl);
      })
    }
  }

  render () {
    const {
      charts,
      selectedChartIndex,
      parameters,
      savedStatus,
      saveInProgress,
      userInfo,
      currentChartMode,
      databases
    } = this.state
    const { googleDefined } = this.props
    return (

        <MainComponent
          userInfo={userInfo}
          charts={charts}
          saveInProgress={saveInProgress}
          savedStatus={savedStatus}
          onHandleTestButton={this.onHandleTestButton}
          selectedChartIndex={selectedChartIndex}
          googleDefined={googleDefined}
          chartAdditionHandler={this.chartAdditionHandler}
          chartSelectionHandler={this.chartSelectionHandler}
          chartDeletionHandler={this.chartDeletionHandler}
          selectedChartChangeHandler={this.selectedChartChangeHandler}
          currentChartMode={currentChartMode}
          updateViewMode={this.updateViewMode}
          databases={databases}
        />

    )
  }
}
<commit_msg>Resolved code commits<commit_after>import React, {Component} from 'react'
import MainComponent from './../Components/MainComponent'
import {
  getEmptyApiDefinition, postApiRequest, getApiRequest, apiCall, formatTestParameters,
  getEmptyUserInfo } from './../Utils'
import { DOMAIN_NAME } from './../Constant'

export default class AuthoringInterfaceContainer extends Component {
  constructor(props) {
    super(props)
    this.state = {
      charts: [],
      selectedChartIndex: 0,
      saveInProgress: false,
      savedStatus: true,
      userInfo: getEmptyUserInfo(),
      currentChartMode: null,
      databases: []
    }
  }

  componentDidMount() {
    getApiRequest(DOMAIN_NAME+'charts/', null,
                    (response)=>this.loadInitialCharts(response),
                     this.loadInitialCharts, null)
    getApiRequest(DOMAIN_NAME+'user/', null,
       (data) => {this.setState({userInfo: data})},
        (error) => console.error(e), null)
    getApiRequest(DOMAIN_NAME+'databases/', null,
                  (data) => {
                    this.setState({databases: data.databases})
                  },
                  (error) => console.error(error), null)
  }

  onChartSaved = () => {
    this.setState({'savedStatus': true, 'saveInProgress': false})
  }

  onChartSaveError = (e) => {
    this.setState({'savedStatus': false, 'saveInProgress': false})
  }

  saveChart = (chart) => {
    if (chart.id && chart.database) {
      this.setState({'saveInProgress': true},
            postApiRequest(DOMAIN_NAME+'charts/', {'chart': chart},
            this.onChartSaved,this.onChartSaveError, null)
      )
    }
  }

  // Updates the selected chart index and updates the selected chart name in the URL
  onChartDeleted = (index, callback) => {
    const {selectedChartIndex, charts} = this.state
    if(charts.length > 1) {
      let charts = JSON.parse(JSON.stringify(this.state.charts)),
        newChartIndex = (selectedChartIndex !== 0)?selectedChartIndex - 1:selectedChartIndex
      charts.splice(index, 1)
      this.setState({
        charts: charts,
        selectedChartIndex: newChartIndex,
        savedStatus: true,
        saveInProgress: false,
        currentChartMode: (charts[newChartIndex].can_edit || false)
      }, () => {
        callback.constructor === 'Function' || callback()
      })
    } else {
      this.setState({
        charts: [],
        selectedChartIndex: 0,
        savedStatus: true,
        saveInProgress: false,
        currentChartMode: false
      }, () => {
        callback.constructor === 'Function' || callback()
      })
    }
  }

  // Calls the Delete chart API and triggers onChartDelete function if the API
  // is successfull
  chartDeletionHandler = (index, callback) => {
    const chartId = this.state.charts[index].id
    this.setState({'saveInProgress': true},
                  apiCall(DOMAIN_NAME+'charts/', JSON.stringify({'id': chartId}), 'DELETE',
                  () => this.onChartDeleted(index, callback),this.onChartSaveError, null)
    )
  }

  onNewChartSaved = (newChartIndex, id) => {
    let charts = JSON.parse(JSON.stringify(this.state.charts))
    charts[newChartIndex].id = id
    this.setState({'charts': charts, 'savedStatus': true, 'saveInProgress': false},
     ()=> this.saveChart(charts[newChartIndex]))
  }

  saveNewChart = (newChartIndex) => {
    this.setState({'saveInProgress': true},
          postApiRequest(DOMAIN_NAME+'charts/', {'chart': this.state.charts[newChartIndex]},
          (id) => this.onNewChartSaved(newChartIndex, id),this.onChartSaveError, null)
    )
  }

  loadInitialCharts = (response) => {
    let charts = [],
    tempChart = {}
    if (response && response.length !== 0) {
      response.map(chart => {
        tempChart = chart
        tempChart.testParameters = {}
        charts.push(tempChart)
      })
      this.setState({charts: charts}, ()=> {
        const { selectedChartIndex, charts } = this.state
        const currentPath = window.location.pathname.split('/')
        // If there is a string after / , set the selected chart else set the
        // chart name in the URL
        if (currentPath[1] !== '') {
          const chartInUrl = currentPath[1]
          if (charts[selectedChartIndex].name !== decodeURIComponent(chartInUrl)) {
            let chartIndex = undefined
            charts.map((chart, i) => {
              if(chart.name === chartInUrl) {
                chartIndex = i
              }
            })
            if(chartIndex) {
              this.setState({selectedChartIndex: chartIndex, currentChartMode: charts[chartIndex].can_edit || false}, this.setUrlPath)
            } else {
              alert('Chart not found')
              this.setState({selectedChartIndex: 0}, this.setUrlPath)
            }
          } else {
            this.setUrlPath()
          }
        } else {
          this.setUrlPath()
        }
      })
    }
  }

  // Updates the URL with the selected chart name
  setUrlPath() {
    const { selectedChartIndex, charts } = this.state
    const selectedChart = charts[selectedChartIndex]
    const canEditUrl = (charts[selectedChartIndex].can_edit) ? 'edit' : 'view'
    const newUrl = '/' + selectedChart.name + '/' + canEditUrl
    this.setState({currentChartMode: charts[selectedChartIndex].can_edit || false})
    window.history.replaceState('', '', newUrl);
  }

  // A generic function to handle change in any property inside the selected chart
  selectedChartChangeHandler = (key, value, callback=null, index) => {
    let charts = JSON.parse(JSON.stringify(this.state.charts)),
      chartIndex = index ? index : this.state.selectedChartIndex
    charts[chartIndex][key] = value
    if (key === 'name') {
      charts[chartIndex].url = value.replace(/ /g, '-').toLowerCase()
    }
    this.setState({charts: charts}, ()=>{this.saveChart(charts[chartIndex]); (callback) && callback()})
  }

  // Updates the selected chart's chart data with the result set returned by the
  // query written by the user
  onSuccessTest = (data) => {
    let currentChartData = [...this.state.charts]
    currentChartData[this.state.selectedChartIndex]['chartData'] = data
    currentChartData[this.state.selectedChartIndex].apiErrorMsg = null
    this.setState({charts: currentChartData})
  }

  // Updates the selected chart with the error message recieved from the backend
  onErrorTest = (e) => {
    let charts = JSON.parse(JSON.stringify(this.state.charts))
    charts[this.state.selectedChartIndex].apiErrorMsg = e.responseJSON.error
    this.setState({charts: charts})
  }

  // Handles click event on run button. This function makes a POST call to get
  // result set of the query written by the user and triggers onSuccessTest if
  // the API is successfull
  onHandleTestButton = () => {
    const selectedChart = this.state.charts[this.state.selectedChartIndex]
    if(!selectedChart.database) {
      alert('Please select a database to run the query on')
      return
    }

    let payloadObj = formatTestParameters(selectedChart.parameters, 'name', 'test_value')
    postApiRequest(DOMAIN_NAME+'squealy/'+selectedChart.url+'/', payloadObj,
                    this.onSuccessTest, this.onErrorTest, 'table')
  }

  //Appends an empty API definition object to current API Definitions
  chartAdditionHandler = (name) => {
    //TODO: open the addition modal and add the new chart to state also making it the selected chart
    let charts = JSON.parse(JSON.stringify(this.state.charts)),
        newChart = getEmptyApiDefinition()
        newChart.name = name
        newChart.can_edit = true
        newChart.url = name.replace(/ /g, '-').toLowerCase()
    let newChartIndex = charts.push(newChart) - 1
    this.setState({
      charts: charts
    }, ()=>this.saveNewChart(newChartIndex))
  }

  //Changes the selected API index to the one which was clicked from the API list
  chartSelectionHandler = (index) => {
    this.setState({selectedChartIndex: index, currentChartMode: this.state.charts[index].can_edit || false},
      () => this.setUrlPath())
  }

  shouldComponentUpdate(nextProps, nextState) {
    if (nextState !== nextProps) {
      return true
    }
  }

  updateViewMode = (val, editPermission) => {
    if (editPermission) {
      const { selectedChartIndex, charts } = this.state
      const newUrl = '/' + charts[selectedChartIndex].name + '/' + (val ? 'view' : 'edit') + '/'
      this.setState({currentChartMode: !val}, () => {
        window.history.replaceState('', '', newUrl);
      })
    }
  }

  render () {
    const {
      charts,
      selectedChartIndex,
      parameters,
      savedStatus,
      saveInProgress,
      userInfo,
      currentChartMode,
      databases
    } = this.state
    const { googleDefined } = this.props
    return (

        <MainComponent
          userInfo={userInfo}
          charts={charts}
          saveInProgress={saveInProgress}
          savedStatus={savedStatus}
          onHandleTestButton={this.onHandleTestButton}
          selectedChartIndex={selectedChartIndex}
          googleDefined={googleDefined}
          chartAdditionHandler={this.chartAdditionHandler}
          chartSelectionHandler={this.chartSelectionHandler}
          chartDeletionHandler={this.chartDeletionHandler}
          selectedChartChangeHandler={this.selectedChartChangeHandler}
          currentChartMode={currentChartMode}
          updateViewMode={this.updateViewMode}
          databases={databases}
        />

    )
  }
}
<|endoftext|>


<commit_before>/* global $ */

import { Parser, HtmlRenderer } from 'commonmark'

const Util = {
  // helper function to determine how many lines are needed
  // Line Splitter Function
  // copyright Stephen Chapman, 19th April 2006
  // you may copy this code but please keep the copyright notice as well
  splitLine: function (st, n) {
    var b = ''
    var s = st ? st : ''
    while (s.length > n) {
      var c = s.substring(0, n)
      var d = c.lastIndexOf(' ')
      var e = c.lastIndexOf('\n')
      if (e != -1) d = e
      if (d == -1) d = n
      b += c.substring(0, d) + '\n'
      s = s.substring(d + 1)
    }
    return b + s
  },

  nowDateFormatted: function (date = new Date(Date.now())) {
    const month = (date.getMonth() + 1) < 10 ? '0' + (date.getMonth() + 1) : (date.getMonth() + 1)
    const day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate()
    const year = date.getFullYear()

    return month + '/' + day + '/' + year
  },

  decodeEntities: function (desc) {
    var str, temp = document.createElement('p')
    temp.innerHTML = desc // browser handles the topics
    str = temp.textContent || temp.innerText
    temp = null // delete the element
    return str
  }, // decodeEntities

  getDistance: function (p1, p2) {
    return Math.sqrt(Math.pow((p2.x - p1.x), 2) + Math.pow((p2.y - p1.y), 2))
  },

  // Try using Visualize.mGraph
  coordsToPixels: function (mGraph, coords) {
    if (mGraph) {
      var canvas = mGraph.canvas,
        s = canvas.getSize(),
        p = canvas.getPos(),
        ox = canvas.translateOffsetX,
        oy = canvas.translateOffsetY,
        sx = canvas.scaleOffsetX,
        sy = canvas.scaleOffsetY
      var pixels = {
        x: (coords.x / (1 / sx)) + p.x + s.width / 2 + ox,
        y: (coords.y / (1 / sy)) + p.y + s.height / 2 + oy
      }
      return pixels
    } else {
      return {
        x: 0,
        y: 0
      }
    }
  },

  // Try using Visualize.mGraph
  pixelsToCoords: function (mGraph, pixels) {
    var coords
    if (mGraph) {
      var canvas = mGraph.canvas,
        s = canvas.getSize(),
        p = canvas.getPos(),
        ox = canvas.translateOffsetX,
        oy = canvas.translateOffsetY,
        sx = canvas.scaleOffsetX,
        sy = canvas.scaleOffsetY
      coords = {
        x: (pixels.x - p.x - s.width / 2 - ox) * (1 / sx),
        y: (pixels.y - p.y - s.height / 2 - oy) * (1 / sy),
      }
    } else {
      coords = {
        x: 0,
        y: 0
      }
    }
    return coords
  },
  getPastelColor: function (opts = {}) {
    const rseed = opts.rseed === undefined ? Math.random() : opts.rseed
    const gseed = opts.gseed === undefined ? Math.random() : opts.gseed
    const bseed = opts.bseed === undefined ? Math.random() : opts.bseed
    var r = (Math.round(rseed * 127) + 127).toString(16)
    var g = (Math.round(gseed * 127) + 127).toString(16)
    var b = (Math.round(bseed * 127) + 127).toString(16)
    return Util.colorLuminance('#' + r + g + b, -0.4)
  },
  // darkens a hex value by 'lum' percentage
  colorLuminance: function (hex, lum) {
    // validate hex string
    hex = String(hex).replace(/[^0-9a-f]/gi, '')
    if (hex.length < 6) {
      hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]
    }
    lum = lum || 0

    // convert to decimal and change luminosity
    var rgb = '#', c, i
    for (i = 0; i < 3; i++) {
      c = parseInt(hex.substr(i * 2, 2), 16)
      c = Math.round(Math.min(Math.max(0, c + (c * lum)), 255)).toString(16)
      rgb += ('00' + c).substr(c.length)
    }

    return rgb
  },
  openLink: function(url){
    var win = (url !== "") ? window.open(url, '_blank') : "empty";

    if (win) {
        //Browser has allowed it to be opened
        return true;
    } else {
        //Browser has blocked it
        alert('Please allow popups in order to open the link');
        return false;
    }
  },
  mdToHTML: text => {
    // use safe: true to filter xss
    return new HtmlRenderer({ safe: true })
      .render(new Parser().parse(text))
  },
  logCanvasAttributes: function(canvas){
    return {
      scaleX: canvas.scaleOffsetX,
      scaleY: canvas.scaleOffsetY,
      centreCoords: Util.pixelsToCoords({ x: canvas.canvases[0].size.width / 2, y: canvas.canvases[0].size.height / 2 }),
    };
  },
  resizeCanvas: function(canvas){
    // Store the current canvas attributes, i.e. scale and map-coordinate at the centre of the user's screen
    const oldAttr = Util.logCanvasAttributes(canvas);

    // Resize the canvas to fill the new window size. Based on how JIT works, this also resets the map back to scale 1 and tranlations = 0
    canvas.resize($(window).width(), $(window).height())

    // Return the map to the original scale, and then put the previous central map-coordinate back to the centre of user's newly resized screen
    canvas.scale(oldAttr.scaleX, oldAttr.scaleY)
    const newAttr = Util.logCanvasAttributes(canvas);
    canvas.translate(newAttr.centreCoords.x - oldAttr.centreCoords.x, newAttr.centreCoords.y - oldAttr.centreCoords.y)
  }
}

export default Util
<commit_msg>fix logCanvasAttributes error (#863)<commit_after>/* global $ */

import { Parser, HtmlRenderer } from 'commonmark'

const Util = {
  // helper function to determine how many lines are needed
  // Line Splitter Function
  // copyright Stephen Chapman, 19th April 2006
  // you may copy this code but please keep the copyright notice as well
  splitLine: function (st, n) {
    var b = ''
    var s = st ? st : ''
    while (s.length > n) {
      var c = s.substring(0, n)
      var d = c.lastIndexOf(' ')
      var e = c.lastIndexOf('\n')
      if (e != -1) d = e
      if (d == -1) d = n
      b += c.substring(0, d) + '\n'
      s = s.substring(d + 1)
    }
    return b + s
  },

  nowDateFormatted: function (date = new Date(Date.now())) {
    const month = (date.getMonth() + 1) < 10 ? '0' + (date.getMonth() + 1) : (date.getMonth() + 1)
    const day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate()
    const year = date.getFullYear()

    return month + '/' + day + '/' + year
  },

  decodeEntities: function (desc) {
    var str, temp = document.createElement('p')
    temp.innerHTML = desc // browser handles the topics
    str = temp.textContent || temp.innerText
    temp = null // delete the element
    return str
  }, // decodeEntities

  getDistance: function (p1, p2) {
    return Math.sqrt(Math.pow((p2.x - p1.x), 2) + Math.pow((p2.y - p1.y), 2))
  },

  // Try using Visualize.mGraph
  coordsToPixels: function (mGraph, coords) {
    if (mGraph) {
      var canvas = mGraph.canvas,
        s = canvas.getSize(),
        p = canvas.getPos(),
        ox = canvas.translateOffsetX,
        oy = canvas.translateOffsetY,
        sx = canvas.scaleOffsetX,
        sy = canvas.scaleOffsetY
      var pixels = {
        x: (coords.x / (1 / sx)) + p.x + s.width / 2 + ox,
        y: (coords.y / (1 / sy)) + p.y + s.height / 2 + oy
      }
      return pixels
    } else {
      return {
        x: 0,
        y: 0
      }
    }
  },

  // Try using Visualize.mGraph
  pixelsToCoords: function (mGraph, pixels) {
    var coords
    if (mGraph) {
      var canvas = mGraph.canvas,
        s = canvas.getSize(),
        p = canvas.getPos(),
        ox = canvas.translateOffsetX,
        oy = canvas.translateOffsetY,
        sx = canvas.scaleOffsetX,
        sy = canvas.scaleOffsetY
      coords = {
        x: (pixels.x - p.x - s.width / 2 - ox) * (1 / sx),
        y: (pixels.y - p.y - s.height / 2 - oy) * (1 / sy),
      }
    } else {
      coords = {
        x: 0,
        y: 0
      }
    }
    return coords
  },
  getPastelColor: function (opts = {}) {
    const rseed = opts.rseed === undefined ? Math.random() : opts.rseed
    const gseed = opts.gseed === undefined ? Math.random() : opts.gseed
    const bseed = opts.bseed === undefined ? Math.random() : opts.bseed
    var r = (Math.round(rseed * 127) + 127).toString(16)
    var g = (Math.round(gseed * 127) + 127).toString(16)
    var b = (Math.round(bseed * 127) + 127).toString(16)
    return Util.colorLuminance('#' + r + g + b, -0.4)
  },
  // darkens a hex value by 'lum' percentage
  colorLuminance: function (hex, lum) {
    // validate hex string
    hex = String(hex).replace(/[^0-9a-f]/gi, '')
    if (hex.length < 6) {
      hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]
    }
    lum = lum || 0

    // convert to decimal and change luminosity
    var rgb = '#', c, i
    for (i = 0; i < 3; i++) {
      c = parseInt(hex.substr(i * 2, 2), 16)
      c = Math.round(Math.min(Math.max(0, c + (c * lum)), 255)).toString(16)
      rgb += ('00' + c).substr(c.length)
    }

    return rgb
  },
  openLink: function(url){
    var win = (url !== "") ? window.open(url, '_blank') : "empty";

    if (win) {
        //Browser has allowed it to be opened
        return true;
    } else {
        //Browser has blocked it
        alert('Please allow popups in order to open the link');
        return false;
    }
  },
  mdToHTML: text => {
    // use safe: true to filter xss
    return new HtmlRenderer({ safe: true })
      .render(new Parser().parse(text))
  },
  logCanvasAttributes: function(canvas){
    const fakeMgraph = { canvas }
    return {
      scaleX: canvas.scaleOffsetX,
      scaleY: canvas.scaleOffsetY,
      centreCoords: Util.pixelsToCoords(fakeMgraph, { x: canvas.canvases[0].size.width / 2, y: canvas.canvases[0].size.height / 2 }),
    };
  },
  resizeCanvas: function(canvas){
    // Store the current canvas attributes, i.e. scale and map-coordinate at the centre of the user's screen
    const oldAttr = Util.logCanvasAttributes(canvas);

    // Resize the canvas to fill the new window size. Based on how JIT works, this also resets the map back to scale 1 and tranlations = 0
    canvas.resize($(window).width(), $(window).height())

    // Return the map to the original scale, and then put the previous central map-coordinate back to the centre of user's newly resized screen
    canvas.scale(oldAttr.scaleX, oldAttr.scaleY)
    const newAttr = Util.logCanvasAttributes(canvas);
    canvas.translate(newAttr.centreCoords.x - oldAttr.centreCoords.x, newAttr.centreCoords.y - oldAttr.centreCoords.y)
  }
}

export default Util
<|endoftext|>


<commit_before>'use strict';

var $ = require('jquery');
var $osf = require('js/osfHelpers');
var bootbox = require('bootbox');
var ko = require('knockout');
var oop = require('js/oop');
var Raven = require('raven-js');
var ChangeMessageMixin = require('js/changeMessage');

require('knockout.punches');
ko.punches.enableAll();

var UserEmail = oop.defclass({
    constructor: function(params) {
        params = params || {};
        this.address = ko.observable(params.address);
        this.isConfirmed = ko.observable(params.isConfirmed || false);
        this.isPrimary = ko.observable(params.isPrimary || false);
    }
});

var UserProfile = oop.defclass({
    constructor: function () {

        this.id = ko.observable();
        this.emails = ko.observableArray();

        this.primaryEmail = ko.pureComputed(function () {
            var emails = this.emails();
            for (var i = 0; i < this.emails().length; i++) {
                if(emails[i].isPrimary()) {
                    return emails[i];
                }
            }
            return new UserEmail();
        }.bind(this));

        this.alternateEmails = ko.pureComputed(function () {
            var emails = this.emails();
            var retval = [];
            for (var i = 0; i < this.emails().length; i++) {
                if (emails[i].isConfirmed() && !emails[i].isPrimary()) {
                    retval.push(emails[i]);
                }
            }
            return retval;
        }.bind(this));

        this.unconfirmedEmails = ko.pureComputed(function () {
            var emails = this.emails();
            var retval = [];
            for (var i = 0; i < this.emails().length; i++) {
                if(!emails[i].isConfirmed()) {
                    retval.push(emails[i]);
                }
            }
            return retval;
        }.bind(this));

    }
});

var UserProfileClient = oop.defclass({
    constructor: function () {},
    urls: {
        fetch: '/api/v1/profile/',
        update: '/api/v1/profile/',
        resend: '/api/v1/resend/'
    },
    fetch: function () {
        var ret = $.Deferred();

        var request = $.get(this.urls.fetch);
        request.done(function(data) {
            ret.resolve(this.unserialize(data));
        }.bind(this));
        request.fail(function(xhr, status, error) {
            $osf.growl('Error', 'Could not fetch user profile.', 'danger');
            Raven.captureMessage('Error fetching user profile', {
                url: this.urls.fetch,
                status: status,
                error: error
            });
            ret.reject(xhr, status, error);
        }.bind(this));

        return ret.promise();
    },
    update: function (profile, email) {
        var url = this.urls.update;
        if(email) {
            url = this.urls.resend;
        }
        var ret = $.Deferred();
        var request = $osf.putJSON(
            url,
            this.serialize(profile, email)
        ).done(function (data) {
            ret.resolve(this.unserialize(data, profile));
        }.bind(this)).fail(function(xhr, status, error) {
            if (xhr.status === 400) {
                $osf.growl('Error', xhr.responseJSON.message_long);

            } else {
                $osf.growl('Error', 'User profile not updated. Please refresh the page and try ' +
                'again or contact support@osf.io ' +
                'if the problem persists.', 'danger');
            }

            Raven.captureMessage('Error fetching user profile', {
                url: this.urls.update,
                status: status,
                error: error
            });
            ret.reject(xhr, status, error);
        }.bind(this));

        return ret;
    },
    serialize: function (profile, email) {
        if(email){
            return {
                id: profile.id(),
                email: {
                    address: email.address(),
                    primary: email.isPrimary(),
                    confirmed: email.isConfirmed()
                }
            };
        }
        return {
            id: profile.id(),
            emails: ko.utils.arrayMap(profile.emails(), function(email) {
                return {
                    address: email.address(),
                    primary: email.isPrimary(),
                    confirmed: email.isConfirmed()
                };
            })

        };
    },
    unserialize: function (data, profile) {
        if (typeof(profile) === 'undefined') {
            profile = new UserProfile();
        }

        profile.id(data.profile.id);
        profile.emails(
            ko.utils.arrayMap(data.profile.emails, function (emailData){
                var email = new UserEmail({
                    address: emailData.address,
                    isPrimary: emailData.primary,
                    isConfirmed: emailData.confirmed
                });
                return email;
            })
        );

        return profile;
    }
});

var UserProfileViewModel = oop.extend(ChangeMessageMixin, {
    constructor: function() {
        this.super.constructor.call(this);
        this.client = new UserProfileClient();
        this.profile = ko.observable(new UserProfile());
        this.emailInput = ko.observable('');

    },
    init: function () {
        this.client.fetch().done(
            function(profile) { this.profile(profile); }.bind(this)
        );
    },
    addEmail: function () {
        this.changeMessage('', 'text-info');
        var newEmail = this.emailInput().toLowerCase().trim();
        if(newEmail){

            var email = new UserEmail({
                address: newEmail
            });

            // ensure email isn't already in the list
            for (var i=0; i<this.profile().emails().length; i++) {
                if (this.profile().emails()[i].address() === email.address()) {
                    this.changeMessage('Duplicate Email', 'text-warning');
                    this.emailInput('');
                    return;
                }
            }

            this.profile().emails.push(email);

            this.client.update(this.profile()).done(function (profile) {
                this.profile(profile);
                var emails = profile.emails();
                for (var i=0; i<emails.length; i++) {
                    if (emails[i].address() === email.address()) {
                        this.emailInput('');
                        var addrText = $osf.htmlEscape(email.address());
                        $osf.growl('' + addrText  + ' added to your account.','You will receive a confirmation email at ' + addrText  + '. Please check your email and confirm.', 'success');
                        return;
                    }
                }
            }.bind(this)).fail(function(){
                this.profile().emails.remove(email);
            }.bind(this));
        } else {
            this.changeMessage('Email cannot be empty.', 'text-danger');
        }
    },
    resendConfirmation: function(email){
        var self = this;
        self.changeMessage('', 'text-info');
        var addrText = $osf.htmlEscape(email.address());
        bootbox.confirm({
            title: 'Resend Email Confirmation?',
            message: 'Are you sure that you want to resend email confirmation to ' + '' + addrText + '?',
            callback: function (confirmed) {
                if (confirmed) {
                    self.client.update(self.profile(), email).done(function () {
                        $osf.growl(
                            'Email confirmation resent to ' + addrText + '',
                            'You will receive a new confirmation email at ' + addrText  + '. Please check your email and confirm.',
                            'success');
                    });
                }
            },
            buttons:{
                confirm:{
                    label:'Resend'
                }
            }
        });
    },
    removeEmail: function (email) {
        var self = this;
        self.changeMessage('', 'text-info');
        if (self.profile().emails().indexOf(email) !== -1) {
            var addrText = $osf.htmlEscape(email.address());
            bootbox.confirm({
                title: 'Remove Email?',
                message: 'Are you sure that you want to remove ' + '' + addrText + '' + ' from your email list?',
                callback: function (confirmed) {
                    if (confirmed) {
                        self.profile().emails.remove(email);
                        self.client.update(self.profile()).done(function () {
                            $osf.growl('Email Removed', '' + addrText + '', 'success');
                        });
                    }
                },
                buttons:{
                    confirm:{
                        label:'Remove',
                        className:'btn-danger'
                    }
                }
            });
        } else {
            $osf.growl('Error', 'Please refresh the page and try again.', 'danger');
        }
    },
    makeEmailPrimary: function (email) {
        this.changeMessage('', 'text-info');
        if (this.profile().emails().indexOf(email) !== -1) {
            this.profile().primaryEmail().isPrimary(false);
            email.isPrimary(true);
            this.client.update(this.profile()).done(function () {
                var addrText = $osf.htmlEscape(email.address());
                $osf.growl('Made Primary', '' + addrText + '', 'success');
            });
        } else {
            $osf.growl('Error', 'Please refresh the page and try again.', 'danger');
        }
    }
});

var DeactivateAccountViewModel = oop.defclass({
    constructor: function () {
        this.success = ko.observable(false);
    },
    urls: {
        'update': '/api/v1/profile/deactivate/'
    },
    _requestDeactivation: function() {
        var request = $osf.postJSON(this.urls.update, {});
        request.done(function() {
            $osf.growl('Success', 'An OSF administrator will contact you shortly to confirm your deactivation request.', 'success');
            this.success(true);
        }.bind(this));
        request.fail(function(xhr, status, error) {
            $osf.growl('Error',
                'Deactivation request failed. Please contact support@osf.io if the problem persists.',
                'danger'
            );
            Raven.captureMessage('Error requesting account deactivation', {
                url: this.urls.update,
                status: status,
                error: error
            });
        }.bind(this));
        return request;
    },
    submit: function () {
        var self = this;
        bootbox.confirm({
            title: 'Request account deactivation?',
            message: 'Are you sure you want to request account deactivation? An OSF administrator will review your request. If accepted, you ' +
                     'will NOT be able to reactivate your account.',
            callback: function(confirmed) {
                if (confirmed) {
                    return self._requestDeactivation();
                }
            },
            buttons:{
                confirm:{
                    label:'Request',
                    className:'btn-danger'
                }
            }
        });
    }
});

var ExportAccountViewModel = oop.defclass({
    constructor: function () {
        this.success = ko.observable(false);
    },
    urls: {
        'update': '/api/v1/profile/export/'
    },
    _requestExport: function() {
        var request = $osf.postJSON(this.urls.update, {});
        request.done(function() {
            $osf.growl('Success', 'An OSF administrator will contact you shortly to confirm your export request.', 'success');
            this.success(true);
        }.bind(this));
        request.fail(function(xhr, status, error) {
            $osf.growl('Error',
                'Export request failed. Please contact support@osf.io if the problem persists.',
                'danger'
            );
            Raven.captureMessage('Error requesting account export', {
                url: this.urls.update,
                status: status,
                error: error
            });
        }.bind(this));
        return request;
    },
    submit: function () {
        var self = this;
        bootbox.confirm({
            title: 'Request account export?',
            message: 'Are you sure you want to request account export?',
            callback: function(confirmed) {
                if (confirmed) {
                    return self._requestExport();
                }
            },
            buttons:{
                confirm:{
                    label:'Request'
                }
            }
        });
    }
});

module.exports = {
    UserProfileViewModel: UserProfileViewModel,
    DeactivateAccountViewModel: DeactivateAccountViewModel,
    ExportAccountViewModel: ExportAccountViewModel
};
<commit_msg>Add back changes from #4741 along with changes in #4967<commit_after>'use strict';

var $ = require('jquery');
var $osf = require('js/osfHelpers');
var bootbox = require('bootbox');
var ko = require('knockout');
var oop = require('js/oop');
var Raven = require('raven-js');
var ChangeMessageMixin = require('js/changeMessage');

require('knockout.punches');
ko.punches.enableAll();

var UserEmail = oop.defclass({
    constructor: function(params) {
        params = params || {};
        this.address = ko.observable(params.address);
        this.isConfirmed = ko.observable(params.isConfirmed || false);
        this.isPrimary = ko.observable(params.isPrimary || false);
    }
});

var UserProfile = oop.defclass({
    constructor: function () {

        this.id = ko.observable();
        this.emails = ko.observableArray();

        this.primaryEmail = ko.pureComputed(function () {
            var emails = this.emails();
            for (var i = 0; i < this.emails().length; i++) {
                if(emails[i].isPrimary()) {
                    return emails[i];
                }
            }
            return new UserEmail();
        }.bind(this));

        this.alternateEmails = ko.pureComputed(function () {
            var emails = this.emails();
            var retval = [];
            for (var i = 0; i < this.emails().length; i++) {
                if (emails[i].isConfirmed() && !emails[i].isPrimary()) {
                    retval.push(emails[i]);
                }
            }
            return retval;
        }.bind(this));

        this.unconfirmedEmails = ko.pureComputed(function () {
            var emails = this.emails();
            var retval = [];
            for (var i = 0; i < this.emails().length; i++) {
                if(!emails[i].isConfirmed()) {
                    retval.push(emails[i]);
                }
            }
            return retval;
        }.bind(this));

    }
});

var UserProfileClient = oop.defclass({
    constructor: function () {},
    urls: {
        fetch: '/api/v1/profile/',
        update: '/api/v1/profile/',
        resend: '/api/v1/resend/'
    },
    fetch: function () {
        var ret = $.Deferred();

        var request = $.get(this.urls.fetch);
        request.done(function(data) {
            ret.resolve(this.unserialize(data));
        }.bind(this));
        request.fail(function(xhr, status, error) {
            $osf.growl('Error', 'Could not fetch user profile.', 'danger');
            Raven.captureMessage('Error fetching user profile', {
                url: this.urls.fetch,
                status: status,
                error: error
            });
            ret.reject(xhr, status, error);
        }.bind(this));

        return ret.promise();
    },
    update: function (profile, email) {
        var url = this.urls.update;
        if(email) {
            url = this.urls.resend;
        }
        var ret = $.Deferred();
        var request = $osf.putJSON(
            url,
            this.serialize(profile, email)
        ).done(function (data) {
            ret.resolve(this.unserialize(data, profile));
        }.bind(this)).fail(function(xhr, status, error) {
            if (xhr.status === 400) {
                $osf.growl('Error', xhr.responseJSON.message_long);

            } else {
                $osf.growl('Error', 'User profile not updated. Please refresh the page and try ' +
                'again or contact support@osf.io ' +
                'if the problem persists.', 'danger');
            }

            Raven.captureMessage('Error fetching user profile', {
                url: this.urls.update,
                status: status,
                error: error
            });
            ret.reject(xhr, status, error);
        }.bind(this));

        return ret;
    },
    serialize: function (profile, email) {
        if(email){
            return {
                id: profile.id(),
                email: {
                    address: email.address(),
                    primary: email.isPrimary(),
                    confirmed: email.isConfirmed()
                }
            };
        }
        return {
            id: profile.id(),
            emails: ko.utils.arrayMap(profile.emails(), function(email) {
                return {
                    address: email.address(),
                    primary: email.isPrimary(),
                    confirmed: email.isConfirmed()
                };
            })

        };
    },
    unserialize: function (data, profile) {
        if (typeof(profile) === 'undefined') {
            profile = new UserProfile();
        }

        profile.id(data.profile.id);
        profile.emails(
            ko.utils.arrayMap(data.profile.emails, function (emailData){
                var email = new UserEmail({
                    address: emailData.address,
                    isPrimary: emailData.primary,
                    isConfirmed: emailData.confirmed
                });
                return email;
            })
        );

        return profile;
    }
});

var UserProfileViewModel = oop.extend(ChangeMessageMixin, {
    constructor: function() {
        this.super.constructor.call(this);
        this.client = new UserProfileClient();
        this.profile = ko.observable(new UserProfile());
        this.emailInput = ko.observable('');

    },
    init: function () {
        this.client.fetch().done(
            function(profile) { this.profile(profile); }.bind(this)
        );
    },
    addEmail: function () {
        this.changeMessage('', 'text-info');
        var newEmail = this.emailInput().toLowerCase().trim();
        if(newEmail){

            var email = new UserEmail({
                address: newEmail
            });

            // ensure email isn't already in the list
            for (var i=0; i<this.profile().emails().length; i++) {
                if (this.profile().emails()[i].address() === email.address()) {
                    this.changeMessage('Duplicate Email', 'text-warning');
                    this.emailInput('');
                    return;
                }
            }

            this.profile().emails.push(email);

            this.client.update(this.profile()).done(function (profile) {
                this.profile(profile);
                var emails = profile.emails();
                var emailAdded = false;
                for (var i=0; i<emails.length; i++) {
                    if (emails[i].address() === email.address()) {
                        emailAdded = true;
                        this.emailInput('');
                    }
                }
                if (emailAdded === true) {
                    var addrText = $osf.htmlEscape(email.address());
                    bootbox.alert({
                                title: 'Confirmation email sent',
                                message: '' + addrText + '' + ' was added to your account.' +
                                ' You will receive a confirmation email at ' + '' + addrText + '.' +
                                ' Please log out of this account and check your email to confirm this action.'
                            });
                }
            }.bind(this)).fail(function(){
                this.profile().emails.remove(email);
            }.bind(this));
        } else {
            this.changeMessage('Email cannot be empty.', 'text-danger');
        }

    },
    resendConfirmation: function(email){
        var self = this;
        self.changeMessage('', 'text-info');
        var addrText = $osf.htmlEscape(email.address());
        bootbox.confirm({
            title: 'Resend Email Confirmation?',
            message: 'Are you sure that you want to resend email confirmation to ' + '' + addrText + '?',
            callback: function (confirmed) {
                if (confirmed) {
                    self.client.update(self.profile(), email).done(function () {
                        $osf.growl(
                            'Email confirmation resent to ' + addrText + '',
                            'You will receive a new confirmation email at ' + addrText  + '.' +
                            ' Please log out of this account and check your email to confirm this action.',
                            'success');
                    });
                }
            },
            buttons:{
                confirm:{
                    label:'Resend'
                }
            }
        });
    },
    removeEmail: function (email) {
        var self = this;
        self.changeMessage('', 'text-info');
        if (self.profile().emails().indexOf(email) !== -1) {
            var addrText = $osf.htmlEscape(email.address());
            bootbox.confirm({
                title: 'Remove Email?',
                message: 'Are you sure that you want to remove ' + '' + addrText + '' + ' from your email list?',
                callback: function (confirmed) {
                    if (confirmed) {
                        self.profile().emails.remove(email);
                        self.client.update(self.profile()).done(function () {
                            $osf.growl('Email Removed', '' + addrText + '', 'success');
                        });
                    }
                },
                buttons:{
                    confirm:{
                        label:'Remove',
                        className:'btn-danger'
                    }
                }
            });
        } else {
            $osf.growl('Error', 'Please refresh the page and try again.', 'danger');
        }
    },
    makeEmailPrimary: function (email) {
        this.changeMessage('', 'text-info');
        if (this.profile().emails().indexOf(email) !== -1) {
            this.profile().primaryEmail().isPrimary(false);
            email.isPrimary(true);
            this.client.update(this.profile()).done(function () {
                var addrText = $osf.htmlEscape(email.address());
                $osf.growl('Made Primary', '' + addrText + '', 'success');
            });
        } else {
            $osf.growl('Error', 'Please refresh the page and try again.', 'danger');
        }
    }
});

var DeactivateAccountViewModel = oop.defclass({
    constructor: function () {
        this.success = ko.observable(false);
    },
    urls: {
        'update': '/api/v1/profile/deactivate/'
    },
    _requestDeactivation: function() {
        var request = $osf.postJSON(this.urls.update, {});
        request.done(function() {
            $osf.growl('Success', 'An OSF administrator will contact you shortly to confirm your deactivation request.', 'success');
            this.success(true);
        }.bind(this));
        request.fail(function(xhr, status, error) {
            $osf.growl('Error',
                'Deactivation request failed. Please contact support@osf.io if the problem persists.',
                'danger'
            );
            Raven.captureMessage('Error requesting account deactivation', {
                url: this.urls.update,
                status: status,
                error: error
            });
        }.bind(this));
        return request;
    },
    submit: function () {
        var self = this;
        bootbox.confirm({
            title: 'Request account deactivation?',
            message: 'Are you sure you want to request account deactivation? An OSF administrator will review your request. If accepted, you ' +
                     'will NOT be able to reactivate your account.',
            callback: function(confirmed) {
                if (confirmed) {
                    return self._requestDeactivation();
                }
            },
            buttons:{
                confirm:{
                    label:'Request',
                    className:'btn-danger'
                }
            }
        });
    }
});

var ExportAccountViewModel = oop.defclass({
    constructor: function () {
        this.success = ko.observable(false);
    },
    urls: {
        'update': '/api/v1/profile/export/'
    },
    _requestExport: function() {
        var request = $osf.postJSON(this.urls.update, {});
        request.done(function() {
            $osf.growl('Success', 'An OSF administrator will contact you shortly to confirm your export request.', 'success');
            this.success(true);
        }.bind(this));
        request.fail(function(xhr, status, error) {
            $osf.growl('Error',
                'Export request failed. Please contact support@osf.io if the problem persists.',
                'danger'
            );
            Raven.captureMessage('Error requesting account export', {
                url: this.urls.update,
                status: status,
                error: error
            });
        }.bind(this));
        return request;
    },
    submit: function () {
        var self = this;
        bootbox.confirm({
            title: 'Request account export?',
            message: 'Are you sure you want to request account export?',
            callback: function(confirmed) {
                if (confirmed) {
                    return self._requestExport();
                }
            },
            buttons:{
                confirm:{
                    label:'Request'
                }
            }
        });
    }
});

module.exports = {
    UserProfileViewModel: UserProfileViewModel,
    DeactivateAccountViewModel: DeactivateAccountViewModel,
    ExportAccountViewModel: ExportAccountViewModel
};
<|endoftext|>


<commit_before>// build.js
const packager = require("electron-packager");
const config = require("./package.json");
const electron = require("./node_modules/electron-prebuilt/package.json");

packager({
  dir: "./",          // 対象
  out: "./bin",      // 出力先
  name: config.name,  // 名前
  platform: "win32", // win32
  arch: "all",        // 64bit:x64, 32bit:ia32
  version: electron.version,  // electron のバージョン
  "app-bundle-id": "io.github.kazunori-kimura",
  "app-version": config.version,          // バージョン
  overwrite: true,  // 上書き
  asar: true,       // アーカイブ
  prune: true,
  // 無視ファイル
  ignore: "node_modules/(electron-packager|electron-prebuilt|\.bin)|build\.js|bin/electron-log-parser-*",
}, function done (err, appPath) {
  if(err) {
    throw new Error(err);
  }
  console.log('Done!!');
});
<commit_msg>[mod] build処理を修正<commit_after>// build.js
"use strict";
const packager = require("electron-packager");
const config = require("./package.json");
const electron = require("./node_modules/electron-prebuilt/package.json");
const co = require("co");
const fs = require("fs-extra-promise");

co(function*(){
  // 出力先を一旦削除
  yield fs.removeAsync("./bin");
  // package作成
  yield pack();

  console.log("done!");
}).catch((err) => {
  console.error(err);
});

/**
 * create electron package
 */
function pack() {
  return new Promise((resolve, reject) => {
    packager({
      dir: "./",          // 対象
      out: "./bin",      // 出力先
      name: config.name,  // 名前
      platform: "win32", // win32
      arch: "all",        // 64bit:x64, 32bit:ia32
      version: electron.version,  // electron のバージョン
      "app-bundle-id": "io.github.kazunori-kimura",
      "app-version": config.version,          // バージョン
      overwrite: true,  // 上書き
      asar: true,       // アーカイブ
      prune: true,
      // 無視ファイル
      ignore: "node_modules/(electron-packager|electron-prebuilt|\.bin)|build\.js|bin/electron-log-parser-*",
    }, function done(err, appPath) {
      if (err) {
        reject(err);
      }
      resolve(appPath);
    });
  });
}<|endoftext|>


<commit_before>var parse = require('postcss').parse;

var postcssJS = require('../');

it('converts declaration', () => {
    var root = parse('color: black');
    expect(postcssJS.objectify(root)).toEqual({ color: 'black' });
});

it('converts declarations to array', () => {
    var root = parse('color: black; color: rgba(0,0,0,.5); color: #000.5;');
    expect(postcssJS.objectify(root)).toEqual({
        color: [
            'black',
            'rgba(0,0,0,.5)',
            '#000.5'
        ]
    });
});

it('converts declarations to array', () => {
    var root = parse('@font-face{font-family:A}@font-face{font-family: B}');
    expect(postcssJS.objectify(root)).toEqual({
        '@font-face': [{ fontFamily: 'A' }, { fontFamily: 'B' }]
    });
});

it('converts declarations to camel case', () => {
    var root = parse('-webkit-z-index: 1; -ms-z-index: 1; z-index: 1');
    expect(postcssJS.objectify(root)).toEqual({
        WebkitZIndex: '1',
        msZIndex:     '1',
        zIndex:       '1'
    });
});

it('maintains !important declarations', () => {
    var root = parse('margin-bottom: 0 !important');
    expect(postcssJS.objectify(root)).toEqual({
        marginBottom: '0 !important'
    });
});

it('ignores comments', () => {
    var root = parse('color: black; /* test */');
    expect(postcssJS.objectify(root)).toEqual({ color: 'black' });
});

it('converts rules', () => {
    var root = parse('&:hover { color: black }');
    expect(postcssJS.objectify(root)).toEqual({
        '&:hover': {
            color: 'black'
        }
    });
});

it('merge rules', () => {
    var root = parse('div { color:blue } div { padding:5px }');
    expect(postcssJS.objectify(root)).toEqual({
        div: {
            color:   'blue',
            padding: '5px'
        }
    });
});

it('converts at-rules', () => {
    var root = parse('@media screen { color: black }');
    expect(postcssJS.objectify(root)).toEqual({
        '@media screen': {
            color: 'black'
        }
    });
});

it('converts at-rules without params', () => {
    var root = parse('@media { color: black }');
    expect(postcssJS.objectify(root)).toEqual({
        '@media': {
            color: 'black'
        }
    });
});

it('converts at-rules without children', () => {
    var root = parse('@media screen { }');
    expect(postcssJS.objectify(root)).toEqual({
        '@media screen': { }
    });
});

it('does fall on at-rules in rules merge', () => {
    var root = parse('@media screen { z-index: 1 } z-index: 2');
    expect(postcssJS.objectify(root)).toEqual({
        '@media screen': {
            zIndex: '1'
        },
        zIndex: '2'
    });
});

it('converts at-rules without body', () => {
    var root = parse('@charset "UTF-8"');
    expect(postcssJS.objectify(root)).toEqual({
        '@charset "UTF-8"': true
    });
});
<commit_msg>Fix coverage<commit_after>var parse = require('postcss').parse;

var postcssJS = require('../');

it('converts declaration', () => {
    var root = parse('color: black');
    expect(postcssJS.objectify(root)).toEqual({ color: 'black' });
});

it('converts declarations to array', () => {
    var root = parse('color: black; color: rgba(0,0,0,.5); color: #000.5;');
    expect(postcssJS.objectify(root)).toEqual({
        color: [
            'black',
            'rgba(0,0,0,.5)',
            '#000.5'
        ]
    });
});

it('converts declarations to array', () => {
    var root = parse(
        '@font-face { font-family: A }' +
        '@font-face { font-family: B }' +
        '@font-face { font-family: C }');
    expect(postcssJS.objectify(root)).toEqual({
        '@font-face': [
            { fontFamily: 'A' },
            { fontFamily: 'B' },
            { fontFamily: 'C' }
        ]
    });
});

it('converts declarations to camel case', () => {
    var root = parse('-webkit-z-index: 1; -ms-z-index: 1; z-index: 1');
    expect(postcssJS.objectify(root)).toEqual({
        WebkitZIndex: '1',
        msZIndex:     '1',
        zIndex:       '1'
    });
});

it('maintains !important declarations', () => {
    var root = parse('margin-bottom: 0 !important');
    expect(postcssJS.objectify(root)).toEqual({
        marginBottom: '0 !important'
    });
});

it('ignores comments', () => {
    var root = parse('color: black; /* test */');
    expect(postcssJS.objectify(root)).toEqual({ color: 'black' });
});

it('converts rules', () => {
    var root = parse('&:hover { color: black }');
    expect(postcssJS.objectify(root)).toEqual({
        '&:hover': {
            color: 'black'
        }
    });
});

it('merge rules', () => {
    var root = parse('div { color:blue } div { padding:5px }');
    expect(postcssJS.objectify(root)).toEqual({
        div: {
            color:   'blue',
            padding: '5px'
        }
    });
});

it('converts at-rules', () => {
    var root = parse('@media screen { color: black }');
    expect(postcssJS.objectify(root)).toEqual({
        '@media screen': {
            color: 'black'
        }
    });
});

it('converts at-rules without params', () => {
    var root = parse('@media { color: black }');
    expect(postcssJS.objectify(root)).toEqual({
        '@media': {
            color: 'black'
        }
    });
});

it('converts at-rules without children', () => {
    var root = parse('@media screen { }');
    expect(postcssJS.objectify(root)).toEqual({
        '@media screen': { }
    });
});

it('does fall on at-rules in rules merge', () => {
    var root = parse('@media screen { z-index: 1 } z-index: 2');
    expect(postcssJS.objectify(root)).toEqual({
        '@media screen': {
            zIndex: '1'
        },
        zIndex: '2'
    });
});

it('converts at-rules without body', () => {
    var root = parse('@charset "UTF-8"');
    expect(postcssJS.objectify(root)).toEqual({
        '@charset "UTF-8"': true
    });
});
<|endoftext|>


<commit_before>export const getDefaultUserFields = () => ({
	name: 1,
	username: 1,
	emails: 1,
	status: 1,
	statusDefault: 1,
	statusText: 1,
	statusConnection: 1,
	bio: 1,
	avatarOrigin: 1,
	utcOffset: 1,
	language: 1,
	settings: 1,
	enableAutoAway: 1,
	idleTimeLimit: 1,
	roles: 1,
	active: 1,
	defaultRoom: 1,
	customFields: 1,
	requirePasswordChange: 1,
	requirePasswordChangeReason: 1,
	'services.github': 1,
	'services.gitlab': 1,
	'services.tokenpass': 1,
	'services.blockstack': 1,
	'services.password.bcrypt': 1,
	'services.totp.enabled': 1,
	'services.email2fa.enabled': 1,
	statusLivechat: 1,
	banners: 1,
	'oauth.authorizedClients': 1,
	_updatedAt: 1,
});
<commit_msg>[FIX] Avatar ETag missing from User (#18109)<commit_after>export const getDefaultUserFields = () => ({
	name: 1,
	username: 1,
	emails: 1,
	status: 1,
	statusDefault: 1,
	statusText: 1,
	statusConnection: 1,
	bio: 1,
	avatarOrigin: 1,
	utcOffset: 1,
	language: 1,
	settings: 1,
	enableAutoAway: 1,
	idleTimeLimit: 1,
	roles: 1,
	active: 1,
	defaultRoom: 1,
	customFields: 1,
	requirePasswordChange: 1,
	requirePasswordChangeReason: 1,
	'services.github': 1,
	'services.gitlab': 1,
	'services.tokenpass': 1,
	'services.blockstack': 1,
	'services.password.bcrypt': 1,
	'services.totp.enabled': 1,
	'services.email2fa.enabled': 1,
	statusLivechat: 1,
	banners: 1,
	'oauth.authorizedClients': 1,
	_updatedAt: 1,
	avatarETag: 1,
});
<|endoftext|>


<commit_before>module.exports = function(grunt) {

	require('load-grunt-tasks')(grunt);

	grunt.initConfig({
		bump: {
			options: {
				files: ['package.json', 'bower.json'],
				commitFiles: ['package.json', 'bower.json'],
				pushTo: 'origin'
			}
		},
		copy: {
			prepare: {
				files: [{
					src: [
						'**',
						'!node_modules/**',
						'!bower_components/**',
						'!Contributing.md',
						'!Gruntfile.js',
						'!License.md',
						'!Readme.md',
						'!bower.json',
						'!package.json'
					],
					dest: 'temp/'
				},{
					expand: true,
					cwd: 'node_modules/shower-core/',
					src: [
						'**',
						'!package.json',
						'!Readme.md'
					],
					dest: 'temp/shower/'
				},{
					expand: true,
					cwd: 'node_modules/shower-ribbon/',
					src: [
						'**',
						'!package.json',
						'!Readme.md'
					],
					dest: 'temp/shower/themes/ribbon/'
				},{
					expand: true,
					cwd: 'node_modules/shower-bright/',
					src: [
						'**',
						'!package.json',
						'!Readme.md'
					],
					dest: 'temp/shower/themes/bright/'
				}]
			}
		},
		replace: {
			core: {
				src: 'temp/index.html',
				overwrite: true,
				replacements: [{
					from: /(node_modules|bower_components)\/shower-core/g,
					to: 'shower'
				},{
					from: /(node_modules|bower_components)\/shower-(ribbon|bright)/g,
					to: 'shower/themes/$2'
				}]
			},
			themes: {
				src: 'temp/shower/themes/*/index.html',
				overwrite: true,
				replacements: [{
					from: '../shower-core', to: '../..'
				}]
			}
		},
		'gh-pages': {
			options: {
				base: 'temp'
			},
			src: ['**']
		},
		clean: ['temp']
	});

	grunt.registerTask('publish', [
		'copy',
		'replace',
		'gh-pages',
		'clean'
	]);

};<commit_msg>Cleaning up publish task output<commit_after>module.exports = function(grunt) {

	require('load-grunt-tasks')(grunt);

	grunt.initConfig({
		bump: {
			options: {
				files: ['package.json', 'bower.json'],
				commitFiles: ['package.json', 'bower.json'],
				pushTo: 'origin'
			}
		},
		copy: {
			prepare: {
				files: [{
					src: [
						'**',
						'!node_modules/**',
						'!bower_components/**',
						'!Contributing.md',
						'!Gruntfile.js',
						'!License.md',
						'!Readme.md',
						'!bower.json',
						'!package.json'
					],
					dest: 'temp/pres/'
				},{
					expand: true,
					cwd: 'node_modules/shower-core/',
					src: [
						'**',
						'!package.json',
						'!Readme.md'
					],
					dest: 'temp/pres/shower/'
				},{
					expand: true,
					cwd: 'node_modules/shower-ribbon/',
					src: [
						'**',
						'!package.json',
						'!Readme.md'
					],
					dest: 'temp/pres/shower/themes/ribbon/'
				},{
					expand: true,
					cwd: 'node_modules/shower-bright/',
					src: [
						'**',
						'!package.json',
						'!Readme.md'
					],
					dest: 'temp/pres/shower/themes/bright/'
				}]
			}
		},
		replace: {
			core: {
				src: 'temp/pres/index.html',
				overwrite: true,
				replacements: [{
					from: /(node_modules|bower_components)\/shower-core/g,
					to: 'shower'
				},{
					from: /(node_modules|bower_components)\/shower-(ribbon|bright)/g,
					to: 'shower/themes/$2'
				}]
			},
			themes: {
				src: 'temp/pres/shower/themes/*/index.html',
				overwrite: true,
				replacements: [{
					from: '../shower-core', to: '../..'
				}]
			}
		},
		'gh-pages': {
			options: {
				base: 'temp/pres',
				clone: 'temp/clone'
			},
			src: ['**']
		},
		clean: ['temp']
	});

	grunt.registerTask('publish', [
		'copy',
		'replace',
		'gh-pages',
		'clean'
	]);

};<|endoftext|>


<commit_before>/**
 * The-M-Project Build Script
 * Version: 0.0.1
 */

var _ = require('lodash');

module.exports = function (grunt) {
    // show elapsed time at the end
    require('time-grunt')(grunt);
    // load all grunt tasks
    require('load-grunt-tasks')(grunt);

    // Project configuration.
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        meta: {
            banner: '/*!\n' + '* Project:   The M-Project - Mobile HTML5 Application Framework\n' + '* Version:   <%= pkg.version %>\n' + '* Copyright: (c) <%= grunt.template.today("yyyy") %> M-Way Solutions GmbH. All rights reserved.\n' + '* Date:      <%= grunt.template.today() %>\n' + '* License:   Dual licensed under the MIT or GPL Version 2 licenses.\n' + '*            http://github.com/mwaylabs/The-M-Project/blob/master/MIT-LICENSE\n' + '*            http://github.com/mwaylabs/The-M-Project/blob/master/GPL-LICENSE\n' + '*/'
        },
        jsonlint: {
            sample: {
                src: [ 'package.json' ]
            }
        },
        clean: {
            dist: ['dist']
        },
        jshint: {
            options: {
                jshintrc: '.jshintrc',
                ignores: ['src/_*.js', 'src/themproject*.js', 'src/ui/themevars.js']
            },
            src: [ 'src/**/*.js' ]
        },
        preprocess: {
            options: {
                context: {
                    BANNER: '<%= meta.banner %>'
                }
            },
            core: {
                files: {
                    'dist/themproject.js': 'src/themproject.js'
                }
            },
            bd: {
                files: {
                    'dist/themproject.bd.js': 'src/themproject.bd.js'
                }
            }
        },
        uglify: {
            options: {
                preserveComments: 'some'
            },
            core: {
                src: 'dist/themproject.js',
                dest: 'dist/themproject.min.js',
                options: {
                    sourceMap: 'dist/themproject.map',
                    sourceMappingURL: 'themproject.map',
                    sourceMapPrefix: 1
                }
            },
            bd: {
                src: 'dist/themproject.bd.js',
                dest: 'dist/themproject.bd.min.js',
                options: {
                    sourceMap: 'dist/themproject.bd.map',
                    sourceMappingURL: 'themproject.bd.map',
                    sourceMapPrefix: 1
                }
            }
        },
        cssmin: {
            minify: {
                expand: true,
                cwd: 'dist/',
                src: ['*.css', '!*.min.css'],
                dest: 'dist/',
                ext: '.min.css'
            }
        },
        copy: {
            minify: {
                expand: true,
                cwd: 'resources/vendor/',
                src: '*{css,js}',
                dest: 'dist/'
            }
        },
        watch: {
            js: {
                files: ['src/**/*'],
                tasks: ['build-js', 'loga'],
                options: {
                    spawn: false
                }
            },
            css: {
                files: ['resources/**/*.{scss,sass,css}'],
                tasks: ['build-css', 'logb'],
                options: {
                    spawn: false
                }
            },
            test: {
                files: ['test/**/*'],
                tasks: ['test', 'logc'],
                options: {
                    spawn: false
                }
            }
        },
        compass: {
            options: {
                sassDir: 'resources/sass',
                cssDir: 'dist',
                relativeAssets: true,
                importPath: ['bower_components']
            },
            dist: {}
        },
        mocha: {
            options: {
                "reporter": "Spec"
            },
            all: ['test/test.html']
        },
        extractSassVars: {
            all: {
                files: {
                    'src/ui/themevars.js': [
                        'resources/sass/themes/default/_variables.scss',
                        'resources/sass/themes/android_dark/_variables.scss',
                        'resources/sass/themes/android_light/_variables.scss',
                        'resources/sass/themes/ios/_variables.scss'
                    ]
                }
            }
        }
    });

    grunt.registerMultiTask('extractSassVars', 'Convert sass variables to javascript', function () {
        var collection = [];
        var regExp = /\$([^:]+):[\s]+([^;]+);/g;
        var results;

        // Iterate over all specified file groups.
        this.files.forEach(function (f) {
            // Concat specified files.
            var sassVars = f.src.filter(function (filepath) {
                // Warn on and remove invalid source files (if nonull was set).
                if (!grunt.file.exists(filepath)) {
                    grunt.log.warn('Source file "' + filepath + '" not found.');
                    return false;
                } else {
                    return true;
                }
            }).map(function (filepath) {
                    // Read file source.
                    var regex = new RegExp('^resources/sass/themes/([^/]*)');
                    var themeName = filepath.match(regex)[1];
                    return {
                        theme: themeName,
                        content: grunt.file.read(filepath)
                    };
                });
            _.each(sassVars, function (item) {
                while ((results = regExp.exec(item.content)) != null) {
                    if (!item.vars) {
                        item.vars = {};
                    }
                    item.vars[results[1]] = results[2];
                }
                delete item.content;
            });
            _.each(sassVars, function (item) {
                var group = item.vars;

                for (var key in group) {
                    for (var key2 in group) {
                        group[key2] = group[key2].replace(new RegExp('\\$' + key, 'gi'), group[key]);
                    }
                }
            });
            var vars = {};
            _.each(sassVars, function (item) {
                vars[item.theme] = item.vars
            });
            var output = grunt.file.read(__dirname + '/utils/themevars.txt');
            output = grunt.template.process(output, {data: {vars: JSON.stringify(vars, null, 4)}});

            // Write the destination file.
            grunt.file.write(f.dest, output);

            // Print a success message.
            grunt.log.writeln('File "' + f.dest + '" created.');
        });
    });

    grunt.registerTask('build-js', ['extractSassVars', 'preprocess:core']);
    grunt.registerTask('build-css', ['compass', 'copy']);

    grunt.registerTask('dev', ['default', 'watch']);
    grunt.registerTask('dev-js', ['default', 'watch:js']);
    grunt.registerTask('dev-css', ['default', 'watch:css']);

    grunt.registerTask('dev', ['default', 'watch']);
    grunt.registerTask('test', ['jshint', 'mocha']);
    grunt.registerTask('dist', ['clean', 'jshint', 'build-js', 'build-css', 'preprocess:bd', 'uglify', 'cssmin']);
    grunt.registerTask('default', ['clean', 'build-js', 'build-css']);
};
<commit_msg>remove unused tasks<commit_after>/**
 * The-M-Project Build Script
 * Version: 0.0.1
 */

var _ = require('lodash');

module.exports = function (grunt) {
    // show elapsed time at the end
    require('time-grunt')(grunt);
    // load all grunt tasks
    require('load-grunt-tasks')(grunt);

    // Project configuration.
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        meta: {
            banner: '/*!\n' + '* Project:   The M-Project - Mobile HTML5 Application Framework\n' + '* Version:   <%= pkg.version %>\n' + '* Copyright: (c) <%= grunt.template.today("yyyy") %> M-Way Solutions GmbH. All rights reserved.\n' + '* Date:      <%= grunt.template.today() %>\n' + '* License:   Dual licensed under the MIT or GPL Version 2 licenses.\n' + '*            http://github.com/mwaylabs/The-M-Project/blob/master/MIT-LICENSE\n' + '*            http://github.com/mwaylabs/The-M-Project/blob/master/GPL-LICENSE\n' + '*/'
        },
        jsonlint: {
            sample: {
                src: [ 'package.json' ]
            }
        },
        clean: {
            dist: ['dist']
        },
        jshint: {
            options: {
                jshintrc: '.jshintrc',
                ignores: ['src/_*.js', 'src/themproject*.js', 'src/ui/themevars.js']
            },
            src: [ 'src/**/*.js' ]
        },
        preprocess: {
            options: {
                context: {
                    BANNER: '<%= meta.banner %>'
                }
            },
            core: {
                files: {
                    'dist/themproject.js': 'src/themproject.js'
                }
            },
            bd: {
                files: {
                    'dist/themproject.bd.js': 'src/themproject.bd.js'
                }
            }
        },
        uglify: {
            options: {
                preserveComments: 'some'
            },
            core: {
                src: 'dist/themproject.js',
                dest: 'dist/themproject.min.js',
                options: {
                    sourceMap: 'dist/themproject.map',
                    sourceMappingURL: 'themproject.map',
                    sourceMapPrefix: 1
                }
            },
            bd: {
                src: 'dist/themproject.bd.js',
                dest: 'dist/themproject.bd.min.js',
                options: {
                    sourceMap: 'dist/themproject.bd.map',
                    sourceMappingURL: 'themproject.bd.map',
                    sourceMapPrefix: 1
                }
            }
        },
        cssmin: {
            minify: {
                expand: true,
                cwd: 'dist/',
                src: ['*.css', '!*.min.css'],
                dest: 'dist/',
                ext: '.min.css'
            }
        },
        copy: {
            minify: {
                expand: true,
                cwd: 'resources/vendor/',
                src: '*{css,js}',
                dest: 'dist/'
            }
        },
        watch: {
            js: {
                files: ['src/**/*'],
                tasks: ['build-js'],
                options: {
                    spawn: false
                }
            },
            css: {
                files: ['resources/**/*.{scss,sass,css}'],
                tasks: ['build-css'],
                options: {
                    spawn: false
                }
            },
            test: {
                files: ['test/**/*'],
                tasks: ['test'],
                options: {
                    spawn: false
                }
            }
        },
        compass: {
            options: {
                sassDir: 'resources/sass',
                cssDir: 'dist',
                relativeAssets: true,
                importPath: ['bower_components']
            },
            dist: {}
        },
        mocha: {
            options: {
                "reporter": "Spec"
            },
            all: ['test/test.html']
        },
        extractSassVars: {
            all: {
                files: {
                    'src/ui/themevars.js': [
                        'resources/sass/themes/default/_variables.scss',
                        'resources/sass/themes/android_dark/_variables.scss',
                        'resources/sass/themes/android_light/_variables.scss',
                        'resources/sass/themes/ios/_variables.scss'
                    ]
                }
            }
        }
    });

    grunt.registerMultiTask('extractSassVars', 'Convert sass variables to javascript', function () {
        var collection = [];
        var regExp = /\$([^:]+):[\s]+([^;]+);/g;
        var results;

        // Iterate over all specified file groups.
        this.files.forEach(function (f) {
            // Concat specified files.
            var sassVars = f.src.filter(function (filepath) {
                // Warn on and remove invalid source files (if nonull was set).
                if (!grunt.file.exists(filepath)) {
                    grunt.log.warn('Source file "' + filepath + '" not found.');
                    return false;
                } else {
                    return true;
                }
            }).map(function (filepath) {
                    // Read file source.
                    var regex = new RegExp('^resources/sass/themes/([^/]*)');
                    var themeName = filepath.match(regex)[1];
                    return {
                        theme: themeName,
                        content: grunt.file.read(filepath)
                    };
                });
            _.each(sassVars, function (item) {
                while ((results = regExp.exec(item.content)) != null) {
                    if (!item.vars) {
                        item.vars = {};
                    }
                    item.vars[results[1]] = results[2];
                }
                delete item.content;
            });
            _.each(sassVars, function (item) {
                var group = item.vars;

                for (var key in group) {
                    for (var key2 in group) {
                        group[key2] = group[key2].replace(new RegExp('\\$' + key, 'gi'), group[key]);
                    }
                }
            });
            var vars = {};
            _.each(sassVars, function (item) {
                vars[item.theme] = item.vars
            });
            var output = grunt.file.read(__dirname + '/utils/themevars.txt');
            output = grunt.template.process(output, {data: {vars: JSON.stringify(vars, null, 4)}});

            // Write the destination file.
            grunt.file.write(f.dest, output);

            // Print a success message.
            grunt.log.writeln('File "' + f.dest + '" created.');
        });
    });

    grunt.registerTask('build-js', ['extractSassVars', 'preprocess:core']);
    grunt.registerTask('build-css', ['compass', 'copy']);

    grunt.registerTask('dev', ['default', 'watch']);
    grunt.registerTask('dev-js', ['default', 'watch:js']);
    grunt.registerTask('dev-css', ['default', 'watch:css']);

    grunt.registerTask('dev', ['default', 'watch']);
    grunt.registerTask('test', ['jshint', 'mocha']);
    grunt.registerTask('dist', ['clean', 'jshint', 'build-js', 'build-css', 'preprocess:bd', 'uglify', 'cssmin']);
    grunt.registerTask('default', ['clean', 'build-js', 'build-css']);
};
<|endoftext|>