<commit_before>/**
 * @file Tbody component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';

import Tr from '../_Tr';

import SelectMode from '../_statics/SelectMode';
import SelectAllMode from '../_statics/SelectAllMode';
import SortType from '../_statics/SortType';

import Util from '../_vendors/Util';

class Tbody extends Component {

    static SelectMode = SelectMode;
    static SelectAllMode = SelectAllMode;
    static SortType = SortType;

    constructor(props, ...restArgs) {
        super(props, ...restArgs);
    }

    isItemChecked = rowData => {

        const {selectMode, idProp, value} = this.props;

        if (!rowData || !value || selectMode === SelectMode.NORMAL) {
            return false;
        }

        switch (selectMode) {
            case SelectMode.MULTI_SELECT:
                return value && value.findIndex(item => item[idProp] === rowData[idProp]) !== -1;
            case SelectMode.SINGLE_SELECT:
                return value[idProp] === rowData[idProp];
        }

    };

    render() {

        const {
            columns, data, startIndex, idProp, disabled,
            onRowClick, onCellClick
        } = this.props;

        return (

                {
                    data && data.map((row, rowIndex) => row ?

                        :
                        null
                    )
                }

        );

    }
}

Tbody.propTypes = {

    /**
     * Children passed into table header.
     */
    columns: PropTypes.arrayOf(PropTypes.shape({

        /**
         * The class name of header.
         */
        headerClassName: PropTypes.string,

        /**
         * Override the styles of header.
         */
        headerStyle: PropTypes.object,

        /**
         * The render content in header.
         * (1) string，example： 'id'
         * (2) callback，example：function (tableData, colIndex) {return colIndex;}
         */
        headerRenderer: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),

        /**
         * The class name of td.
         */
        cellClassName: PropTypes.string,

        /**
         * Override the styles of td.
         */
        cellStyle: PropTypes.object,

        /**
         * The render content in table.
         * (1) data key，example： 'id'
         * (2) data key tamplate，example：'${id} - ${name}'
         * (3) callback，example：function (rowData, rowIndex, colIndex) {return rowData.id;}
         */
        cellRenderer: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),

        /**
         * The class name of footer.
         */
        footerClassName: PropTypes.string,

        /**
         * Override the styles of footer.
         */
        footerStyle: PropTypes.object,

        /**
         * The render content in footer.
         * (1) string，example： 'id'
         * (2) callback，example：function (tableData, colIndex) {return colIndex;}
         */
        footerRenderer: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),

        /**
         * If true,this column can be sorted.
         */
        sortable: PropTypes.bool,

        /**
         * Sort field.
         */
        sortProp: PropTypes.string,

        defaultSortType: PropTypes.oneOf(Util.enumerateValue(SortType)),

        /**
         * Column span callback
         * example: function (colIndex, rowIndex) {return colIndex === 0 ? 2 : null;}
         */
        span: PropTypes.func

    })).isRequired,

    data: PropTypes.array,
    value: PropTypes.any,
    startIndex: PropTypes.number,
    idProp: PropTypes.string,
    selectMode: PropTypes.oneOf(Util.enumerateValue(SelectMode)),
    disabled: PropTypes.bool,

    onRowClick: PropTypes.func,
    onCellClick: PropTypes.func

};

Tbody.defaultProps = {
    selectMode: SelectMode.SINGLE_SELECT,
    startIndex: 0,
    idProp: 'id',
    disabled: false
};

export default Tbody;
<commit_msg>update Tbody<commit_after>/**
 * @file Tbody component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';

import Tr from '../_Tr';

import SelectMode from '../_statics/SelectMode';
import SelectAllMode from '../_statics/SelectAllMode';
import SortingType from '../_statics/SortingType';

import Util from '../_vendors/Util';

class Tbody extends Component {

    static SelectMode = SelectMode;
    static SelectAllMode = SelectAllMode;
    static SortingType = SortingType;

    constructor(props, ...restArgs) {
        super(props, ...restArgs);
    }

    isItemChecked = rowData => {

        const {selectMode, idProp, value} = this.props;

        if (!rowData || !value || selectMode === SelectMode.NORMAL) {
            return false;
        }

        switch (selectMode) {
            case SelectMode.MULTI_SELECT:
                return value && value.findIndex(item => item[idProp] === rowData[idProp]) !== -1;
            case SelectMode.SINGLE_SELECT:
                return value[idProp] === rowData[idProp];
        }

    };

    render() {

        const {
            columns, data, startIndex, idProp, disabled,
            onRowClick, onCellClick
        } = this.props;

        return (

                {
                    data && data.map((row, rowIndex) => row ?

                        :
                        null
                    )
                }

        );

    }
}

Tbody.propTypes = {

    /**
     * Children passed into table header.
     */
    columns: PropTypes.arrayOf(PropTypes.shape({

        /**
         * The class name of header.
         */
        headerClassName: PropTypes.string,

        /**
         * Override the styles of header.
         */
        headerStyle: PropTypes.object,

        /**
         * The render content in header.
         * (1) string，example： 'id'
         * (2) callback，example：function (tableData, colIndex) {return colIndex;}
         */
        headerRenderer: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),

        /**
         * The class name of td.
         */
        cellClassName: PropTypes.string,

        /**
         * Override the styles of td.
         */
        cellStyle: PropTypes.object,

        /**
         * The render content in table.
         * (1) data key，example： 'id'
         * (2) data key tamplate，example：'${id} - ${name}'
         * (3) callback，example：function (rowData, rowIndex, colIndex) {return rowData.id;}
         */
        cellRenderer: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),

        /**
         * The class name of footer.
         */
        footerClassName: PropTypes.string,

        /**
         * Override the styles of footer.
         */
        footerStyle: PropTypes.object,

        /**
         * The render content in footer.
         * (1) string，example： 'id'
         * (2) callback，example：function (tableData, colIndex) {return colIndex;}
         */
        footerRenderer: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),

        /**
         * If true,this column can be sorted.
         */
        sortable: PropTypes.bool,

        /**
         * Sort field.
         */
        sortingProp: PropTypes.string,

        defaultSortingType: PropTypes.oneOf(Util.enumerateValue(SortingType)),

        /**
         * Column span callback
         * example: function (colIndex, rowIndex) {return colIndex === 0 ? 2 : null;}
         */
        span: PropTypes.func

    })).isRequired,

    data: PropTypes.array,
    value: PropTypes.any,
    startIndex: PropTypes.number,
    idProp: PropTypes.string,
    selectMode: PropTypes.oneOf(Util.enumerateValue(SelectMode)),
    disabled: PropTypes.bool,

    onRowClick: PropTypes.func,
    onCellClick: PropTypes.func

};

Tbody.defaultProps = {
    selectMode: SelectMode.SINGLE_SELECT,
    startIndex: 0,
    idProp: 'id',
    disabled: false
};

export default Tbody;
<|endoftext|>


<commit_before>//     Zepto.js
//     (c) 2010-2012 Thomas Fuchs
//     Zepto.js may be freely distributed under the MIT license.

;(function($){
  var jsonpID = 0,
      document = window.document,
      key,
      name,
      rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
      scriptTypeRE = /^(?:text|application)\/javascript/i,
      xmlTypeRE = /^(?:text|application)\/xml/i,
      jsonType = 'application/json',
      htmlType = 'text/html',
      blankRE = /^\s*$/

  // trigger a custom event and return false if it was cancelled
  function triggerAndReturn(context, eventName, data) {
    var event = $.Event(eventName)
    $(context).trigger(event, data)
    return !event.defaultPrevented
  }

  // trigger an Ajax "global" event
  function triggerGlobal(settings, context, eventName, data) {
    if (settings.global) return triggerAndReturn(context || document, eventName, data)
  }

  // Number of active Ajax requests
  $.active = 0

  function ajaxStart(settings) {
    if (settings.global && $.active++ === 0) triggerGlobal(settings, null, 'ajaxStart')
  }
  function ajaxStop(settings) {
    if (settings.global && !(--$.active)) triggerGlobal(settings, null, 'ajaxStop')
  }

  // triggers an extra global event "ajaxBeforeSend" that's like "ajaxSend" but cancelable
  function ajaxBeforeSend(xhr, settings) {
    var context = settings.context
    if (settings.beforeSend.call(context, xhr, settings) === false ||
        triggerGlobal(settings, context, 'ajaxBeforeSend', [xhr, settings]) === false)
      return false

    triggerGlobal(settings, context, 'ajaxSend', [xhr, settings])
  }
  function ajaxSuccess(data, xhr, settings) {
    var context = settings.context, status = 'success'
    settings.success.call(context, data, status, xhr)
    triggerGlobal(settings, context, 'ajaxSuccess', [xhr, settings, data])
    ajaxComplete(status, xhr, settings)
  }
  // type: "timeout", "error", "abort", "parsererror"
  function ajaxError(error, type, xhr, settings) {
    var context = settings.context
    settings.error.call(context, xhr, type, error)
    triggerGlobal(settings, context, 'ajaxError', [xhr, settings, error])
    ajaxComplete(type, xhr, settings)
  }
  // status: "success", "notmodified", "error", "timeout", "abort", "parsererror"
  function ajaxComplete(status, xhr, settings) {
    var context = settings.context
    settings.complete.call(context, xhr, status)
    triggerGlobal(settings, context, 'ajaxComplete', [xhr, settings])
    ajaxStop(settings)
  }

  // Empty function, used as default callback
  function empty() {}

  $.ajaxJSONP = function(options){
    if (!('type' in options)) return $.ajax(options)

    var callbackName = 'jsonp' + (++jsonpID),
      script = document.createElement('script'),
      cleanup = function() {
        clearTimeout(abortTimeout)
        $(script).remove()
        delete window[callbackName]
      },
      abort = function(){
        cleanup()
        ajaxComplete('abort', xhr, options)
      },
      xhr = { abort: abort }, abortTimeout

    serializeData(options)

    if (ajaxBeforeSend(xhr, options) === false) {
      ajaxError(null, 'abort', xhr, options)
      return false
    }

    window[callbackName] = function(data){
      cleanup()
      ajaxSuccess(data, xhr, options)
    }

    script.onerror = function() {
      cleanup()
      ajaxError(null, 'error', xhr, options)
    }

    script.src = options.url.replace(/=\?/, '=' + callbackName)
    $('head').append(script)

    if (options.timeout > 0) abortTimeout = setTimeout(function(){
        cleanup()
        ajaxError(null, 'timeout', xhr, options)
      }, options.timeout)

    return xhr
  }

  $.ajaxSettings = {
    // Default type of request
    type: 'GET',
    // Callback that is executed before request
    beforeSend: empty,
    // Callback that is executed if the request succeeds
    success: empty,
    // Callback that is executed the the server drops error
    error: empty,
    // Callback that is executed on request complete (both: error and success)
    complete: empty,
    // The context for the callbacks
    context: null,
    // Whether to trigger "global" Ajax events
    global: true,
    // Transport
    xhr: function () {
      return new window.XMLHttpRequest()
    },
    // MIME types mapping
    accepts: {
      script: 'text/javascript, application/javascript',
      json:   jsonType,
      xml:    'application/xml, text/xml',
      html:   htmlType,
      text:   'text/plain'
    },
    // Whether the request is to another domain
    crossDomain: false,
    // Default timeout
    timeout: 0,
    // Whether data should be serialized to string
    processData: true
  }

  function mimeToDataType(mime) {
    return mime && ( mime == htmlType ? 'html' :
      mime == jsonType ? 'json' :
      scriptTypeRE.test(mime) ? 'script' :
      xmlTypeRE.test(mime) && 'xml' ) || 'text'
  }

  function appendQuery(url, query) {
    return (url + '&' + query).replace(/[&?]{1,2}/, '?')
  }

  // serialize payload and append it to the URL for GET requests
  function serializeData(options) {
    if (options.processData && options.data && $.type(options.data) != "string")
      options.data = $.param(options.data, options.traditional)
    if (options.data && (!options.type || options.type.toUpperCase() == 'GET'))
      options.url = appendQuery(options.url, options.data)
  }

  $.ajax = function(options){
    var settings = $.extend({}, options || {})
    for (key in $.ajaxSettings) if (settings[key] === undefined) settings[key] = $.ajaxSettings[key]

    ajaxStart(settings)

    if (!settings.crossDomain) settings.crossDomain = /^([\w-]+:)?\/\/([^\/]+)/.test(settings.url) &&
      RegExp.$2 != window.location.host

    var dataType = settings.dataType, hasPlaceholder = /=\?/.test(settings.url)
    if (dataType == 'jsonp' || hasPlaceholder) {
      if (!hasPlaceholder) settings.url = appendQuery(settings.url, 'callback=?')
      return $.ajaxJSONP(settings)
    }

    if (!settings.url) settings.url = window.location.toString()
    serializeData(settings)

    var mime = settings.accepts[dataType],
        baseHeaders = { },
        protocol = /^([\w-]+:)\/\//.test(settings.url) ? RegExp.$1 : window.location.protocol,
        xhr = settings.xhr(), abortTimeout

    if (!settings.crossDomain) baseHeaders['X-Requested-With'] = 'XMLHttpRequest'
    if (mime) {
      baseHeaders['Accept'] = mime
      if (mime.indexOf(',') > -1) mime = mime.split(',', 2)[0]
      xhr.overrideMimeType && xhr.overrideMimeType(mime)
    }
    if (settings.contentType || (settings.contentType !== false && settings.data && settings.type.toUpperCase() != 'GET'))
      baseHeaders['Content-Type'] = (settings.contentType || 'application/x-www-form-urlencoded')
    settings.headers = $.extend(baseHeaders, settings.headers || {})

    xhr.onreadystatechange = function(){
      if (xhr.readyState == 4) {
        xhr.onreadystatechange = empty;
        clearTimeout(abortTimeout)
        var result, error = false
        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304 || (xhr.status == 0 && protocol == 'file:')) {
          dataType = dataType || mimeToDataType(xhr.getResponseHeader('content-type'))
          result = xhr.responseText

          try {
            // http://perfectionkills.com/global-eval-what-are-the-options/
            if (dataType == 'script')    (1,eval)(result)
            else if (dataType == 'xml')  result = xhr.responseXML
            else if (dataType == 'json') result = blankRE.test(result) ? null : $.parseJSON(result)
          } catch (e) { error = e }

          if (error) ajaxError(error, 'parsererror', xhr, settings)
          else ajaxSuccess(result, xhr, settings)
        } else {
          ajaxError(null, xhr.status ? 'error' : 'abort', xhr, settings)
        }
      }
    }

    var async = 'async' in settings ? settings.async : true
    xhr.open(settings.type, settings.url, async)

    for (name in settings.headers) xhr.setRequestHeader(name, settings.headers[name])

    if (ajaxBeforeSend(xhr, settings) === false) {
      xhr.abort()
      return false
    }

    if (settings.timeout > 0) abortTimeout = setTimeout(function(){
        xhr.onreadystatechange = empty
        xhr.abort()
        ajaxError(null, 'timeout', xhr, settings)
      }, settings.timeout)

    // avoid sending empty string (#319)
    xhr.send(settings.data ? settings.data : null)
    return xhr
  }

  $.get = function(url, success){ return $.ajax({ url: url, success: success }) }

  $.post = function(url, data, success, dataType){
    if ($.isFunction(data)) dataType = dataType || success, success = data, data = null
    return $.ajax({ type: 'POST', url: url, data: data, success: success, dataType: dataType })
  }

  $.getJSON = function(url, success){
    return $.ajax({ url: url, success: success, dataType: 'json' })
  }

  $.fn.load = function(url, success){
    if (!this.length) return this
    var self = this, parts = url.split(/\s/), selector
    if (parts.length > 1) url = parts[0], selector = parts[1]
    $.get(url, function(response){
      self.html(selector ?
        $('<div>').html(response.replace(rscript, "")).find(selector)
        : response)
      success && success.apply(self, arguments)
    })
    return this
  }

  var escape = encodeURIComponent

  function serialize(params, obj, traditional, scope){
    var type, array = $.isArray(obj)
    $.each(obj, function(key, value) {
      type = $.type(value)
      if (scope) key = traditional ? scope : scope + '[' + (array ? '' : key) + ']'
      // handle data in serializeArray() format
      if (!scope && array) params.add(value.name, value.value)
      // recurse into nested objects
      else if (type == "array" || (!traditional && type == "object"))
        serialize(params, value, traditional, key)
      else params.add(key, value)
    })
  }

  $.param = function(obj, traditional){
    var params = []
    params.add = function(k, v){ this.push(escape(k) + '=' + escape(v)) }
    serialize(params, obj, traditional)
    return params.join('&').replace(/%20/g, '+')
  }
})(Zepto)
<commit_msg>fix error callbacks for ajaxJSONP<commit_after>//     Zepto.js
//     (c) 2010-2012 Thomas Fuchs
//     Zepto.js may be freely distributed under the MIT license.

;(function($){
  var jsonpID = 0,
      document = window.document,
      key,
      name,
      rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
      scriptTypeRE = /^(?:text|application)\/javascript/i,
      xmlTypeRE = /^(?:text|application)\/xml/i,
      jsonType = 'application/json',
      htmlType = 'text/html',
      blankRE = /^\s*$/

  // trigger a custom event and return false if it was cancelled
  function triggerAndReturn(context, eventName, data) {
    var event = $.Event(eventName)
    $(context).trigger(event, data)
    return !event.defaultPrevented
  }

  // trigger an Ajax "global" event
  function triggerGlobal(settings, context, eventName, data) {
    if (settings.global) return triggerAndReturn(context || document, eventName, data)
  }

  // Number of active Ajax requests
  $.active = 0

  function ajaxStart(settings) {
    if (settings.global && $.active++ === 0) triggerGlobal(settings, null, 'ajaxStart')
  }
  function ajaxStop(settings) {
    if (settings.global && !(--$.active)) triggerGlobal(settings, null, 'ajaxStop')
  }

  // triggers an extra global event "ajaxBeforeSend" that's like "ajaxSend" but cancelable
  function ajaxBeforeSend(xhr, settings) {
    var context = settings.context
    if (settings.beforeSend.call(context, xhr, settings) === false ||
        triggerGlobal(settings, context, 'ajaxBeforeSend', [xhr, settings]) === false)
      return false

    triggerGlobal(settings, context, 'ajaxSend', [xhr, settings])
  }
  function ajaxSuccess(data, xhr, settings) {
    var context = settings.context, status = 'success'
    settings.success.call(context, data, status, xhr)
    triggerGlobal(settings, context, 'ajaxSuccess', [xhr, settings, data])
    ajaxComplete(status, xhr, settings)
  }
  // type: "timeout", "error", "abort", "parsererror"
  function ajaxError(error, type, xhr, settings) {
    var context = settings.context
    settings.error.call(context, xhr, type, error)
    triggerGlobal(settings, context, 'ajaxError', [xhr, settings, error])
    ajaxComplete(type, xhr, settings)
  }
  // status: "success", "notmodified", "error", "timeout", "abort", "parsererror"
  function ajaxComplete(status, xhr, settings) {
    var context = settings.context
    settings.complete.call(context, xhr, status)
    triggerGlobal(settings, context, 'ajaxComplete', [xhr, settings])
    ajaxStop(settings)
  }

  // Empty function, used as default callback
  function empty() {}

  $.ajaxJSONP = function(options){
    if (!('type' in options)) return $.ajax(options)

    var callbackName = 'jsonp' + (++jsonpID),
      script = document.createElement('script'),
      cleanup = function() {
        clearTimeout(abortTimeout)
        $(script).remove()
        delete window[callbackName]
      },
      abort = function(type){
        cleanup()
        // In case of manual abort or timeout, keep an empty function as callback
        // so that the SCRIPT tag that eventually loads won't result in an error.
        if (!type || type == 'timeout') window[callbackName] = empty
        ajaxError(null, type || 'abort', xhr, options)
      },
      xhr = { abort: abort }, abortTimeout

    serializeData(options)

    if (ajaxBeforeSend(xhr, options) === false) {
      abort('abort')
      return false
    }

    window[callbackName] = function(data){
      cleanup()
      ajaxSuccess(data, xhr, options)
    }

    script.onerror = function() { abort('error') }

    script.src = options.url.replace(/=\?/, '=' + callbackName)
    $('head').append(script)

    if (options.timeout > 0) abortTimeout = setTimeout(function(){
      abort('timeout')
    }, options.timeout)

    return xhr
  }

  $.ajaxSettings = {
    // Default type of request
    type: 'GET',
    // Callback that is executed before request
    beforeSend: empty,
    // Callback that is executed if the request succeeds
    success: empty,
    // Callback that is executed the the server drops error
    error: empty,
    // Callback that is executed on request complete (both: error and success)
    complete: empty,
    // The context for the callbacks
    context: null,
    // Whether to trigger "global" Ajax events
    global: true,
    // Transport
    xhr: function () {
      return new window.XMLHttpRequest()
    },
    // MIME types mapping
    accepts: {
      script: 'text/javascript, application/javascript',
      json:   jsonType,
      xml:    'application/xml, text/xml',
      html:   htmlType,
      text:   'text/plain'
    },
    // Whether the request is to another domain
    crossDomain: false,
    // Default timeout
    timeout: 0,
    // Whether data should be serialized to string
    processData: true
  }

  function mimeToDataType(mime) {
    return mime && ( mime == htmlType ? 'html' :
      mime == jsonType ? 'json' :
      scriptTypeRE.test(mime) ? 'script' :
      xmlTypeRE.test(mime) && 'xml' ) || 'text'
  }

  function appendQuery(url, query) {
    return (url + '&' + query).replace(/[&?]{1,2}/, '?')
  }

  // serialize payload and append it to the URL for GET requests
  function serializeData(options) {
    if (options.processData && options.data && $.type(options.data) != "string")
      options.data = $.param(options.data, options.traditional)
    if (options.data && (!options.type || options.type.toUpperCase() == 'GET'))
      options.url = appendQuery(options.url, options.data)
  }

  $.ajax = function(options){
    var settings = $.extend({}, options || {})
    for (key in $.ajaxSettings) if (settings[key] === undefined) settings[key] = $.ajaxSettings[key]

    ajaxStart(settings)

    if (!settings.crossDomain) settings.crossDomain = /^([\w-]+:)?\/\/([^\/]+)/.test(settings.url) &&
      RegExp.$2 != window.location.host

    var dataType = settings.dataType, hasPlaceholder = /=\?/.test(settings.url)
    if (dataType == 'jsonp' || hasPlaceholder) {
      if (!hasPlaceholder) settings.url = appendQuery(settings.url, 'callback=?')
      return $.ajaxJSONP(settings)
    }

    if (!settings.url) settings.url = window.location.toString()
    serializeData(settings)

    var mime = settings.accepts[dataType],
        baseHeaders = { },
        protocol = /^([\w-]+:)\/\//.test(settings.url) ? RegExp.$1 : window.location.protocol,
        xhr = settings.xhr(), abortTimeout

    if (!settings.crossDomain) baseHeaders['X-Requested-With'] = 'XMLHttpRequest'
    if (mime) {
      baseHeaders['Accept'] = mime
      if (mime.indexOf(',') > -1) mime = mime.split(',', 2)[0]
      xhr.overrideMimeType && xhr.overrideMimeType(mime)
    }
    if (settings.contentType || (settings.contentType !== false && settings.data && settings.type.toUpperCase() != 'GET'))
      baseHeaders['Content-Type'] = (settings.contentType || 'application/x-www-form-urlencoded')
    settings.headers = $.extend(baseHeaders, settings.headers || {})

    xhr.onreadystatechange = function(){
      if (xhr.readyState == 4) {
        xhr.onreadystatechange = empty;
        clearTimeout(abortTimeout)
        var result, error = false
        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304 || (xhr.status == 0 && protocol == 'file:')) {
          dataType = dataType || mimeToDataType(xhr.getResponseHeader('content-type'))
          result = xhr.responseText

          try {
            // http://perfectionkills.com/global-eval-what-are-the-options/
            if (dataType == 'script')    (1,eval)(result)
            else if (dataType == 'xml')  result = xhr.responseXML
            else if (dataType == 'json') result = blankRE.test(result) ? null : $.parseJSON(result)
          } catch (e) { error = e }

          if (error) ajaxError(error, 'parsererror', xhr, settings)
          else ajaxSuccess(result, xhr, settings)
        } else {
          ajaxError(null, xhr.status ? 'error' : 'abort', xhr, settings)
        }
      }
    }

    var async = 'async' in settings ? settings.async : true
    xhr.open(settings.type, settings.url, async)

    for (name in settings.headers) xhr.setRequestHeader(name, settings.headers[name])

    if (ajaxBeforeSend(xhr, settings) === false) {
      xhr.abort()
      return false
    }

    if (settings.timeout > 0) abortTimeout = setTimeout(function(){
        xhr.onreadystatechange = empty
        xhr.abort()
        ajaxError(null, 'timeout', xhr, settings)
      }, settings.timeout)

    // avoid sending empty string (#319)
    xhr.send(settings.data ? settings.data : null)
    return xhr
  }

  $.get = function(url, success){ return $.ajax({ url: url, success: success }) }

  $.post = function(url, data, success, dataType){
    if ($.isFunction(data)) dataType = dataType || success, success = data, data = null
    return $.ajax({ type: 'POST', url: url, data: data, success: success, dataType: dataType })
  }

  $.getJSON = function(url, success){
    return $.ajax({ url: url, success: success, dataType: 'json' })
  }

  $.fn.load = function(url, success){
    if (!this.length) return this
    var self = this, parts = url.split(/\s/), selector
    if (parts.length > 1) url = parts[0], selector = parts[1]
    $.get(url, function(response){
      self.html(selector ?
        $('<div>').html(response.replace(rscript, "")).find(selector)
        : response)
      success && success.apply(self, arguments)
    })
    return this
  }

  var escape = encodeURIComponent

  function serialize(params, obj, traditional, scope){
    var type, array = $.isArray(obj)
    $.each(obj, function(key, value) {
      type = $.type(value)
      if (scope) key = traditional ? scope : scope + '[' + (array ? '' : key) + ']'
      // handle data in serializeArray() format
      if (!scope && array) params.add(value.name, value.value)
      // recurse into nested objects
      else if (type == "array" || (!traditional && type == "object"))
        serialize(params, value, traditional, key)
      else params.add(key, value)
    })
  }

  $.param = function(obj, traditional){
    var params = []
    params.add = function(k, v){ this.push(escape(k) + '=' + escape(v)) }
    serialize(params, obj, traditional)
    return params.join('&').replace(/%20/g, '+')
  }
})(Zepto)
<|endoftext|>


<commit_before>/**
 * @file Miscellaneous utility functions
 * @author Capuccino
 * @author Ovyerus
 */
 const Eris = require('eris');

 /**
  * Class that handles miscellaneous utility functions
  */
 class Utils {
     /**
      * Converts milliseconds to a more human-readable format
      * @param {Number} ms Milliseconds to convert
      * @returns {String} Formatted string with days, hours, minutes and seconds.
      */
     static async msToTime(ms) {
         var time = ms/1000;
         var seconds = time % 60;
         time /=60;
         var minutes = time % 60;
         time /= 60;
         var hours = time % 24;
         time /= 24;
         var days = time;

         seconds = Math.floor(seconds);
         minutes = Math.floor(minutes);
         hours = Math.floor(hours);
         days = Math.floor(days);

         return `${days} days, ${hours}:${minutes}:${seconds}`;
     }

    /**
     * Easily format user names and discriminators
     * @param { Eris.User | Eris.Member} user the target user to format.
     * @param {Boolean} [noDiscrim=false] whether to not include or include the user's discriminator.
     * @returns {String} The users formatted name in the format 'user#0001' or likewise. Will use nickname if member is passed in as a user.
     */
     static async formatUsername(user, noDiscrim = false) {
         return user instanceof Eris.Member ? `${user.nick ? user.nick : user.user.username}${noDiscrim ? '' : `#${user.user.discriminator}`}` : `${user.username}${noDiscrim ? '' : `#${user.discriminator}`}`;
     }

     /**
      * Output a random color (usually for embeds)
      * @returns {Number} a colour.
      */
     static randomColour() {
         let colours = [
             0x7289DA, // Discord Blurple
             0x99AAB5, // Discord Greyple
             0xF44336, // Red - Rest are Material Design colours from here on
             0xE91E63, // Pink
             0x9C27B0, // Purple
             0x673AB7, // Deep Purple
             0x3F51B5, // Indigo
             0x2196F3, // Blue
             0x03A9F4, // Light Blue
             0x00BCD4, // Cyan
             0x009688, // Teal
             0x4CAF50, // Green
             0x8BC34A, // Light Green
             0xCDDC39, // Lime
             0xFFEB3B, // Yellow
             0xFFC107, // Amber
             0xFF9800, // Orange
             0xFF5722, // Deep Orange
             0x607D8B // Blue Grey
         ];
         return colours[Math.floor(Math.random() * colours.length)];
     }
 }

 module.exports = Utils;<commit_msg>fix indents<commit_after>/**
 * @file Miscellaneous utility functions
 * @author Capuccino
 * @author Ovyerus
 */
const Eris = require('eris');

/**
  * Class that handles miscellaneous utility functions
  */
class Utils {
    /**
      * Converts milliseconds to a more human-readable format
      * @param {Number} ms Milliseconds to convert
      * @returns {String} Formatted string with days, hours, minutes and seconds.
      */
    static async msToTime(ms) {
        var time = ms/1000;
        var seconds = time % 60;
        time /=60;
        var minutes = time % 60;
        time /= 60;
        var hours = time % 24;
        time /= 24;
        var days = time;

        seconds = Math.floor(seconds);
        minutes = Math.floor(minutes);
        hours = Math.floor(hours);
        days = Math.floor(days);

        return `${days} days, ${hours}:${minutes}:${seconds}`;
    }

    /**
     * Easily format user names and discriminators
     * @param { Eris.User | Eris.Member} user the target user to format.
     * @param {Boolean} [noDiscrim=false] whether to not include or include the user's discriminator.
     * @returns {String} The users formatted name in the format 'user#0001' or likewise. Will use nickname if member is passed in as a user.
     */
    static async formatUsername(user, noDiscrim = false) {
        return user instanceof Eris.Member ? `${user.nick ? user.nick : user.user.username}${noDiscrim ? '' : `#${user.user.discriminator}`}` : `${user.username}${noDiscrim ? '' : `#${user.discriminator}`}`;
    }

    /**
      * Output a random color (usually for embeds)
      * @returns {Number} a colour.
      */
    static randomColour() {
        let colours = [
            0x7289DA, // Discord Blurple
            0x99AAB5, // Discord Greyple
            0xF44336, // Red - Rest are Material Design colours from here on
            0xE91E63, // Pink
            0x9C27B0, // Purple
            0x673AB7, // Deep Purple
            0x3F51B5, // Indigo
            0x2196F3, // Blue
            0x03A9F4, // Light Blue
            0x00BCD4, // Cyan
            0x009688, // Teal
            0x4CAF50, // Green
            0x8BC34A, // Light Green
            0xCDDC39, // Lime
            0xFFEB3B, // Yellow
            0xFFC107, // Amber
            0xFF9800, // Orange
            0xFF5722, // Deep Orange
            0x607D8B // Blue Grey
        ];
        return colours[Math.floor(Math.random() * colours.length)];
    }
}

module.exports = Utils;<|endoftext|>


<commit_before>/* eslint-disable standard/no-callback-literal */

import * as admin from 'firebase-admin'
import AWS from 'aws-sdk'

const encryptedFirebasePrivateKey = process.env['FIREBASE_PRIVATE_KEY']
let decryptedFirebasePrivateKey

/*
 * Generate the AWS policy document to return from the authorizer.
 * Return an empty 'context' object if the user is denied access.
 * https://docs.aws.amazon.com/apigateway/latest/developerguide/use-custom-authorizer.html#api-gateway-custom-authorizer-output
 * @param {object} user - The user object from the decoded token.
 * @param {string} user.uid - The user's ID
 * @param {string} user.email - The user's email
 * @param {string} user.username - The user's username
 * @param {boolean} user.isAnonymous - Whether the user is anonymous
 * @param {boolean} user.emailVerified - Whether the user has verified their email
 * @param {boolean} allow - Whether the user is allowed access.
 * @param {string} resource - The AWS resource ARN the user wants to access.
 * @returns {object} The AWS policy
 */
const generatePolicy = function (user, allow, resource) {
  return {
    principalId: user.uid,
    policyDocument: {
      Version: '2012-10-17',
      Statement: [
        {
          Action: 'execute-api:Invoke',
          Effect: allow ? 'Allow' : 'Deny',
          Resource: resource
        }
      ]
    },
    context: (
      allow
      ? {
        id: user.uid,
        email: user.email,
        username: user.username,
        isAnonymous: user.isAnonymous,
        emailVerified: user.emailVerified
      }
      : {}
    )
  }
}

function checkUserAuthorization (event, context, callback) {
  console.log('checkUserAuthorization decryptedFirebasePrivateKey with replacement')
  const token = event.authorizationToken
  if (!token) {
    callback('Error: Invalid token')
  }
  if (decryptedFirebasePrivateKey) {
    console.log(decryptedFirebasePrivateKey.replace(/\\n/g, '\n'))
  }
  try {
    admin.initializeApp({
      credential: admin.credential.cert({
        projectId: process.env.FIREBASE_PROJECT_ID,
        clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
        // https://stackoverflow.com/a/41044630/1332513
        privateKey: decryptedFirebasePrivateKey.replace(/\\n/g, '\n')
      }),
      databaseURL: process.env.FIREBASE_DATABASE_URL
    })

    // Validate the Firebase token.
    admin.auth().verifyIdToken(token)
      .then((decodedToken) => {
        const user = {
          uid: decodedToken.uid,
          email: decodedToken.email,
          username: decodedToken.username,
          isAnonymous: decodedToken.isAnonymous,
          emailVerified: decodedToken.emailVerified
        }
        const valid = user.uid && user.emailVerified

        // Generate AWS authorization policy
        callback(null, generatePolicy(user, valid, event.methodArn))
      }).catch((e) => {
        console.error(e)
        callback('Error: Invalid token')
      })
  } catch (e) {
    console.error(e)
    callback('Error: Invalid token')
  }
}

const handler = (event, context, callback) => {
  console.log('firebase-authorizer handler')
  console.log('-------------------------------')
  console.log('encryptedFirebasePrivateKey', encryptedFirebasePrivateKey)
  console.log('-------------------------------')
  console.log('decryptedFirebasePrivateKey', decryptedFirebasePrivateKey)
  // Decrypt secure environment variables.
  if (decryptedFirebasePrivateKey) {
    checkUserAuthorization(event, context)
  } else {
    // Decrypt code should run once and variables stored outside of the function
    // handler so that these are decrypted once per container
    const kms = new AWS.KMS()
    kms.decrypt({ CiphertextBlob: Buffer.from(encryptedFirebasePrivateKey, 'base64') }, (err, data) => {
      if (err) {
        console.log('Decrypt error:', err)
        callback('Error decrypting secure environnment variables.')
        return
      }
      decryptedFirebasePrivateKey = data.Plaintext.toString('ascii')
      checkUserAuthorization(event, context, callback)
    })
  }
}

const serverlessHandler = (event, context, callback) => {
  handler(event, context, callback)
}

module.exports = {
  handler: handler,
  serverlessHandler: serverlessHandler,
  checkUserAuthorization: checkUserAuthorization
}
<commit_msg>Fix test.<commit_after>/* eslint-disable standard/no-callback-literal */

import * as admin from 'firebase-admin'
import AWS from 'aws-sdk'

const encryptedFirebasePrivateKey = process.env['FIREBASE_PRIVATE_KEY']
let decryptedFirebasePrivateKey = ''

/*
 * Generate the AWS policy document to return from the authorizer.
 * Return an empty 'context' object if the user is denied access.
 * https://docs.aws.amazon.com/apigateway/latest/developerguide/use-custom-authorizer.html#api-gateway-custom-authorizer-output
 * @param {object} user - The user object from the decoded token.
 * @param {string} user.uid - The user's ID
 * @param {string} user.email - The user's email
 * @param {string} user.username - The user's username
 * @param {boolean} user.isAnonymous - Whether the user is anonymous
 * @param {boolean} user.emailVerified - Whether the user has verified their email
 * @param {boolean} allow - Whether the user is allowed access.
 * @param {string} resource - The AWS resource ARN the user wants to access.
 * @returns {object} The AWS policy
 */
const generatePolicy = function (user, allow, resource) {
  return {
    principalId: user.uid,
    policyDocument: {
      Version: '2012-10-17',
      Statement: [
        {
          Action: 'execute-api:Invoke',
          Effect: allow ? 'Allow' : 'Deny',
          Resource: resource
        }
      ]
    },
    context: (
      allow
      ? {
        id: user.uid,
        email: user.email,
        username: user.username,
        isAnonymous: user.isAnonymous,
        emailVerified: user.emailVerified
      }
      : {}
    )
  }
}

function checkUserAuthorization (event, context, callback) {
  console.log('checkUserAuthorization decryptedFirebasePrivateKey with replacement')
  const token = event.authorizationToken
  if (!token) {
    callback('Error: Invalid token')
  }
  if (decryptedFirebasePrivateKey) {
    console.log(decryptedFirebasePrivateKey.replace(/\\n/g, '\n'))
  }
  try {
    admin.initializeApp({
      credential: admin.credential.cert({
        projectId: process.env.FIREBASE_PROJECT_ID,
        clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
        // https://stackoverflow.com/a/41044630/1332513
        privateKey: decryptedFirebasePrivateKey.replace(/\\n/g, '\n')
      }),
      databaseURL: process.env.FIREBASE_DATABASE_URL
    })

    // Validate the Firebase token.
    admin.auth().verifyIdToken(token)
      .then((decodedToken) => {
        const user = {
          uid: decodedToken.uid,
          email: decodedToken.email,
          username: decodedToken.username,
          isAnonymous: decodedToken.isAnonymous,
          emailVerified: decodedToken.emailVerified
        }
        const valid = user.uid && user.emailVerified

        // Generate AWS authorization policy
        callback(null, generatePolicy(user, valid, event.methodArn))
      }).catch((e) => {
        console.error(e)
        callback('Error: Invalid token')
      })
  } catch (e) {
    console.error(e)
    callback('Error: Invalid token')
  }
}

const handler = (event, context, callback) => {
  console.log('firebase-authorizer handler')
  console.log('-------------------------------')
  console.log('encryptedFirebasePrivateKey', encryptedFirebasePrivateKey)
  console.log('-------------------------------')
  console.log('decryptedFirebasePrivateKey', decryptedFirebasePrivateKey)
  // Decrypt secure environment variables.
  if (decryptedFirebasePrivateKey) {
    checkUserAuthorization(event, context)
  } else {
    // Decrypt code should run once and variables stored outside of the function
    // handler so that these are decrypted once per container
    const kms = new AWS.KMS()
    kms.decrypt({ CiphertextBlob: Buffer.from(encryptedFirebasePrivateKey, 'base64') }, (err, data) => {
      if (err) {
        console.log('Decrypt error:', err)
        callback('Error decrypting secure environnment variables.')
        return
      }
      decryptedFirebasePrivateKey = data.Plaintext.toString('ascii')
      checkUserAuthorization(event, context, callback)
    })
  }
}

const serverlessHandler = (event, context, callback) => {
  handler(event, context, callback)
}

module.exports = {
  handler: handler,
  serverlessHandler: serverlessHandler,
  checkUserAuthorization: checkUserAuthorization
}
<|endoftext|>


<commit_before>/* jQuery UI dialog clickoutside */

/*
The MIT License (MIT)

Copyright (c) {{year}} {{fullname}}

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

$.widget( "ui.dialog", $.ui.dialog, {
  options: {
    clickOutside: false, // Determine if clicking outside the dialog shall close it
    clickOutsideTrigger: "" // Element (id or class) that triggers the dialog opening
  },

  open: function() {
    var clickOutsideTriggerEl = $( this.options.clickOutsideTrigger );
    var that = this;

    if (this.options.clickOutside){
      // Add document wide click handler for the current dialog namespace
      $(document).on( "click.ui.dialogClickOutside" + that.eventNamespace, function(event){
        if ( $(event.target).closest($(clickOutsideTriggerEl)).length == 0 && $(event.target).closest($(that.uiDialog)).length == 0){
          that.close();
        }
      });
    }

    this._super(); // Invoke parent open method
  },

  close: function() {
    var that = this;

    // Remove document wide click handler for the current dialog
    $(document).off( "click.ui.dialogClickOutside" + that.eventNamespace );

    this._super(); // Invoke parent close method
  },

});
<commit_msg>updated license<commit_after>/* jQuery UI dialog clickoutside */

/*
The MIT License (MIT)

Copyright (c) 2013 - AGENCE WEB COHERACTIO

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

$.widget( "ui.dialog", $.ui.dialog, {
  options: {
    clickOutside: false, // Determine if clicking outside the dialog shall close it
    clickOutsideTrigger: "" // Element (id or class) that triggers the dialog opening
  },

  open: function() {
    var clickOutsideTriggerEl = $( this.options.clickOutsideTrigger );
    var that = this;

    if (this.options.clickOutside){
      // Add document wide click handler for the current dialog namespace
      $(document).on( "click.ui.dialogClickOutside" + that.eventNamespace, function(event){
        if ( $(event.target).closest($(clickOutsideTriggerEl)).length == 0 && $(event.target).closest($(that.uiDialog)).length == 0){
          that.close();
        }
      });
    }

    this._super(); // Invoke parent open method
  },

  close: function() {
    var that = this;

    // Remove document wide click handler for the current dialog
    $(document).off( "click.ui.dialogClickOutside" + that.eventNamespace );

    this._super(); // Invoke parent close method
  },

});
<|endoftext|>


<commit_before>import async from 'async';
import log from 'winston';
import tesseract from 'node-tesseract';
import nodecr from 'nodecr';

class OCRExtractor {
    constructor(file, config) {
        this.config = config;
        this.file = file;
    }

    extract(next) {
        console.log('---------- OCR Extraction start');
        let extracts = [];
        async.waterfall([
            () => {
            this.tesseract(extracts, next);
            },
            OCRExtractor.mySecondFunction,
            OCRExtractor.myLastFunction,
        ], (err, result) => {
            if (err !== null) {
                log.error(`[OCRExtractor.extract] ${err}`);
            }
            next(err, result);
        });
    }

    tesseract(extracts, next) {
        nodecr.process(this.file,function(err, text) {
            log.info('[OCR][TESSERACT] Result : ');
            if (err !== null) {
                log.info('Error :');
                log.info(err);
            } else {
                log.info('Success :');
                log.info(text);
            }
            extracts.tesseract = text;
            next(err, text);
        }, null, 6);
    }

    static mySecondFunction(arg1, arg2, next) {
        // arg1 now equals 'one' and arg2 now equals 'two'
        next(null, 'three');
    }

    static myLastFunction(arg1, next) {
        // arg1 now equals 'three'
        next(null, 'done');
    }
}

export default OCRExtractor;<commit_msg>tesseract test<commit_after>import async from 'async';
import log from 'winston';
import tesseract from 'node-tesseract';
import nodecr from 'nodecr';

class OCRExtractor {
    constructor(file, config) {
        this.config = config;
        this.file = file;
    }

    extract(next) {
        console.log('---------- OCR Extraction start');
        let extracts = [];
        async.parallel({
            tesseract: (callback) => {
                this.tesseract(extracts, callback);
            },
            ocr: (callback) => {
                this.ocr(extracts, callback);
            }
        }, (err, results) => {
            if (err !== null) {
                log.error(`[OCRExtractor.extract] ${err}`);
            }
            next(err, results);
        });
    }

    tesseract(extracts, next) {
        nodecr.process(this.file, function(error, text) {
            log.info('[OCR][TESSERACT] Result : ');
            if (error !== null) {
                log.info('Error :');
                log.info(error);
            } else {
                text = text.trim();
                log.info('Success :');
                log.info(text);
            }
            extracts.tesseract = {text, error};
            next(null, extracts);
        }, null, 6);
    }

    ocr(extracts, next) {
        nodecr.process(this.file, function(error, text) {
            log.info('[OCR][OCR] Result : ');
            if (error !== null) {
                log.info('Error :');
                log.info(error);
            } else {
                text = text.trim();
                log.info('Success :');
                log.info(text);
            }
            extracts.tesseract = {text, error};
            next(null, extracts);
        }, null, 6);
    }
}

export default OCRExtractor;<|endoftext|>


<commit_before>import * as firebase from 'firebase';
import { push } from 'react-router-redux';
import { browserHistory } from 'react-router';

import { firebaseAuth, firebaseDb } from '../firebase/firebase';
import * as types from './types';

import directActions from './directs';
import meetingActions from './meetings';
import followUpActions from './followUps';

const recordLogin = (accountData) => {
  firebaseDb.ref('accounts').child(accountData.uid).set(accountData)
    .catch((error) => {
      console.log(error);
    });
};

export function isAuthenticated(state) {
  return state.auth.status === types.AUTH_LOGGED_IN;
}

export function rootPath(authenticated) {
  return authenticated ? '/dashboard' : '/';
}

export const listenToAuth = () => {
  return (dispatch, getState) => {
    firebaseAuth.onAuthStateChanged((authData) => {
      if (authData) {
        dispatch({
          ...authData.toJSON(),
          type: types.AUTH_LOGIN,
        });

        // reload on auth update.
        directActions.subscribe(dispatch, getState);
        meetingActions.subscribe(dispatch, getState);
        followUpActions.subscribe(dispatch, getState);
        browserHistory.push(rootPath(true));

        recordLogin({
          ...authData.toJSON(),
          lastLogin: new Date().toISOString(),
        });
      } else if (getState().auth.status !== types.AUTH_ANONYMOUS) {
        dispatch({ type: types.AUTH_LOGOUT });
      }
    });
  };
};

export const openAuth = () => {
  return (dispatch) => {
    dispatch({ type: types.AUTH_AWAITING_RESPONSE });

    const provider = new firebase.auth.GoogleAuthProvider();
    firebaseAuth.signInWithRedirect(provider);
    firebaseAuth.getRedirectResult().catch((error) => {
      const errorMessage = error.message;
      console.log(errorMessage);
      dispatch({
        type: types.AUTH_ERROR,
        error: `Login failed! ${errorMessage}`,
      });
      dispatch({ type: types.AUTH_LOGOUT });
    });
  };
};

export const logoutUser = () => {
  return (dispatch, getState) => {
    directActions.unsubscribe(dispatch, getState);
    firebaseAuth.signOut().then(() => {
      dispatch({ type: types.AUTH_LOGOUT });
      dispatch(push(rootPath(false)));
    });
  };
};

export function requireAuth(nextState, replace) {
  return (dispatch, getState) => {
    if (!isAuthenticated(getState())) {
      replace({
        pathname: rootPath(false),
        state: { nextPathname: nextState.location.pathname },
      });
    }
  };
}
<commit_msg>feature(auth): show error alert on login failure, previously was silent<commit_after>import * as firebase from 'firebase';
import { push } from 'react-router-redux';
import { browserHistory } from 'react-router';

import { firebaseAuth, firebaseDb } from '../firebase/firebase';
import * as types from './types';

import directActions from './directs';
import meetingActions from './meetings';
import followUpActions from './followUps';

const recordLogin = (accountData) => {
  firebaseDb.ref('accounts').child(accountData.uid).set(accountData)
    .catch((error) => {
      console.log(error);
    });
};

export function isAuthenticated(state) {
  return state.auth.status === types.AUTH_LOGGED_IN;
}

export function rootPath(authenticated) {
  return authenticated ? '/dashboard' : '/';
}

export const listenToAuth = () => {
  return (dispatch, getState) => {
    firebaseAuth.onAuthStateChanged((authData) => {
      if (authData) {
        dispatch({
          ...authData.toJSON(),
          type: types.AUTH_LOGIN,
        });

        // reload on auth update.
        directActions.subscribe(dispatch, getState);
        meetingActions.subscribe(dispatch, getState);
        followUpActions.subscribe(dispatch, getState);
        browserHistory.push(rootPath(true));

        recordLogin({
          ...authData.toJSON(),
          lastLogin: new Date().toISOString(),
        });
      } else if (getState().auth.status !== types.AUTH_ANONYMOUS) {
        dispatch({ type: types.AUTH_LOGOUT });
      }
    });
  };
};

export const openAuth = () => {
  return (dispatch) => {
    dispatch({ type: types.AUTH_AWAITING_RESPONSE });

    const provider = new firebase.auth.GoogleAuthProvider();
    firebaseAuth.signInWithRedirect(provider);
    firebaseAuth.getRedirectResult().catch((error) => {
      const errorMessage = error.message;
      console.log(errorMessage);
      alert(errorMessage);
      dispatch({
        type: types.AUTH_ERROR,
        error: `Login failed! ${errorMessage}`,
      });
      dispatch({ type: types.AUTH_LOGOUT });
    });
  };
};

export const logoutUser = () => {
  return (dispatch, getState) => {
    directActions.unsubscribe(dispatch, getState);
    firebaseAuth.signOut().then(() => {
      dispatch({ type: types.AUTH_LOGOUT });
      dispatch(push(rootPath(false)));
    });
  };
};

export function requireAuth(nextState, replace) {
  return (dispatch, getState) => {
    if (!isAuthenticated(getState())) {
      replace({
        pathname: rootPath(false),
        state: { nextPathname: nextState.location.pathname },
      });
    }
  };
}
<|endoftext|>


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

  var _ = require('./vendor/underscore-min.js'),
      $ = require('./vendor/jquery-2.0.3.min.js'),
      fs = require('fs');

  var gui = window.require('nw.gui');
  var win = gui.Window.get();

  var Moonshot = function Moonshot(){
    _.templateSettings.variable = 'rc';
    var games = {};

    var template = _.template($( 'script.template' ).html());
    fs.readdirSync('./games/')
      .filter(function(file) { return fs.statSync('./games/'+file).isDirectory() === true })
      .forEach(function(gameSlug) {
    if (fs.existsSync('./games/'+gameSlug+'/lexitron.json')) {
     var game = JSON.parse(
       fs.readFileSync('./games/'+gameSlug+'/lexitron.json', 'utf8')
     );
     game.slug = gameSlug;
     if(game.exec[0] !== '/') {
      game.exec = process.cwd() + '/' + game.exec;
     }
     if(game.cwd[0] !== '/') {
      game.exec = process.cwd() + '/' + game.exec;
     }
     games[game.slug] = game;
    }
    });
    var templateData = {
      games: games
    };
    $( '.slides' ).append(
      template( templateData )
    );
    $('.slides script').remove();
    this.games = games;
  };

  Moonshot.prototype = {
    _fonts: [
      'bitterregular'
      ,'armataregular'
      ,'averia_serif_libreregular'
      ,'ralewayregular'
      ,'share_tech_monoregular'
      ,'vigaregular'
    ]

    ,_fontIndex: 0

    ,launch: function(input, Reveal, Parallax, callback) {
      var self = this;
      this._cp = require('child_process');
      this._finish = callback;
      this._input = input;
      this._gallery = Reveal;
      Reveal.initialize({
        width: window.innerWidth
        ,height: window.innerHeight
        ,loop: true
        ,keyboard: false
        ,transition: 'cube'
        ,autoSlide: 0
      });
      this._entities = [];
      $.each($('.entity'), function(i, el) {
        var $el = $(el);
        $el.css('left', 0);
        self._entities.push({
          el: el
          ,vx: $el.data('velocity-x') || 0
          ,vy: $el.data('velocity-y') || 0
          ,animate: function() {
            var left = $el.css('left')
              ,top = $el.css('top');
            $el.css('left', parseFloat(left.substr(0, left.length-2))+this.vx+'px');
            $el.css('top', parseFloat(top.substr(0, top.length-2))-this.vy+'px');
            //  console.log('set left to '+left+'-->'+$el.css('left'));
          }
        });
      });
      var scene = window.document.getElementById('scene');
      this._parallax = new Parallax(scene);
      // this is mainly for debugging
      this._parallax.onMouseMove = null;

      var slideCount = $('.slides')[0].childElementCount;
      this._gallery.addEventListener('slidechanged', function(event) {
        self._parallax.ix = event.indexh/slideCount;
        // removing this while we work on just reacting to dx
        // self._parallax.iy = event.indexv;
      });
      this.setupInputs();
      this._setFont();
      this.animate.call(this);
    }
    ,animate: function() {
      window.moonshot._entities.forEach(function(entity) {
        entity.animate();
      });
      window.requestAnimationFrame(window.moonshot.__proto__.animate);
    }
    ,setAttractMode: function(enable) {
      var self = this;
      if(!enable) {
        window.clearTimeout(this._attractTimer);
        this._attractTimer = window.setTimeout(
          function() {self.setAttractMode(true);}
          , 30000);
      }
      // if we want to enable or
      if (enable || this._attractMode) {
        $('[class*="autoslide"]').each(function(i, slide) {
          var delay = enable ? slide.className.match(/autoslide-(\d+)/)[1] : 0;
          slide.setAttribute('data-autoslide', delay);
        });
        this._attractMode = !this._attractMode ? 1 : 0;
        this._gallery.configure({ autoSlide: this._attractMode });
      }
    }
    ,setupInputs: function() {
      var input = this._input;

      input.on('button_down', _.bind(function(button, padnum) {
        this.setAttractMode(false);
        switch(button) {
          case 'button1':
          case 'action':
          console.log(this._gallery.getCurrentSlide());
            this.startGame(this._gallery.getIndices().h);
            break;
          case 'left':
            this._gallery.left();
            break;
          case 'right':
            this._gallery.right();
            break;
          case 'up':
            this._gallery.up();
            break;
          case 'down':
            this._gallery.down();
            break;
          case 'button5':
            this._nextFont();
            break;
          case 'button6':
            this._prevFont();
            break;
          case 'inspector':
            win.showDevTools();
            break;
          case 'fullscreen':
            win.toggleFullscreen();
            break;
          case 'quit':
            gui.App.quit();
            break;
        }
      }, this));
    }

    ,startGame: _.throttle(function(idx) {
      var gameObj = $('#moonshot .game')[idx];
      var gameSlug = $(gameObj).data('slug');
      var exec = this.games[gameSlug].exec || ""
        , args = this.games[gameSlug].args || ""
        , options = this.games[gameSlug].cwd ? {cwd: this.games[gameSlug].cwd} : {};

      this._input.teardown();
      var gameProc = this._cp.exec(exec+" "+args, options, _.bind(function(error, stdout, stderr) {
        if (error) {
          console.log(error.stack);
          console.log('Error code: '+error.code);
          console.log('Signal received: '+error.signal);
        }
        console.log('Child Process STDOUT: '+stdout);
        console.log('Child Process STDERR: '+stderr);
        this.setupInputs();
      }, this));
     gameProc.on('exit', function (code) {
       console.log('Child process exited with exit code '+code);
     });
    }, 5000, {trailing: false})

    ,_nextFont: function() {
      // TODO: not working.
      this._fontIndex--;
      this._setFont();
    }

    ,_prevFont: function() {
      this._fontIndex++;
      if (this._fontIndex > this._fonts.length - 1) {
        this._fontIndex = this._fonts.length - 1;
      }
      this._setFont();
    }

    ,_setFont: function() {
      this._fontIndex = this._clamp(this._fontIndex, 0, this._fonts.length - 1);
      $('#moonshot').css('font-family', this._fonts[this._fontIndex]);
    }

    ,_clamp: function(num, min, max) {
      return Math.min(Math.max(min, num), max);
    }
  };

  exports.Moonshot = Moonshot;

})(((typeof(module) !== 'undefined') && module.exports) || window);
<commit_msg>Calls start game by slide slug if that slug is registered as a game. We can add behavior for ad/info slides here.<commit_after>(function(exports) {
  'use strict';

  var _ = require('./vendor/underscore-min.js'),
      $ = require('./vendor/jquery-2.0.3.min.js'),
      fs = require('fs');

  var gui = window.require('nw.gui');
  var win = gui.Window.get();

  var Moonshot = function Moonshot(){
    _.templateSettings.variable = 'rc';
    var games = {};

    var template = _.template($( 'script.template' ).html());
    fs.readdirSync('./games/')
      .filter(function(file) { return fs.statSync('./games/'+file).isDirectory() === true })
      .forEach(function(gameSlug) {
    if (fs.existsSync('./games/'+gameSlug+'/lexitron.json')) {
     var game = JSON.parse(
       fs.readFileSync('./games/'+gameSlug+'/lexitron.json', 'utf8')
     );
     game.slug = gameSlug;
     if(game.exec[0] !== '/') {
      game.exec = process.cwd() + '/' + game.exec;
     }
     if(game.cwd[0] !== '/') {
      game.exec = process.cwd() + '/' + game.exec;
     }
     games[game.slug] = game;
    }
    });
    var templateData = {
      games: games
    };
    $( '.slides' ).append(
      template( templateData )
    );
    $('.slides script').remove();
    this.games = games;
  };

  Moonshot.prototype = {
    _fonts: [
      'bitterregular'
      ,'armataregular'
      ,'averia_serif_libreregular'
      ,'ralewayregular'
      ,'share_tech_monoregular'
      ,'vigaregular'
    ]

    ,_fontIndex: 0

    ,launch: function(input, Reveal, Parallax, callback) {
      var self = this;
      this._cp = require('child_process');
      this._finish = callback;
      this._input = input;
      this._gallery = Reveal;
      Reveal.initialize({
        width: window.innerWidth
        ,height: window.innerHeight
        ,loop: true
        ,keyboard: false
        ,transition: 'cube'
        ,autoSlide: 0
      });
      this._entities = [];
      $.each($('.entity'), function(i, el) {
        var $el = $(el);
        $el.css('left', 0);
        self._entities.push({
          el: el
          ,vx: $el.data('velocity-x') || 0
          ,vy: $el.data('velocity-y') || 0
          ,animate: function() {
            var left = $el.css('left')
              ,top = $el.css('top');
            $el.css('left', parseFloat(left.substr(0, left.length-2))+this.vx+'px');
            $el.css('top', parseFloat(top.substr(0, top.length-2))-this.vy+'px');
            //  console.log('set left to '+left+'-->'+$el.css('left'));
          }
        });
      });
      var scene = window.document.getElementById('scene');
      this._parallax = new Parallax(scene);
      // this is mainly for debugging
      this._parallax.onMouseMove = null;

      var slideCount = $('.slides')[0].childElementCount;
      this._gallery.addEventListener('slidechanged', function(event) {
        self._parallax.ix = event.indexh/slideCount;
        // removing this while we work on just reacting to dx
        // self._parallax.iy = event.indexv;
      });
      this.setupInputs();
      this._setFont();
      this.animate.call(this);
    }
    ,animate: function() {
      window.moonshot._entities.forEach(function(entity) {
        entity.animate();
      });
      window.requestAnimationFrame(window.moonshot.__proto__.animate);
    }
    ,setAttractMode: function(enable) {
      var self = this;
      if(!enable) {
        window.clearTimeout(this._attractTimer);
        this._attractTimer = window.setTimeout(
          function() {self.setAttractMode(true);}
          , 30000);
      }
      // if we want to enable or
      if (enable || this._attractMode) {
        $('[class*="autoslide"]').each(function(i, slide) {
          var delay = enable ? slide.className.match(/autoslide-(\d+)/)[1] : 0;
          slide.setAttribute('data-autoslide', delay);
        });
        this._attractMode = !this._attractMode ? 1 : 0;
        this._gallery.configure({ autoSlide: this._attractMode });
      }
    }
    ,setupInputs: function() {
      var input = this._input;

      input.on('button_down', _.bind(function(button, padnum) {
        this.setAttractMode(false);
        switch(button) {
          case 'button1':
          case 'action':
            var slug = $(this._gallery.getCurrentSlide()).parent().data('slug');
            if(this.game.hasOwnProperty(slug)) {
              this.startGame(slug);
            }
            break;
          case 'left':
            this._gallery.left();
            break;
          case 'right':
            this._gallery.right();
            break;
          case 'up':
            this._gallery.up();
            break;
          case 'down':
            this._gallery.down();
            break;
          case 'button5':
            this._nextFont();
            break;
          case 'button6':
            this._prevFont();
            break;
          case 'inspector':
            win.showDevTools();
            break;
          case 'fullscreen':
            win.toggleFullscreen();
            break;
          case 'quit':
            gui.App.quit();
            break;
        }
      }, this));
    }

    ,startGame: _.throttle(function(gameSlug) {
      var exec = this.games[gameSlug].exec || ""
        , args = this.games[gameSlug].args || ""
        , options = this.games[gameSlug].cwd ? {cwd: this.games[gameSlug].cwd} : {};

      this._input.teardown();
      var gameProc = this._cp.exec(exec+" "+args, options, _.bind(function(error, stdout, stderr) {
        if (error) {
          console.log(error.stack);
          console.log('Error code: '+error.code);
          console.log('Signal received: '+error.signal);
        }
        console.log('Child Process STDOUT: '+stdout);
        console.log('Child Process STDERR: '+stderr);
        this.setupInputs();
      }, this));
     gameProc.on('exit', function (code) {
       console.log('Child process exited with exit code '+code);
     });
    }, 5000, {trailing: false})

    ,_nextFont: function() {
      // TODO: not working.
      this._fontIndex--;
      this._setFont();
    }

    ,_prevFont: function() {
      this._fontIndex++;
      if (this._fontIndex > this._fonts.length - 1) {
        this._fontIndex = this._fonts.length - 1;
      }
      this._setFont();
    }

    ,_setFont: function() {
      this._fontIndex = this._clamp(this._fontIndex, 0, this._fonts.length - 1);
      $('#moonshot').css('font-family', this._fonts[this._fontIndex]);
    }

    ,_clamp: function(num, min, max) {
      return Math.min(Math.max(min, num), max);
    }
  };

  exports.Moonshot = Moonshot;

})(((typeof(module) !== 'undefined') && module.exports) || window);
<|endoftext|>


<commit_before>/**
 * Write an array of all properties to the sheet.
 * @param {string} sheetName The name of the sheet where the data will
 * be written.
 * @param {string} rangeName The range for the given sheet were the data
 * will be written.
 */
function writeDestinationPropertiesToSheet(sheetName, rangeName) {
  const allProperties = getAllProperties();
  allProperties.forEach(property => property.push(false));
  const range = ss.getSheetByName(sheetName).getRange(
    rangeName.write.row,
    rangeName.write.column,
    allProperties.length,
    rangeName.write.numColumns
  );
  range.setValues(allProperties);
}

/**
 * Either creates new or updates existing custom definitions for selected
 * Universal Analytics properties.
 * @param {string} sheetName The name of the sheet where the information exists.
 * @param {!Object} templateValuesRange The range of the template custom definitions
 * on the sheet.
 * @param {!Object} destinationPropertyRange The range of the destination properties
 * on the sheet.
 * @param {!Object} settingsRange The range for the settings on the sheet.
 * @param {string} type Either custom dimensions or custom metrics.
 */
function modifyUACustomDefinitions(
  sheetName, templateValuesRange, destinationPropertyRange, settingsRange, type) {
  const modifyCustomDefinitionSheet = ss.getSheetByName(sheetName);
  let selectedDestinationProperties = modifyCustomDefinitionSheet.getRange(
    destinationPropertyRange.read.row,
    destinationPropertyRange.read.column,
    modifyCustomDefinitionSheet.getLastRow(),
    destinationPropertyRange.read.numColumns
  ).getValues();
  selectedDestinationProperties = selectedDestinationProperties.filter(row => row[5] == true);
  let templateValues = modifyCustomDefinitionSheet.getRange(
    templateValuesRange.read.row,
    templateValuesRange.read.column,
    modifyCustomDefinitionSheet.getLastRow(),
    templateValuesRange.read.numColumns
  ).getValues();
  templateValues = templateValues.filter(row => row[0] != '');
  const modifySettings = modifyCustomDefinitionSheet.getRange(
    settingsRange.read.row,
    settingsRange.read.column,
    settingsRange.read.numRows,
    settingsRange.read.numColumns
  ).getValues();
  const overwriteExisting = modifySettings[0][0];
  if (templateValues.length > 0 && selectedDestinationProperties.length > 0) {
    selectedDestinationProperties.forEach(property => {
      const existingDestinationValues = getCustomDimensions(property[1], property[3]);
      for (let i = 0; i < templateValues.length; i++) {
        if (!property[5] && i > 19) {
          break;
        }
        const templateValue = templateValues[i];
        const existingValue = existingDestinationValues[i];
        const templateRequest = {
          accountId: property[1],
          propertyId: property[3],
          index: templateValue[0],
          body: {
            name: templateValue[1],
            scope: templateValue[2],
            active: templateValue[3]
          }
        };
        let placeholderName = modifySettings[1][0] || 'Placeholder';
        let placeholderScope = modifySettings[2][0] || 'HIT';
        let placeholderActive = modifySettings[3][0] || false;
        const placeholderRequest = {
          accountId: property[1],
          propertyId: property[3],
          index: templateValue[0],
          body: {
            name:  placeholderName + ' ' + templateValue[0],
            scope: placeholderScope,
            active: placeholderActive
          }
        };
        if (type == 'custom metrics') {
          templateRequest.body.minValue = templateValue[4];
          templateRequest.body.maxValue = templateValue[5];
          templateRequest.body.type = templateValue[6];
          placeholderRequest.body.minValue = modifySettings[4][0];
          placeholderRequest.body.maxValue = modifySettings[5][0];
          placeholderRequest.body.type = modifySettings[6][0] || 'INTEGER';
        }
        if (existingValue != undefined) {
          if (templateValue[templateValue.length - 1]) {
            if (overwriteExisting) {
              if (templateValue[1] != existingValue.name ||
              templateValue[2] != existingValue.scope ||
              templateValue[3] != existingValue.active) {
                let response = null;
                let resultsSheetName = '';
                let resultsRange = {};
                if (type == 'custom dimensions') {
                  response = updateCustomDimension(templateRequest);
                  resultsSheetName = sheetNames.ua.modifyCdsResults;
                  resultsRange = sheetRanges.ua.modifyCdsResults;
                } else if (type == 'custom metrics' &&
                templateValue[4] != existingValue.min_value &&
                templateValue[5] != existingValue.max_value &&
                templateValue[6] != existingValue.type) {
                  response = updateCustomMetric(templateRequest);
                  resultsSheetName = sheetNames.ua.modifyCmsResults;
                  resultsRange = sheetRanges.ua.modifyCmsResults;
                }
                writeUACustomDefinitionModificationToSheet(
                  type, response, property[1], property[3], 'created',
                  resultsSheetName, resultsRange);
                Utilities.sleep(750);
              }
            }
          }
        } else {
          if (templateCd[4]) {
            let response = null;
            let resultsSheetName = '';
            let resultsRange = {};
            if (type == 'custom dimensions') {
              response = createCustomDimension(templateRequest);
              resultsSheetName = sheetNames.ua.modifyCdsResults;
              resultsRange = sheetRanges.ua.modifyCdsResults;
            } else if (type == 'custom metrics') {
              response = createCustomMetric(templateRequest);
              resultsSheetName = sheetNames.ua.modifyCmsResults;
              resultsRange = sheetRanges.ua.modifyCmsResults;
            }
            writeUACustomDefinitionModificationToSheet(
              type, response, property[1], property[3], 'created',
              resultsSheetName, resultsRange);
            Utilities.sleep(750);
          } else {
            let response = null;
            let resultsSheetName = '';
            let resultsRange = {};
            if (type == 'custom dimensions') {
              response = createCustomDimension(placeholderRequest);
              resultsSheetName = sheetNames.ua.modifyCdsResults;
              resultsRange = sheetRanges.ua.modifyCdsResults;
            } else if (type == 'custom metrics') {
              response = createCustomMetric(placeholderRequest);
              resultsSheetName = sheetNames.ua.modifyCmsResults;
              resultsRange = sheetRanges.ua.modifyCmsResults;
            }
            writeUACustomDefinitionModificationToSheet(
              type, response, property[1], property[3], 'created',
              resultsSheetName, resultsRange);
            Utilities.sleep(750);
          }
        }
      }
    });
  }
}

/**
 * Write template property custom dimensions to sheet.
 * @param {string} sheetName
 * @param {!Object} templatePropertyRange
 * @param {!Object} templateValuesRange
 * @param {string} type
 */
function writeTemplateCustomDefinitionsToSheet(
  sheetName, templatePropertyRange, templateValuesRange, type) {
  const sheet = ss.getSheetByName(sheetName);
  // Get template IDs from the sheet.
  const ids = sheet.getRange(
    templatePropertyRange.read.row,
    templatePropertyRange.read.column,
    templatePropertyRange.read.numRows,
    templatePropertyRange.read.numColumns
  ).getValues();
  // Get the template property custom dimensions.
  let definitions = null;
  if (type == 'custom dimensions') {
    definitions = listCustomDimensions(ids[0][1], ids[0][3]);
  } else if (type == 'custom metrics') {
    definitions = listCustomMetrics(ids[0][1], ids[0][3]);
  }
  if (definitions.length > 0) {
    // Remove the account ID and property ID for each definition.
    definitions.forEach(definition => {
      definition.shift();
      definition.shift();
    });
    const range = sheet.getRange(
      templateValuesRange.write.row,
      templateValuesRange.write.column,
      definitions.length,
      templateValuesRange.write.numColumns
    );
    range.setValues(definitions);
  }
}

/**
 * Write the results of modifying a UA custom dimension or metric to a sheet.
 * @param {string} type Either custom dimensions or custom metrics.
 * @param {!Object} values The UA custom metric or dimension after it has been modified.
 * @param {number} accountId The account ID for the custom metric or dimension.
 * @param {string} propertyId The property ID for the custom metric or dimension.
 * @param {string} actionTaken The action taken on the custom metric or dimension.
 * @param {string} sheetName The sheet name where the results will be written.
 * @param {!Object} sheetRange The range where the results will be written.
 */
function writeUACustomDefinitionModificationToSheet(
  type, values, accountId, propertyId, actionTaken, sheetName, sheetRange) {
  const result = [];
  const date = new Date();
  if (type == 'custom dimensions') {
    result.push([
      accountId, propertyId,
      values.index, values.name, values.scope, values.active,
      actionTaken, date
    ]);
  } else if (type == 'custom metrics') {
    result.push([
      accountId, propertyId,
      values.index, values.name, values.scope, values.active,
      values.min_value, values.max_value, values.type,
      actionTaken, date
    ]);
  }
  ss.getSheetByName(sheetName).getRange(
    ss.getSheetByName(sheetName).getLastRow() + 1,
    sheetRange.write.column, 1,
    sheetRange.write.numColumns).setValues(result);
}

/**
 * Write an array of all properties to the sheet Custom Dimension - Modify sheet.
 */
function writeCustomDimensionDestinationPropertiesToSheet() {
  writeDestinationPropertiesToSheet(
    sheetNames.ua.modifyCds,
    sheetRanges.ua.modifyCdsDestinationProperties
  );
}

/**
 * Write an array of custom dimensions to the Custom Dimension - Modify Sheet.
 */
function writeTemplateCustomDimensionsToSheet() {
  writeTemplateCustomDefinitionsToSheet(
    sheetNames.ua.modifyCds,
    sheetRanges.ua.modifyCdsTemplateProperty,
    sheetRanges.ua.modifyCdsTemplateDimensions,
    'custom dimensions'
  );
}

/**
 * Modify custom dimensions for the selected destination properties.
 */
function modifyCustomDimensions() {
  modifyUACustomDefinitions(sheetNames.ua.modifyCds, sheetRanges.ua.modifyCdsTemplateDimensions,
  sheetRanges.ua.modifyCdsDestinationProperties, sheetRanges.ua.modifyCdsSettings, 'custom dimensions');
}

/**
 * Write an array of all properties to the sheet Custom Metrics - Modify sheet.
 */
function writeCustomMetricDestinationPropertiesToSheet() {
  writeDestinationPropertiesToSheet(
    sheetNames.ua.modifyCms,
    sheetRanges.ua.modifyCmsDestinationProperties
  );
}

/**
 * Write an array of custom metrics to the Custom Metrics - Modify Sheet.
 */
function writeTemplateCustomMetricsToSheet() {
  writeTemplateCustomDefinitionsToSheet(
    sheetNames.ua.modifyCms,
    sheetRanges.ua.modifyCmsTemplateProperty,
    sheetRanges.ua.modifyCmsTemplateMetrics,
    'custom metrics'
  );
}

/**
 * Modify custom metrics for the selected destination properties.
 */
function modifyCustomMetrics() {
  modifyUACustomDefinitions(sheetNames.ua.modifyCms, sheetRanges.ua.modifyCmsTemplateMetrics,
  sheetRanges.ua.modifyCmsDestinationProperties, sheetRanges.ua.modifyCmsSettings, 'custom metrics');
}<commit_msg>[bug] - UA Custom Definitions Bug<commit_after>/**
 * Write an array of all properties to the sheet.
 * @param {string} sheetName The name of the sheet where the data will
 * be written.
 * @param {string} rangeName The range for the given sheet were the data
 * will be written.
 */
function writeDestinationPropertiesToSheet(sheetName, rangeName) {
  const allProperties = getAllProperties();
  allProperties.forEach(property => property.push(false));
  const range = ss.getSheetByName(sheetName).getRange(
    rangeName.write.row,
    rangeName.write.column,
    allProperties.length,
    rangeName.write.numColumns
  );
  range.setValues(allProperties);
}

/**
 * Either creates new or updates existing custom definitions for selected
 * Universal Analytics properties.
 * @param {string} sheetName The name of the sheet where the information exists.
 * @param {!Object} templateValuesRange The range of the template custom definitions
 * on the sheet.
 * @param {!Object} destinationPropertyRange The range of the destination properties
 * on the sheet.
 * @param {!Object} settingsRange The range for the settings on the sheet.
 * @param {string} type Either custom dimensions or custom metrics.
 */
function modifyUACustomDefinitions(
  sheetName, templateValuesRange, destinationPropertyRange, settingsRange, type) {
  const modifyCustomDefinitionSheet = ss.getSheetByName(sheetName);
  let selectedDestinationProperties = modifyCustomDefinitionSheet.getRange(
    destinationPropertyRange.read.row,
    destinationPropertyRange.read.column,
    modifyCustomDefinitionSheet.getLastRow(),
    destinationPropertyRange.read.numColumns
  ).getValues();
  selectedDestinationProperties = selectedDestinationProperties.filter(row => row[5] == true);
  let templateValues = modifyCustomDefinitionSheet.getRange(
    templateValuesRange.read.row,
    templateValuesRange.read.column,
    modifyCustomDefinitionSheet.getLastRow(),
    templateValuesRange.read.numColumns
  ).getValues();
  templateValues = templateValues.filter(row => row[0] != '');
  const modifySettings = modifyCustomDefinitionSheet.getRange(
    settingsRange.read.row,
    settingsRange.read.column,
    settingsRange.read.numRows,
    settingsRange.read.numColumns
  ).getValues();
  const overwriteExisting = modifySettings[0][0];
  if (templateValues.length > 0 && selectedDestinationProperties.length > 0) {
    selectedDestinationProperties.forEach(property => {
      const existingDestinationValues = getCustomDimensions(property[1], property[3]);
      for (let i = 0; i < templateValues.length; i++) {
        if (!property[5] && i > 19) {
          break;
        }
        const templateValue = templateValues[i];
        const existingValue = existingDestinationValues[i];
        const templateRequest = {
          accountId: property[1],
          propertyId: property[3],
          index: templateValue[0],
          body: {
            name: templateValue[1],
            scope: templateValue[2],
            active: templateValue[3]
          }
        };
        let placeholderName = modifySettings[1][0] || 'Placeholder';
        let placeholderScope = modifySettings[2][0] || 'HIT';
        let placeholderActive = modifySettings[3][0] || false;
        const placeholderRequest = {
          accountId: property[1],
          propertyId: property[3],
          index: templateValue[0],
          body: {
            name:  placeholderName + ' ' + templateValue[0],
            scope: placeholderScope,
            active: placeholderActive
          }
        };
        if (type == 'custom metrics') {
          templateRequest.body.minValue = templateValue[4];
          templateRequest.body.maxValue = templateValue[5];
          templateRequest.body.type = templateValue[6];
          placeholderRequest.body.minValue = modifySettings[4][0];
          placeholderRequest.body.maxValue = modifySettings[5][0];
          placeholderRequest.body.type = modifySettings[6][0] || 'INTEGER';
        }
        if (existingValue != undefined) {
          if (templateValue[templateValue.length - 1]) {
            if (overwriteExisting) {
              if (templateValue[1] != existingValue.name ||
              templateValue[2] != existingValue.scope ||
              templateValue[3] != existingValue.active) {
                let response = null;
                let resultsSheetName = '';
                let resultsRange = {};
                if (type == 'custom dimensions') {
                  response = updateCustomDimension(templateRequest);
                  resultsSheetName = sheetNames.ua.modifyCdsResults;
                  resultsRange = sheetRanges.ua.modifyCdsResults;
                } else if (type == 'custom metrics' &&
                templateValue[4] != existingValue.min_value &&
                templateValue[5] != existingValue.max_value &&
                templateValue[6] != existingValue.type) {
                  response = updateCustomMetric(templateRequest);
                  resultsSheetName = sheetNames.ua.modifyCmsResults;
                  resultsRange = sheetRanges.ua.modifyCmsResults;
                }
                writeUACustomDefinitionModificationToSheet(
                  type, response, property[1], property[3], 'created',
                  resultsSheetName, resultsRange);
                Utilities.sleep(750);
              }
            }
          }
        } else {
          if (templateValue[templateValue.length - 1]) {
            let response = null;
            let resultsSheetName = '';
            let resultsRange = {};
            if (type == 'custom dimensions') {
              response = createCustomDimension(templateRequest);
              resultsSheetName = sheetNames.ua.modifyCdsResults;
              resultsRange = sheetRanges.ua.modifyCdsResults;
            } else if (type == 'custom metrics') {
              response = createCustomMetric(templateRequest);
              resultsSheetName = sheetNames.ua.modifyCmsResults;
              resultsRange = sheetRanges.ua.modifyCmsResults;
            }
            writeUACustomDefinitionModificationToSheet(
              type, response, property[1], property[3], 'created',
              resultsSheetName, resultsRange);
            Utilities.sleep(750);
          } else {
            let response = null;
            let resultsSheetName = '';
            let resultsRange = {};
            if (type == 'custom dimensions') {
              response = createCustomDimension(placeholderRequest);
              resultsSheetName = sheetNames.ua.modifyCdsResults;
              resultsRange = sheetRanges.ua.modifyCdsResults;
            } else if (type == 'custom metrics') {
              response = createCustomMetric(placeholderRequest);
              resultsSheetName = sheetNames.ua.modifyCmsResults;
              resultsRange = sheetRanges.ua.modifyCmsResults;
            }
            writeUACustomDefinitionModificationToSheet(
              type, response, property[1], property[3], 'created',
              resultsSheetName, resultsRange);
            Utilities.sleep(750);
          }
        }
      }
    });
  }
}

/**
 * Write template property custom dimensions to sheet.
 * @param {string} sheetName
 * @param {!Object} templatePropertyRange
 * @param {!Object} templateValuesRange
 * @param {string} type
 */
function writeTemplateCustomDefinitionsToSheet(
  sheetName, templatePropertyRange, templateValuesRange, type) {
  const sheet = ss.getSheetByName(sheetName);
  // Get template IDs from the sheet.
  const ids = sheet.getRange(
    templatePropertyRange.read.row,
    templatePropertyRange.read.column,
    templatePropertyRange.read.numRows,
    templatePropertyRange.read.numColumns
  ).getValues();
  // Get the template property custom dimensions.
  let definitions = null;
  if (type == 'custom dimensions') {
    definitions = listCustomDimensions(ids[0][1], ids[0][3]);
  } else if (type == 'custom metrics') {
    definitions = listCustomMetrics(ids[0][1], ids[0][3]);
  }
  if (definitions.length > 0) {
    // Remove the account ID and property ID for each definition.
    definitions.forEach(definition => {
      definition.shift();
      definition.shift();
    });
    const range = sheet.getRange(
      templateValuesRange.write.row,
      templateValuesRange.write.column,
      definitions.length,
      templateValuesRange.write.numColumns
    );
    range.setValues(definitions);
  }
}

/**
 * Write the results of modifying a UA custom dimension or metric to a sheet.
 * @param {string} type Either custom dimensions or custom metrics.
 * @param {!Object} values The UA custom metric or dimension after it has been modified.
 * @param {number} accountId The account ID for the custom metric or dimension.
 * @param {string} propertyId The property ID for the custom metric or dimension.
 * @param {string} actionTaken The action taken on the custom metric or dimension.
 * @param {string} sheetName The sheet name where the results will be written.
 * @param {!Object} sheetRange The range where the results will be written.
 */
function writeUACustomDefinitionModificationToSheet(
  type, values, accountId, propertyId, actionTaken, sheetName, sheetRange) {
  const result = [];
  const date = new Date();
  if (type == 'custom dimensions') {
    result.push([
      accountId, propertyId,
      values.index, values.name, values.scope, values.active,
      actionTaken, date
    ]);
  } else if (type == 'custom metrics') {
    result.push([
      accountId, propertyId,
      values.index, values.name, values.scope, values.active,
      values.min_value, values.max_value, values.type,
      actionTaken, date
    ]);
  }
  ss.getSheetByName(sheetName).getRange(
    ss.getSheetByName(sheetName).getLastRow() + 1,
    sheetRange.write.column, 1,
    sheetRange.write.numColumns).setValues(result);
}

/**
 * Write an array of all properties to the sheet Custom Dimension - Modify sheet.
 */
function writeCustomDimensionDestinationPropertiesToSheet() {
  writeDestinationPropertiesToSheet(
    sheetNames.ua.modifyCds,
    sheetRanges.ua.modifyCdsDestinationProperties
  );
}

/**
 * Write an array of custom dimensions to the Custom Dimension - Modify Sheet.
 */
function writeTemplateCustomDimensionsToSheet() {
  writeTemplateCustomDefinitionsToSheet(
    sheetNames.ua.modifyCds,
    sheetRanges.ua.modifyCdsTemplateProperty,
    sheetRanges.ua.modifyCdsTemplateDimensions,
    'custom dimensions'
  );
}

/**
 * Modify custom dimensions for the selected destination properties.
 */
function modifyCustomDimensions() {
  modifyUACustomDefinitions(sheetNames.ua.modifyCds, sheetRanges.ua.modifyCdsTemplateDimensions,
  sheetRanges.ua.modifyCdsDestinationProperties, sheetRanges.ua.modifyCdsSettings, 'custom dimensions');
}

/**
 * Write an array of all properties to the sheet Custom Metrics - Modify sheet.
 */
function writeCustomMetricDestinationPropertiesToSheet() {
  writeDestinationPropertiesToSheet(
    sheetNames.ua.modifyCms,
    sheetRanges.ua.modifyCmsDestinationProperties
  );
}

/**
 * Write an array of custom metrics to the Custom Metrics - Modify Sheet.
 */
function writeTemplateCustomMetricsToSheet() {
  writeTemplateCustomDefinitionsToSheet(
    sheetNames.ua.modifyCms,
    sheetRanges.ua.modifyCmsTemplateProperty,
    sheetRanges.ua.modifyCmsTemplateMetrics,
    'custom metrics'
  );
}

/**
 * Modify custom metrics for the selected destination properties.
 */
function modifyCustomMetrics() {
  modifyUACustomDefinitions(sheetNames.ua.modifyCms, sheetRanges.ua.modifyCmsTemplateMetrics,
  sheetRanges.ua.modifyCmsDestinationProperties, sheetRanges.ua.modifyCmsSettings, 'custom metrics');
}<|endoftext|>