<commit_before>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 * @flow
 */

'use strict';

const DeprecatedViewPropTypes = require('DeprecatedViewPropTypes');
const PropTypes = require('prop-types');
const React = require('React');
const ReactNative = require('ReactNative');
const UIManager = require('UIManager');

const dismissKeyboard = require('dismissKeyboard');
const requireNativeComponent = require('requireNativeComponent');

const NativeAndroidViewPager = requireNativeComponent('AndroidViewPager');

const VIEWPAGER_REF = 'viewPager';

type Event = Object;

export type ViewPagerScrollState = $Enum<{
  idle: string,
  dragging: string,
  settling: string,
}>;

/**
 * Container that allows to flip left and right between child views. Each
 * child view of the `ViewPagerAndroid` will be treated as a separate page
 * and will be stretched to fill the `ViewPagerAndroid`.
 *
 * It is important all children are `<View>`s and not composite components.
 * You can set style properties like `padding` or `backgroundColor` for each
 * child. It is also important that each child have a `key` prop.
 *
 * Example:
 *
 * ```
 * render: function() {
 *   return (
 *     <ViewPagerAndroid
 *       style={styles.viewPager}
 *       initialPage={0}>
 *       <View style={styles.pageStyle} key="1">
 *         <Text>First page</Text>
 *       </View>
 *       <View style={styles.pageStyle} key="2">
 *         <Text>Second page</Text>
 *       </View>
 *     </ViewPagerAndroid>
 *   );
 * }
 *
 * ...
 *
 * var styles = {
 *   ...
 *   viewPager: {
 *     flex: 1
 *   },
 *   pageStyle: {
 *     alignItems: 'center',
 *     padding: 20,
 *   }
 * }
 * ```
 */
class ViewPagerAndroid extends React.Component<{
  initialPage?: number,
  onPageScroll?: Function,
  onPageScrollStateChanged?: Function,
  onPageSelected?: Function,
  pageMargin?: number,
  peekEnabled?: boolean,
  keyboardDismissMode?: 'none' | 'on-drag',
  scrollEnabled?: boolean,
}> {
  /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
   * when making Flow check .android.js files. */
  static propTypes = {
    ...DeprecatedViewPropTypes,
    /**
     * Index of initial page that should be selected. Use `setPage` method to
     * update the page, and `onPageSelected` to monitor page changes
     */
    initialPage: PropTypes.number,

    /**
     * Executed when transitioning between pages (ether because of animation for
     * the requested page change or when user is swiping/dragging between pages)
     * The `event.nativeEvent` object for this callback will carry following data:
     *  - position - index of first page from the left that is currently visible
     *  - offset - value from range [0,1) describing stage between page transitions.
     *    Value x means that (1 - x) fraction of the page at "position" index is
     *    visible, and x fraction of the next page is visible.
     */
    onPageScroll: PropTypes.func,

    /**
     * Function called when the page scrolling state has changed.
     * The page scrolling state can be in 3 states:
     * - idle, meaning there is no interaction with the page scroller happening at the time
     * - dragging, meaning there is currently an interaction with the page scroller
     * - settling, meaning that there was an interaction with the page scroller, and the
     *   page scroller is now finishing it's closing or opening animation
     */
    onPageScrollStateChanged: PropTypes.func,

    /**
     * This callback will be called once ViewPager finish navigating to selected page
     * (when user swipes between pages). The `event.nativeEvent` object passed to this
     * callback will have following fields:
     *  - position - index of page that has been selected
     */
    onPageSelected: PropTypes.func,

    /**
     * Blank space to show between pages. This is only visible while scrolling, pages are still
     * edge-to-edge.
     */
    pageMargin: PropTypes.number,

    /**
     * Determines whether the keyboard gets dismissed in response to a drag.
     *   - 'none' (the default), drags do not dismiss the keyboard.
     *   - 'on-drag', the keyboard is dismissed when a drag begins.
     */
    keyboardDismissMode: PropTypes.oneOf([
      'none', // default
      'on-drag',
    ]),

    /**
     * When false, the content does not scroll.
     * The default value is true.
     */
    scrollEnabled: PropTypes.bool,

    /**
     * Whether enable showing peekFraction or not. If this is true, the preview of
     * last and next page will show in current screen. Defaults to false.
     */
    peekEnabled: PropTypes.bool,
  };

  componentDidMount() {
    if (this.props.initialPage != null) {
      this.setPageWithoutAnimation(this.props.initialPage);
    }
  }

  /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
   * when making Flow check .android.js files. */
  getInnerViewNode = (): ReactComponent => {
    return this.refs[VIEWPAGER_REF].getInnerViewNode();
  };

  /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
   * when making Flow check .android.js files. */
  _childrenWithOverridenStyle = (): Array => {
    // Override styles so that each page will fill the parent. Native component
    // will handle positioning of elements, so it's not important to offset
    // them correctly.
    /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
     * when making Flow check .android.js files. */
    return React.Children.map(this.props.children, function(child) {
      if (!child) {
        return null;
      }
      const newProps = {
        ...child.props,
        style: [
          child.props.style,
          {
            position: 'absolute',
            left: 0,
            top: 0,
            right: 0,
            bottom: 0,
            width: undefined,
            height: undefined,
          },
        ],
        collapsable: false,
      };
      if (
        child.type &&
        child.type.displayName &&
        child.type.displayName !== 'RCTView' &&
        child.type.displayName !== 'View'
      ) {
        console.warn(
          'Each ViewPager child must be a <View>. Was ' +
            child.type.displayName,
        );
      }
      return React.createElement(child.type, newProps);
    });
  };

  _onPageScroll = (e: Event) => {
    if (this.props.onPageScroll) {
      this.props.onPageScroll(e);
    }
    if (this.props.keyboardDismissMode === 'on-drag') {
      dismissKeyboard();
    }
  };

  _onPageScrollStateChanged = (e: Event) => {
    if (this.props.onPageScrollStateChanged) {
      this.props.onPageScrollStateChanged(e.nativeEvent.pageScrollState);
    }
  };

  _onPageSelected = (e: Event) => {
    if (this.props.onPageSelected) {
      this.props.onPageSelected(e);
    }
  };

  /**
   * A helper function to scroll to a specific page in the ViewPager.
   * The transition between pages will be animated.
   */
  setPage = (selectedPage: number) => {
    UIManager.dispatchViewManagerCommand(
      ReactNative.findNodeHandle(this),
      UIManager.getViewManagerConfig('AndroidViewPager').Commands.setPage,
      [selectedPage],
    );
  };

  /**
   * A helper function to scroll to a specific page in the ViewPager.
   * The transition between pages will *not* be animated.
   */
  setPageWithoutAnimation = (selectedPage: number) => {
    UIManager.dispatchViewManagerCommand(
      ReactNative.findNodeHandle(this),
      UIManager.getViewManagerConfig('AndroidViewPager').Commands
        .setPageWithoutAnimation,
      [selectedPage],
    );
  };

  render() {
    return (
      <NativeAndroidViewPager
        {...this.props}
        ref={VIEWPAGER_REF}
        /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was
         * found when making Flow check .android.js files. */
        style={this.props.style}
        onPageScroll={this._onPageScroll}
        onPageScrollStateChanged={this._onPageScrollStateChanged}
        onPageSelected={this._onPageSelected}
        children={this._childrenWithOverridenStyle()}
      />
    );
  }
}

module.exports = ViewPagerAndroid;
<commit_msg>Remove PropTypes from ViewerPagerAndroid.android.js (#21347)<commit_after>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 * @flow
 */

'use strict';

const React = require('React');
const ReactNative = require('ReactNative');
const UIManager = require('UIManager');

const dismissKeyboard = require('dismissKeyboard');
const requireNativeComponent = require('requireNativeComponent');

const NativeAndroidViewPager = requireNativeComponent('AndroidViewPager');

import type {ViewStyleProp} from 'StyleSheet';

const VIEWPAGER_REF = 'viewPager';

type Event = Object;

export type ViewPagerScrollState = $Enum<{
  idle: string,
  dragging: string,
  settling: string,
}>;

type Props = $ReadOnly<{|
  /**
   * Index of initial page that should be selected. Use `setPage` method to
   * update the page, and `onPageSelected` to monitor page changes
   */
  initialPage?: ?number,

  /**
   * Executed when transitioning between pages (ether because of animation for
   * the requested page change or when user is swiping/dragging between pages)
   * The `event.nativeEvent` object for this callback will carry following data:
   *  - position - index of first page from the left that is currently visible
   *  - offset - value from range [0,1) describing stage between page transitions.
   *    Value x means that (1 - x) fraction of the page at "position" index is
   *    visible, and x fraction of the next page is visible.
   */
  onPageScroll?: ?Function,

  /**
   * Function called when the page scrolling state has changed.
   * The page scrolling state can be in 3 states:
   * - idle, meaning there is no interaction with the page scroller happening at the time
   * - dragging, meaning there is currently an interaction with the page scroller
   * - settling, meaning that there was an interaction with the page scroller, and the
   *   page scroller is now finishing it's closing or opening animation
   */
  onPageScrollStateChanged?: ?Function,

  /**
   * This callback will be called once ViewPager finish navigating to selected page
   * (when user swipes between pages). The `event.nativeEvent` object passed to this
   * callback will have following fields:
   *  - position - index of page that has been selected
   */
  onPageSelected?: ?Function,

  /**
   * Blank space to show between pages. This is only visible while scrolling, pages are still
   * edge-to-edge.
   */
  pageMargin?: ?number,

  /**
   * Whether enable showing peekFraction or not. If this is true, the preview of
   * last and next page will show in current screen. Defaults to false.
   */

  peekEnabled?: ?boolean,

  /**
   * Determines whether the keyboard gets dismissed in response to a drag.
   *   - 'none' (the default), drags do not dismiss the keyboard.
   *   - 'on-drag', the keyboard is dismissed when a drag begins.
   */
  keyboardDismissMode?: ?('none' | 'on-drag'),

  /**
   * When false, the content does not scroll.
   * The default value is true.
   */
  scrollEnabled?: ?boolean,

  children?: React.Node,

  style?: ?ViewStyleProp,
|}>;

/**
 * Container that allows to flip left and right between child views. Each
 * child view of the `ViewPagerAndroid` will be treated as a separate page
 * and will be stretched to fill the `ViewPagerAndroid`.
 *
 * It is important all children are `<View>`s and not composite components.
 * You can set style properties like `padding` or `backgroundColor` for each
 * child. It is also important that each child have a `key` prop.
 *
 * Example:
 *
 * ```
 * render: function() {
 *   return (
 *     <ViewPagerAndroid
 *       style={styles.viewPager}
 *       initialPage={0}>
 *       <View style={styles.pageStyle} key="1">
 *         <Text>First page</Text>
 *       </View>
 *       <View style={styles.pageStyle} key="2">
 *         <Text>Second page</Text>
 *       </View>
 *     </ViewPagerAndroid>
 *   );
 * }
 *
 * ...
 *
 * var styles = {
 *   ...
 *   viewPager: {
 *     flex: 1
 *   },
 *   pageStyle: {
 *     alignItems: 'center',
 *     padding: 20,
 *   }
 * }
 * ```
 */

class ViewPagerAndroid extends React.Component<Props> {
  componentDidMount() {
    if (this.props.initialPage != null) {
      this.setPageWithoutAnimation(this.props.initialPage);
    }
  }

  /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
   * when making Flow check .android.js files. */
  getInnerViewNode = (): ReactComponent => {
    return this.refs[VIEWPAGER_REF].getInnerViewNode();
  };

  /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
   * when making Flow check .android.js files. */
  _childrenWithOverridenStyle = (): Array => {
    // Override styles so that each page will fill the parent. Native component
    // will handle positioning of elements, so it's not important to offset
    // them correctly.
    return React.Children.map(this.props.children, function(child) {
      if (!child) {
        return null;
      }
      const newProps = {
        ...child.props,
        style: [
          child.props.style,
          {
            position: 'absolute',
            left: 0,
            top: 0,
            right: 0,
            bottom: 0,
            width: undefined,
            height: undefined,
          },
        ],
        collapsable: false,
      };
      if (
        child.type &&
        child.type.displayName &&
        child.type.displayName !== 'RCTView' &&
        child.type.displayName !== 'View'
      ) {
        console.warn(
          'Each ViewPager child must be a <View>. Was ' +
            child.type.displayName,
        );
      }
      return React.createElement(child.type, newProps);
    });
  };

  _onPageScroll = (e: Event) => {
    if (this.props.onPageScroll) {
      this.props.onPageScroll(e);
    }
    if (this.props.keyboardDismissMode === 'on-drag') {
      dismissKeyboard();
    }
  };

  _onPageScrollStateChanged = (e: Event) => {
    if (this.props.onPageScrollStateChanged) {
      this.props.onPageScrollStateChanged(e.nativeEvent.pageScrollState);
    }
  };

  _onPageSelected = (e: Event) => {
    if (this.props.onPageSelected) {
      this.props.onPageSelected(e);
    }
  };

  /**
   * A helper function to scroll to a specific page in the ViewPager.
   * The transition between pages will be animated.
   */
  setPage = (selectedPage: number) => {
    UIManager.dispatchViewManagerCommand(
      ReactNative.findNodeHandle(this),
      UIManager.getViewManagerConfig('AndroidViewPager').Commands.setPage,
      [selectedPage],
    );
  };

  /**
   * A helper function to scroll to a specific page in the ViewPager.
   * The transition between pages will *not* be animated.
   */
  setPageWithoutAnimation = (selectedPage: number) => {
    UIManager.dispatchViewManagerCommand(
      ReactNative.findNodeHandle(this),
      UIManager.getViewManagerConfig('AndroidViewPager').Commands
        .setPageWithoutAnimation,
      [selectedPage],
    );
  };

  render() {
    return (
      <NativeAndroidViewPager
        {...this.props}
        ref={VIEWPAGER_REF}
        style={this.props.style}
        onPageScroll={this._onPageScroll}
        onPageScrollStateChanged={this._onPageScrollStateChanged}
        onPageSelected={this._onPageSelected}
        children={this._childrenWithOverridenStyle()}
      />
    );
  }
}

module.exports = ViewPagerAndroid;
<|endoftext|>


<commit_before>function is_valid_auth(xml)
{
    errcode = xml.getElementsByTagName("error_num");
    if(errcode.length == 0)
    {
        //No errors, return 0 and authenificator
        return {err_code:0, msg:xml.getElementsByTagName("authenticator")[0].childNodes[0].nodeValue}
    }
    else
    {
        //Error occurred, return error code and error message
        return {err_code:xml.getElementsByTagName("error_num")[0].childNodes[0].nodeValue, msg:xml.getElementsByTagName("error_msg")[0].childNodes[0].nodeValue}
    }
}
<commit_msg>performed a whitespace fix in xml_parse.js<commit_after>function is_valid_auth(xml)
{
    errcode = xml.getElementsByTagName("error_num");
    if(errcode.length == 0)
    {
        //No errors, return 0 and authenificator
        return {err_code:0, msg:xml.getElementsByTagName("authenticator")[0].childNodes[0].nodeValue}
    }
    else
    {
        //Error occurred, return error code and error message
        return {err_code:xml.getElementsByTagName("error_num")[0].childNodes[0].nodeValue,
                msg:xml.getElementsByTagName("error_msg")[0].childNodes[0].nodeValue}
    }
}
<|endoftext|>


<commit_before>import { getInstance } from '../utils.js'
import { sendAndReactToTransaction } from './transActions.js'
import { Stage, LoadingStage } from '../constants.js'
export const RECEIVE_ASSESSMENT = 'RECEIVE_ASSESSMENT'
export const RECEIVE_FINALSCORE = 'RECEIVE_FINALSCORE'
export const RECEIVE_STORED_DATA = 'RECEIVE_STORED_DATA'
export const RECEIVE_PAYOUTS = 'RECEIVE_PAYOUTS'
export const RECEIVE_ASSESSMENTSTAGE = 'RECEIVE_ASSESSMENTSTAGE'
export const REMOVE_ASSESSMENT = 'REMOVE_ASSESSMENT'
export const RECEIVE_ASSESSORS = 'RECEIVE_ASSESSORS'
export const BEGIN_LOADING_ASSESSMENTS = 'BEGIN_LOADING_ASSESSMENTS'
export const END_LOADING_ASSESSMENTS = 'END_LOADING_ASSESSMENTS'
export const SET_ASSESSMENT = 'SET_ASSESSMENT'
export const BEGIN_LOADING_DETAIL = 'BEGIN_LOADING_DETAIL'
export const END_LOADING_DETAIL = 'END_LOADING_DETAIL'
export const RESET_LOADED_DETAILS = 'RESET_LOADED_DETAILS'

const ethereumjsABI = require('ethereumjs-abi')

export function hashScoreAndSalt (_score, _salt) {
  return '0x' + ethereumjsABI.soliditySHA3(
    ['int128', 'string'],
    [_score, _salt]
  ).toString('hex')
}

// ============== async actions ===================

export function confirmAssessor (address) {
  return async (dispatch, getState) => {
    let userAddress = getState().ethereum.userAddress
    let assessmentInstance = getInstance.assessment(getState(), address)
    // also salt should be saved in state => I put the saing part in the assessorStatus component
    sendAndReactToTransaction(
      dispatch,
      {method: assessmentInstance.methods.confirmAssessor, args: []},
      Stage.Called,
      userAddress,
      address
    )
  }
}

export function commit (address, score, salt) {
  return async (dispatch, getState) => {
    let userAddress = getState().ethereum.userAddress
    let assessmentInstance = getInstance.assessment(getState(), address)
    sendAndReactToTransaction(
      dispatch,
      {method: assessmentInstance.methods.commit, args: [hashScoreAndSalt(score, salt)]},
      Stage.Confirmed,
      userAddress,
      address
    )
  }
}

export function reveal (address, score, salt) {
  return async (dispatch, getState) => {
    let userAddress = getState().ethereum.userAddress
    let assessmentInstance = getInstance.assessment(getState(), address)
    sendAndReactToTransaction(
      dispatch,
      {method: assessmentInstance.methods.reveal, args: [score, salt]},
      Stage.Committed,
      userAddress,
      address
    )
  }
}

export function storeData (address, data) {
  return async (dispatch, getState) => {
    dispatch(storeDataOnAssessment(address, data))
  }
}

export function storeDataOnAssessment (address, data) {
  return async (dispatch, getState) => {
    let userAddress = getState().ethereum.userAddress
    let assessmentInstance = getInstance.assessment(getState(), address)
    // also salt should be saved in state
    let dataAsBytes = getState().ethereum.web3.utils.utf8ToHex(data)
    sendAndReactToTransaction(
      dispatch,
      {method: assessmentInstance.methods.addData, args: [dataAsBytes]},
      'meetingPointChange',
      userAddress,
      address
      // either put back fetchStoredData that was deprecated in favor of fetchAssessmentData, or use fetchAssessmentData
      // {method: fetchStoredData, args: [address]}
    )
  }
}

// fetch assessment data for one given assessment
// if that assessment is already in state, it only fetches what could have changed (stage)
export function fetchAssessmentData (assessmentAddress) {
  return async (dispatch, getState) => {
    let userAddress = getState().ethereum.userAddress
    let address = assessmentAddress || getState().assessments.selectedAssessment
    if (getState().assessments[address]) {
      let assessmentInstance = getInstance.assessment(getState(), address)
      let stage = Number(await assessmentInstance.methods.assessmentStage().call())
      if (stage !== getState().assessments[address].stage) {
        dispatch(receiveAssessmentStage(address, stage))
      }
      // mark info as loaded
      dispatch(endLoadingDetail('info'))
    } else {
      dispatch(beginLoadingDetail('info'))
      try {
        let assessmentInstance = getInstance.assessment(getState(), address)

        // get assessment infos
        let cost = await assessmentInstance.methods.cost().call()
        let endTime = await assessmentInstance.methods.endTime().call()
        // checkpoint -> keeps track of timelimits for 1) latest possible time to confirm and 2) earliest time to reveal
        let checkpoint = await assessmentInstance.methods.checkpoint().call()
        let size = await assessmentInstance.methods.size().call()
        let stage = Number(await assessmentInstance.methods.assessmentStage().call())
        let finalScore = Number(await assessmentInstance.methods.finalScore().call())
        let userStage = Number(await assessmentInstance.methods.assessorState(userAddress).call())
        let assessee = await assessmentInstance.methods.assessee().call()
        let conceptAddress = await assessmentInstance.methods.concept().call()

        // get the data (meeting point) and convert it from bytes32 to string
        let data = 'no meeting point set'
        let bytesData = await assessmentInstance.methods.data(assessee).call()
        if (bytesData) {
          data = getState().ethereum.web3.utils.hexToUtf8(bytesData)
        }

        // get conceptRegistry instance to verify assessment/concept/conceptRegistry link authenticity
        let conceptRegistryInstance = getInstance.conceptRegistry(getState())
        let isValidConcept = await conceptRegistryInstance.methods.conceptExists(conceptAddress).call()

        // check if assessment is from concept
        let conceptInstance = getInstance.concept(getState(), conceptAddress)
        let isValidAssessment = await conceptInstance.methods.assessmentExists(address).call()

        // if concept is from Registry and assessment is from concept,
        // go ahead and fetch data, otherwise, add an invalid assessment object
        if (isValidConcept && isValidAssessment) {
          // get data from associated concept
          let conceptInstance = getInstance.concept(getState(), conceptAddress)
          let conceptData = await conceptInstance.methods.data().call()
          if (conceptData) {
            conceptData = Buffer.from(conceptData.slice(2), 'hex').toString('utf8')
          } else {
            conceptData = ''
            console.log('was undefined: conceptData ', conceptData)
          }
          dispatch(receiveAssessment({
            address,
            cost,
            checkpoint,
            endTime,
            size,
            assessee,
            userStage,
            stage,
            finalScore,
            conceptAddress,
            conceptData,
            data,
            valid: true
          }))
        } else {
          // if the concept is not linked to concept Registry
          dispatch(receiveAssessment({
            address: address,
            valid: false
          }))
        }
      } catch (e) {
        console.log('reading assessment-data from the chain did not work for assessment: ', address, e)
        // In case of error, we assume the assessment address is invalid
        // conceptData will be used to detect wrong address situation (but could be any other field)
      }
      dispatch(endLoadingDetail('info'))
    }
  }
}

export function fetchScoreAndPayout (address) {
  return async (dispatch, getState) => {
    try {
      let assessmentInstance = getInstance.assessment(getState(), address)
      let finalScore = await assessmentInstance.methods.finalScore().call()

      dispatch(receiveFinalScore({
        address,
        finalScore
      }))
    } catch (e) {
      console.log('reading assessment-data from the chain did not work for assessment: ', address, e)
    }
  }
}

// export function updateAssessment (address) {
//   return async (dispatch, getState) => {
//   }
// }

// reads all staked assessors from event-logs and reads their stage from the chain
// if the assessment is in the calling phase one also checks whether the user has been called
// and if, so he will be added to the list of assessors with his stage set to 1
export function fetchAssessors (selectedAssessment) {
  return async (dispatch, getState) => {
    try {
      let address = selectedAssessment || getState().assessments.selectedAssessment
      dispatch(beginLoadingDetail('assessors'))
      // reading assessors from events
      const fathomTokenInstance = getInstance.fathomToken(getState())
      // NOTE: this piece is a bit tricky, as filtering in the call usually works on the local testnet, but not on rinkeby
      // for rinkeby one has to get all events and filter locally
      let pastEvents = await fathomTokenInstance.getPastEvents({fromBlock: 0, toBlock: 'latest'})
      if (pastEvents.length === []) {
        console.log('Oddly no Notifications events have been found. Try switching Metamasks network back and forth')
      }
      let assessors = []
      pastEvents.filter(
        e =>
          e.event === 'Notification' &&
          e.returnValues['sender'] === address &&
          e.returnValues['topic'] === '2' &&
          assessors.push(e.returnValues['user'])
      )
      let stage = Number(getState().assessments[address].stage)
      dispatch(fetchAssessorStages(address, assessors, Number(stage) === Stage.Called))
      if (stage === Stage.Done) {
        dispatch(fetchAllPayouts(address))
      }
    } catch (e) {
      console.log('ERROR: fetching assessors from the events did not work!', e)
    }
  }
}

// reads all transfers an assessments to users from event-logs
export function fetchAllPayouts (address) {
  return async (dispatch, getState) => {
    dispatch(beginLoadingDetail('payouts'))
    try {
      // reading assessors-payouts from events
      const fathomTokenInstance = getInstance.fathomToken(getState())
      // NOTE: this piece is a bit tricky, as filtering in the call usually works on the local testnet, but not on rinkeby
      // for rinkeby one has to get all events and filter locally
      let pastEvents = await fathomTokenInstance.getPastEvents({fromBlock: 0, toBlock: 'latest'})
      if (pastEvents.length === []) {
        console.log('Oddly no Notifications events have been found. Try switching Metamasks network back and forth')
      }
      let payouts = {}
      pastEvents.filter(
        e =>
          e.event === 'Transfer' &&
          e.returnValues['_from'] === address &&
          (payouts[e.returnValues['_to']] = e.returnValues['_value'])
      )
      dispatch(receivePayouts(address, payouts))
    } catch (e) {
      console.log('ERROR: fetching payouts from the events did not work!', e)
    }
    dispatch(endLoadingDetail('payouts'))
  }
}

// let assessors = getState().assessments[address].assessors || []
// let data = {}
// for (let i = 0; i < assessors.length; i++) {
// data[assessors[i]] = await assessmentInstance.methods.data(assessors[i]).call()
// }

export function fetchAssessorStages (address, assessors, checkUserAddress = false) {
  return async (dispatch, getState) => {
    let assessmentInstance = getInstance.assessment(getState(), address)
    let assessorStages = []
    for (let i = 0; i < assessors.length; i++) {
      let stage = await assessmentInstance.methods.assessorState(assessors[i]).call()
      assessorStages.push({address: assessors[i], stage: stage})
    }
    if (checkUserAddress) {
      let userAddress = getState().ethereum.userAddress
      let userStage = Number(await assessmentInstance.methods.assessorState(userAddress).call())
      if (userStage === Stage.Called) {
        assessorStages.push({address: userAddress, stage: userStage})
      }
    }
    dispatch(receiveAssessors(address, assessorStages))
    dispatch(endLoadingDetail('assessors'))
  }
}

// part of fetchAssessmentData now

// returns the strings that are stored on the assessments
// for now, only the data stored by the assessee

// export function fetchStoredData (selectedAssessment) {
//   console.log('fetchStoredData', selectedAssessment)
//   return async (dispatch, getState) => {
//     dispatch(beginLoadingDetail('attachments'))
//     let address = selectedAssessment || getState().assessments.selectedAssessment
//     let assessmentInstance = getInstance.assessment(getState(), address)
//     let assessee = await assessmentInstance.methods.assessee().call()
//     let data = await assessmentInstance.methods.data(assessee).call()
//     dispatch(receiveStoredData(address, data))
//     dispatch(endLoadingDetail('attachments'))
//   }
// }

export function fetchLatestAssessments () {
  return async (dispatch, getState) => {
    if (getState().loading.assessments === LoadingStage.None) {
      // get State data
      let userAddress = getState().ethereum.userAddress
      dispatch(beginLoadingAssessments())

      // get notification events from fathomToken contract
      const fathomTokenInstance = getInstance.fathomToken(getState())
      let pastNotifications = await fathomTokenInstance.getPastEvents('Notification', {filter: {user: userAddress}, fromBlock: 0, toBlock: 'latest'})
      let assessmentAddresses = pastNotifications.reduce((accumulator, notification) => {
        let assessment = notification.returnValues.sender
        if (accumulator.indexOf(assessment) === -1) {
          accumulator.push(assessment)
        }
        return accumulator
      }, [])

      assessmentAddresses.forEach((address) => {
        dispatch(updateAssessments(address))
      })
      dispatch(endLoadingAssessments())
    } else {
      // TODO
      // console.log('do not fetch all again')
    }
  }
}

export function updateAssessments (address) {
  return async (dispatch, getState) => {
    let assessments = await getState().assessments
    if (Object.keys(assessments).includes(address)) {
      dispatch(updateExistingAssessment(address))
    } else {
      dispatch(fetchAssessmentData(address))
    }
  }
}

function updateExistingAssessment (address) {
  return async (dispatch, getState) => {
    let userAddress = getState().ethereum.userAddress
    let oldStage = getState().assessments[address].stage

    const assessmentInstance = getInstance.assessment(getState(), address)
    let userStage = Number(await assessmentInstance.methods.assessorState(userAddress).call())
    let assessmentStage = Number(await assessmentInstance.methods.assessmentStage().call())

    // if the assessment is no longer available to the user:
    if (oldStage === Stage.Called &&
        assessmentStage > Stage.Called &&
        userStage < Stage.Confirmed) {
      dispatch(removeAssessment(address))
    }

    if (assessmentStage === Stage.Done) {
      dispatch(fetchScoreAndPayout(address))
    } else {
      dispatch(receiveAssessmentStage(address, assessmentStage))
    }
  }
}

// ============== sync actions ===================

export function receiveAssessors (address, assessors) {
  return {
    type: RECEIVE_ASSESSORS,
    address,
    assessors
  }
}

export function receiveStoredData (assessmentAddress, data) {
  return {
    type: RECEIVE_STORED_DATA,
    assessmentAddress,
    data
  }
}

export function receivePayouts (assessmentAddress, payouts) {
  return {
    type: RECEIVE_PAYOUTS,
    assessmentAddress,
    payouts
  }
}

export function receiveAssessment (assessment) {
  return {
    type: RECEIVE_ASSESSMENT,
    assessment
  }
}

export function receiveAssessmentStage (address, stage) {
  return {
    type: RECEIVE_ASSESSMENTSTAGE,
    address,
    stage
  }
}

export function receiveFinalScore (address, finalScore) {
  return {
    type: RECEIVE_ASSESSMENTSTAGE,
    address,
    finalScore
  }
}

export function removeAssessment (address) {
  return {
    type: REMOVE_ASSESSMENT,
    address
  }
}

export function beginLoadingAssessments () {
  return {
    type: BEGIN_LOADING_ASSESSMENTS
  }
}

export function endLoadingAssessments () {
  return {
    type: END_LOADING_ASSESSMENTS
  }
}

export function beginLoadingDetail (detail) {
  return {
    type: BEGIN_LOADING_DETAIL,
    detail
  }
}

export function endLoadingDetail (detail) {
  return {
    type: END_LOADING_DETAIL,
    detail
  }
}

export function setAssessment (address) {
  return {
    type: SET_ASSESSMENT,
    address
  }
}

export function resetLoadedDetails () {
  return {
    type: RESET_LOADED_DETAILS
  }
}
<commit_msg>added conversion fucntion to score fetching functions<commit_after>import { getInstance } from '../utils.js'
import { sendAndReactToTransaction } from './transActions.js'
import { Stage, LoadingStage } from '../constants.js'
export const RECEIVE_ASSESSMENT = 'RECEIVE_ASSESSMENT'
export const RECEIVE_FINALSCORE = 'RECEIVE_FINALSCORE'
export const RECEIVE_STORED_DATA = 'RECEIVE_STORED_DATA'
export const RECEIVE_PAYOUTS = 'RECEIVE_PAYOUTS'
export const RECEIVE_ASSESSMENTSTAGE = 'RECEIVE_ASSESSMENTSTAGE'
export const REMOVE_ASSESSMENT = 'REMOVE_ASSESSMENT'
export const RECEIVE_ASSESSORS = 'RECEIVE_ASSESSORS'
export const BEGIN_LOADING_ASSESSMENTS = 'BEGIN_LOADING_ASSESSMENTS'
export const END_LOADING_ASSESSMENTS = 'END_LOADING_ASSESSMENTS'
export const SET_ASSESSMENT = 'SET_ASSESSMENT'
export const BEGIN_LOADING_DETAIL = 'BEGIN_LOADING_DETAIL'
export const END_LOADING_DETAIL = 'END_LOADING_DETAIL'
export const RESET_LOADED_DETAILS = 'RESET_LOADED_DETAILS'

const ethereumjsABI = require('ethereumjs-abi')

export function hashScoreAndSalt (_score, _salt) {
  return '0x' + ethereumjsABI.soliditySHA3(
    ['int128', 'string'],
    [_score, _salt]
  ).toString('hex')
}

// ============== async actions ===================

export function confirmAssessor (address) {
  return async (dispatch, getState) => {
    let userAddress = getState().ethereum.userAddress
    let assessmentInstance = getInstance.assessment(getState(), address)
    // also salt should be saved in state => I put the saing part in the assessorStatus component
    sendAndReactToTransaction(
      dispatch,
      {method: assessmentInstance.methods.confirmAssessor, args: []},
      Stage.Called,
      userAddress,
      address
    )
  }
}

export function commit (address, score, salt) {
  return async (dispatch, getState) => {
    let userAddress = getState().ethereum.userAddress
    let assessmentInstance = getInstance.assessment(getState(), address)
    sendAndReactToTransaction(
      dispatch,
      {method: assessmentInstance.methods.commit, args: [hashScoreAndSalt(score, salt)]},
      Stage.Confirmed,
      userAddress,
      address
    )
  }
}

export function reveal (address, score, salt) {
  return async (dispatch, getState) => {
    let userAddress = getState().ethereum.userAddress
    let assessmentInstance = getInstance.assessment(getState(), address)
    sendAndReactToTransaction(
      dispatch,
      {method: assessmentInstance.methods.reveal, args: [score, salt]},
      Stage.Committed,
      userAddress,
      address
    )
  }
}

export function storeData (address, data) {
  return async (dispatch, getState) => {
    dispatch(storeDataOnAssessment(address, data))
  }
}

export function storeDataOnAssessment (address, data) {
  return async (dispatch, getState) => {
    let userAddress = getState().ethereum.userAddress
    let assessmentInstance = getInstance.assessment(getState(), address)
    // also salt should be saved in state
    let dataAsBytes = getState().ethereum.web3.utils.utf8ToHex(data)
    sendAndReactToTransaction(
      dispatch,
      {method: assessmentInstance.methods.addData, args: [dataAsBytes]},
      'meetingPointChange',
      userAddress,
      address
      // either put back fetchStoredData that was deprecated in favor of fetchAssessmentData, or use fetchAssessmentData
      // {method: fetchStoredData, args: [address]}
    )
  }
}

// fetch assessment data for one given assessment
// if that assessment is already in state, it only fetches what could have changed (stage)
export function fetchAssessmentData (assessmentAddress) {
  return async (dispatch, getState) => {
    let userAddress = getState().ethereum.userAddress
    let address = assessmentAddress || getState().assessments.selectedAssessment
    if (getState().assessments[address]) {
      let assessmentInstance = getInstance.assessment(getState(), address)
      let stage = Number(await assessmentInstance.methods.assessmentStage().call())
      if (stage !== getState().assessments[address].stage) {
        dispatch(receiveAssessmentStage(address, stage))
      }
      // mark info as loaded
      dispatch(endLoadingDetail('info'))
    } else {
      dispatch(beginLoadingDetail('info'))
      try {
        let assessmentInstance = getInstance.assessment(getState(), address)

        // get assessment infos
        let cost = await assessmentInstance.methods.cost().call()
        let endTime = await assessmentInstance.methods.endTime().call()
        // checkpoint -> keeps track of timelimits for 1) latest possible time to confirm and 2) earliest time to reveal
        let checkpoint = await assessmentInstance.methods.checkpoint().call()
        let size = await assessmentInstance.methods.size().call()
        let stage = Number(await assessmentInstance.methods.assessmentStage().call())
        let userStage = Number(await assessmentInstance.methods.assessorState(userAddress).call())
        let assessee = await assessmentInstance.methods.assessee().call()
        let conceptAddress = await assessmentInstance.methods.concept().call()

        //convert score to Front End range (FE:0,100%; BE:-100,100)
        let onChainScore = Number(await assessmentInstance.methods.finalScore().call())
        let finalScore = (onChainScore + 100 ) / 2

        // get the data (meeting point) and convert it from bytes32 to string
        let data = 'no meeting point set'
        let bytesData = await assessmentInstance.methods.data(assessee).call()
        if (bytesData) {
          data = getState().ethereum.web3.utils.hexToUtf8(bytesData)
        }

        // get conceptRegistry instance to verify assessment/concept/conceptRegistry link authenticity
        let conceptRegistryInstance = getInstance.conceptRegistry(getState())
        let isValidConcept = await conceptRegistryInstance.methods.conceptExists(conceptAddress).call()

        // check if assessment is from concept
        let conceptInstance = getInstance.concept(getState(), conceptAddress)
        let isValidAssessment = await conceptInstance.methods.assessmentExists(address).call()

        // if concept is from Registry and assessment is from concept,
        // go ahead and fetch data, otherwise, add an invalid assessment object
        if (isValidConcept && isValidAssessment) {
          // get data from associated concept
          let conceptInstance = getInstance.concept(getState(), conceptAddress)
          let conceptData = await conceptInstance.methods.data().call()
          if (conceptData) {
            conceptData = Buffer.from(conceptData.slice(2), 'hex').toString('utf8')
          } else {
            conceptData = ''
            console.log('was undefined: conceptData ', conceptData)
          }
          dispatch(receiveAssessment({
            address,
            cost,
            checkpoint,
            endTime,
            size,
            assessee,
            userStage,
            stage,
            finalScore,
            conceptAddress,
            conceptData,
            data,
            valid: true
          }))
        } else {
          // if the concept is not linked to concept Registry
          dispatch(receiveAssessment({
            address: address,
            valid: false
          }))
        }
      } catch (e) {
        console.log('reading assessment-data from the chain did not work for assessment: ', address, e)
        // In case of error, we assume the assessment address is invalid
        // conceptData will be used to detect wrong address situation (but could be any other field)
      }
      dispatch(endLoadingDetail('info'))
    }
  }
}

export function fetchScoreAndPayout (address) {
  return async (dispatch, getState) => {
    try {
      let assessmentInstance = getInstance.assessment(getState(), address)

      //convert score to Front End range (FE:0,100%; BE:-100,100)
      let onChainScore = Number(await assessmentInstance.methods.finalScore().call())
      let finalScore = (onChainScore + 100 ) / 2

      dispatch(receiveFinalScore({
        address,
        finalScore
      }))
    } catch (e) {
      console.log('reading assessment-data from the chain did not work for assessment: ', address, e)
    }
  }
}

// export function updateAssessment (address) {
//   return async (dispatch, getState) => {
//   }
// }

// reads all staked assessors from event-logs and reads their stage from the chain
// if the assessment is in the calling phase one also checks whether the user has been called
// and if, so he will be added to the list of assessors with his stage set to 1
export function fetchAssessors (selectedAssessment) {
  return async (dispatch, getState) => {
    try {
      let address = selectedAssessment || getState().assessments.selectedAssessment
      dispatch(beginLoadingDetail('assessors'))
      // reading assessors from events
      const fathomTokenInstance = getInstance.fathomToken(getState())
      // NOTE: this piece is a bit tricky, as filtering in the call usually works on the local testnet, but not on rinkeby
      // for rinkeby one has to get all events and filter locally
      let pastEvents = await fathomTokenInstance.getPastEvents({fromBlock: 0, toBlock: 'latest'})
      if (pastEvents.length === []) {
        console.log('Oddly no Notifications events have been found. Try switching Metamasks network back and forth')
      }
      let assessors = []
      pastEvents.filter(
        e =>
          e.event === 'Notification' &&
          e.returnValues['sender'] === address &&
          e.returnValues['topic'] === '2' &&
          assessors.push(e.returnValues['user'])
      )
      let stage = Number(getState().assessments[address].stage)
      dispatch(fetchAssessorStages(address, assessors, Number(stage) === Stage.Called))
      if (stage === Stage.Done) {
        dispatch(fetchAllPayouts(address))
      }
    } catch (e) {
      console.log('ERROR: fetching assessors from the events did not work!', e)
    }
  }
}

// reads all transfers an assessments to users from event-logs
export function fetchAllPayouts (address) {
  return async (dispatch, getState) => {
    dispatch(beginLoadingDetail('payouts'))
    try {
      // reading assessors-payouts from events
      const fathomTokenInstance = getInstance.fathomToken(getState())
      // NOTE: this piece is a bit tricky, as filtering in the call usually works on the local testnet, but not on rinkeby
      // for rinkeby one has to get all events and filter locally
      let pastEvents = await fathomTokenInstance.getPastEvents({fromBlock: 0, toBlock: 'latest'})
      if (pastEvents.length === []) {
        console.log('Oddly no Notifications events have been found. Try switching Metamasks network back and forth')
      }
      let payouts = {}
      pastEvents.filter(
        e =>
          e.event === 'Transfer' &&
          e.returnValues['_from'] === address &&
          (payouts[e.returnValues['_to']] = e.returnValues['_value'])
      )
      dispatch(receivePayouts(address, payouts))
    } catch (e) {
      console.log('ERROR: fetching payouts from the events did not work!', e)
    }
    dispatch(endLoadingDetail('payouts'))
  }
}

// let assessors = getState().assessments[address].assessors || []
// let data = {}
// for (let i = 0; i < assessors.length; i++) {
// data[assessors[i]] = await assessmentInstance.methods.data(assessors[i]).call()
// }

export function fetchAssessorStages (address, assessors, checkUserAddress = false) {
  return async (dispatch, getState) => {
    let assessmentInstance = getInstance.assessment(getState(), address)
    let assessorStages = []
    for (let i = 0; i < assessors.length; i++) {
      let stage = await assessmentInstance.methods.assessorState(assessors[i]).call()
      assessorStages.push({address: assessors[i], stage: stage})
    }
    if (checkUserAddress) {
      let userAddress = getState().ethereum.userAddress
      let userStage = Number(await assessmentInstance.methods.assessorState(userAddress).call())
      if (userStage === Stage.Called) {
        assessorStages.push({address: userAddress, stage: userStage})
      }
    }
    dispatch(receiveAssessors(address, assessorStages))
    dispatch(endLoadingDetail('assessors'))
  }
}

// part of fetchAssessmentData now

// returns the strings that are stored on the assessments
// for now, only the data stored by the assessee

// export function fetchStoredData (selectedAssessment) {
//   console.log('fetchStoredData', selectedAssessment)
//   return async (dispatch, getState) => {
//     dispatch(beginLoadingDetail('attachments'))
//     let address = selectedAssessment || getState().assessments.selectedAssessment
//     let assessmentInstance = getInstance.assessment(getState(), address)
//     let assessee = await assessmentInstance.methods.assessee().call()
//     let data = await assessmentInstance.methods.data(assessee).call()
//     dispatch(receiveStoredData(address, data))
//     dispatch(endLoadingDetail('attachments'))
//   }
// }

export function fetchLatestAssessments () {
  return async (dispatch, getState) => {
    if (getState().loading.assessments === LoadingStage.None) {
      // get State data
      let userAddress = getState().ethereum.userAddress
      dispatch(beginLoadingAssessments())

      // get notification events from fathomToken contract
      const fathomTokenInstance = getInstance.fathomToken(getState())
      let pastNotifications = await fathomTokenInstance.getPastEvents('Notification', {filter: {user: userAddress}, fromBlock: 0, toBlock: 'latest'})
      let assessmentAddresses = pastNotifications.reduce((accumulator, notification) => {
        let assessment = notification.returnValues.sender
        if (accumulator.indexOf(assessment) === -1) {
          accumulator.push(assessment)
        }
        return accumulator
      }, [])

      assessmentAddresses.forEach((address) => {
        dispatch(updateAssessments(address))
      })
      dispatch(endLoadingAssessments())
    } else {
      // TODO
      // console.log('do not fetch all again')
    }
  }
}

export function updateAssessments (address) {
  return async (dispatch, getState) => {
    let assessments = await getState().assessments
    if (Object.keys(assessments).includes(address)) {
      dispatch(updateExistingAssessment(address))
    } else {
      dispatch(fetchAssessmentData(address))
    }
  }
}

function updateExistingAssessment (address) {
  return async (dispatch, getState) => {
    let userAddress = getState().ethereum.userAddress
    let oldStage = getState().assessments[address].stage

    const assessmentInstance = getInstance.assessment(getState(), address)
    let userStage = Number(await assessmentInstance.methods.assessorState(userAddress).call())
    let assessmentStage = Number(await assessmentInstance.methods.assessmentStage().call())

    // if the assessment is no longer available to the user:
    if (oldStage === Stage.Called &&
        assessmentStage > Stage.Called &&
        userStage < Stage.Confirmed) {
      dispatch(removeAssessment(address))
    }

    if (assessmentStage === Stage.Done) {
      dispatch(fetchScoreAndPayout(address))
    } else {
      dispatch(receiveAssessmentStage(address, assessmentStage))
    }
  }
}

// ============== sync actions ===================

export function receiveAssessors (address, assessors) {
  return {
    type: RECEIVE_ASSESSORS,
    address,
    assessors
  }
}

export function receiveStoredData (assessmentAddress, data) {
  return {
    type: RECEIVE_STORED_DATA,
    assessmentAddress,
    data
  }
}

export function receivePayouts (assessmentAddress, payouts) {
  return {
    type: RECEIVE_PAYOUTS,
    assessmentAddress,
    payouts
  }
}

export function receiveAssessment (assessment) {
  return {
    type: RECEIVE_ASSESSMENT,
    assessment
  }
}

export function receiveAssessmentStage (address, stage) {
  return {
    type: RECEIVE_ASSESSMENTSTAGE,
    address,
    stage
  }
}

export function receiveFinalScore (address, finalScore) {
  return {
    type: RECEIVE_ASSESSMENTSTAGE,
    address,
    finalScore
  }
}

export function removeAssessment (address) {
  return {
    type: REMOVE_ASSESSMENT,
    address
  }
}

export function beginLoadingAssessments () {
  return {
    type: BEGIN_LOADING_ASSESSMENTS
  }
}

export function endLoadingAssessments () {
  return {
    type: END_LOADING_ASSESSMENTS
  }
}

export function beginLoadingDetail (detail) {
  return {
    type: BEGIN_LOADING_DETAIL,
    detail
  }
}

export function endLoadingDetail (detail) {
  return {
    type: END_LOADING_DETAIL,
    detail
  }
}

export function setAssessment (address) {
  return {
    type: SET_ASSESSMENT,
    address
  }
}

export function resetLoadedDetails () {
  return {
    type: RESET_LOADED_DETAILS
  }
}
<|endoftext|>


<commit_before>$(document).ready(function () {
    // prepare for scrolling model
    if ($('.model-container').length) {
        calculateDimensions();
        $(document).bind('scroll', $scroll_handler);
    }

    // add event listeners
    $('input[type=radio]').click(function () {
        $('#check').removeClass('disabled');
    });

    $('#header').click(function () {
        maxHeader();
    });
    $('#overlay').click(function () {
        exitFullScreen();
    });
    $('.full-screen-toggle').click(function () {
        fullScreen();
        return false;
    });

    // Adjust iframe to have correct aspect ratio
    setIframeHeight();

    // Set up sortable list
    $('#sort_embeddables').sortable({ handle: '.drag_handle',
                                      opacity: 0.8,
                                      tolerance: 'pointer',
                                      update: function(i) {
                                          $.ajax({
                                              type: "GET",
                                              url: "reorder_embeddables",
                                              data: $("#sort_embeddables").sortable("serialize")
                                          });
                                      }
                                   });
    $('#sort-pages').sortable({ handle: '.drag_handle',
                                opacity: 0.8,
                                tolerance: 'pointer',
                                update: function(i) {
                                    $.ajax({
                                        type: "GET",
                                        url: "reorder_pages",
                                        data: $('#sort-pages').sortable("serialize")
                                    });
                                }
                              });
});

var $content_height;
var $content_offset;
var $content_top;
var $content_bottom;
var $last_scroll_pos = $(document).scrollTop();
var $stop_scrolltop;
var $model_width;
var $model_height;

var $scroll_handler = function() {
    // 90px is header and its margin
    var $header_height = 90;
    if ($(document).scrollTop() > $header_height && (($(document).scrollTop() - $content_top) < (($content_bottom - $model_height) + $header_height))) {
        // Case 1: moving with scroll
        $('.model-container').css({'position': 'absolute', 'top': ($(document).scrollTop() + $header_height) + 'px', 'width': $model_width});
    } else if (($(document).scrollTop() - $content_top) >= ($content_bottom - $model_height + $header_height)) {
        // Case 2: fixed to bottom
        $('.model-container').css({'position': 'absolute', 'top': (($content_top - $header_height) + ($content_height - $model_height)) + 'px', 'width': $model_width});
    } else {
        // Case 3: fixed to top
        $('.model-container').css({'position': 'absolute', 'top': ($content_top - $header_height) + 'px', 'width': $model_width});
    }
};

function calculateDimensions(){
    $content_height = $('.text').height();
    $content_offset = $('.text').offset();
    $content_top = $content_offset.top;
    $content_bottom = $(document).height() - ($content_top + $content_height);
    $model_height = $('.model-container').height() + 35; // 25 is the height of the blue bar
    $model_width = $('.model-container').css('width');
}

$(window).resize(function(){
    calculateDimensions();
});

function checkAnswer() {
    // check for valid answer
    if (!$('input:radio[name=q1]:checked').val()) {
        alert('Please select an answer before checking.');
    } else {
        if ($('input:radio[name=q1]:checked').val() == 50) {
            alert('Correct!');
            $('#next').removeClass('disabled');
        } else {
            alert('That answer is incorrect.');
            $('#next').addClass('disabled');
        }
    }
}

function maxHeader() {
    $('#header').unbind('click').click(function(){
        minHeader();
    }).animate({'height': '130px'}, 300, function(){
        $('#header nav').fadeIn();
    });
    $('#header #mw-logo').animate({'height': '78px', 'width': '372px'}, 300);
    $('#header #cc-logo').animate({'height': '56px', 'margin-top': '15px', 'width': '182px'}, 300);
}

function minHeader() {
    $('#header nav').fadeOut();
    $('#header #mw-logo').animate({'height': '50px', 'width': '238px'}, 300);
    $('#header #cc-logo').animate({'height': '40px', 'margin-top': '10px', 'width': '130px'}, 300);
    $('#header').click(function(){
        maxHeader();
    }).animate({'height': '60px'}, 300);
}

function fullScreen() {
    $(document).unbind('scroll');
    $('#overlay').fadeIn('fast');
    $('.model').fadeOut('fast');

    $('.full-screen-toggle').attr('onclick', '').click(function(){
        exitFullScreen();
        return false;
    });
    $('.full-screen-toggle').html('Exit Full Screen');
    $('.model').css({'height': '90%', 'left': '5%', 'margin': '0', 'position': 'fixed', 'top': '5%', 'width': '90%', 'z-index': '100'});
    $('.model iframe').css({'height': '100%', 'width': '100%'});
    $('.model').fadeIn('fast');
}

function showTutorial() {
    $('#overlay').fadeIn('fast');
    $('#tutorial').fadeIn('fast');
}

function setIframeHeight() {
    // This depends on a data-aspect_ratio attribute being set in the HTML.
    var aspectRatio = $('iframe[data-aspect_ratio]').attr('data-aspect_ratio');
    var targetHeight = $('iframe[data-aspect_ratio]').width() / aspectRatio;
    $('iframe[data-aspect_ratio]').height(targetHeight);
}

function exitFullScreen() {
    if (!($('body').hasClass('full'))) {
        $(document).bind('scroll', scrollHandler());
    }
    $('#tutorial').fadeOut('fast');
    $('.model').fadeOut('fast');
    $('.full-screen-toggle').unbind('click').click(function(){
        fullScreen();
        return false;
    });
    $('.full-screen-toggle').html('Full Screen');
    $('.model').css({'height': '510px', 'left': 'auto', 'margin': '13px 0 20px', 'position': 'relative', 'top': 'auto', 'width': '100%', 'z-index': '1'});
    $('#overlay').fadeOut('slow');
    $('.model').fadeIn('fast');
}

function nextQuestion(num) {
    var curr_q = '.q' + (num - 1);
    var next_q = '.q' + num;
    $(curr_q).fadeOut('fast', function(){$(next_q).fadeIn();});
}

function prevQuestion(num) {
    var curr_q = '.q' + (num + 1);
    var next_q = '.q' + num;
    $(curr_q).fadeOut('fast', function(){$(next_q).fadeIn();});
}

function adjustWidth() {
    var model_width;
    var width;
    if ($('.content').css('width') == '960px') {
        model_width = '60%';
        width = '95%';
    } else {
        model_width = '576px';
        width = '960px';
    }

    $('#header div').css('width', width);
    $('.content').css('width', width);
    $('div.model').css('width', model_width);
    $('#footer div').css('width', width);
}

// Update the modal edit window with a returned partial
$(function() {
    $('[data-remote][data-replace]')
        .data('type', 'html')
        .live('ajax:success', function(event, data) {
                var $this = $(this);
                $($this.data('replace')).html(data.html);
                $this.trigger('ajax:replaced');
            });
});
<commit_msg>First steps for client side of "Check Answer"<commit_after>$(document).ready(function () {
    // prepare for scrolling model
    if ($('.model-container').length) {
        calculateDimensions();
        $(document).bind('scroll', $scroll_handler);
    }

    // add event listeners
    $('input[type=radio]').click(function () {
        $('#check').removeClass('disabled');
    });

    $('#header').click(function () {
        maxHeader();
    });
    $('#overlay').click(function () {
        exitFullScreen();
    });
    $('.full-screen-toggle').click(function () {
        fullScreen();
        return false;
    });

    // Adjust iframe to have correct aspect ratio
    setIframeHeight();

    // Set up sortable list
    $('#sort_embeddables').sortable({ handle: '.drag_handle',
                                      opacity: 0.8,
                                      tolerance: 'pointer',
                                      update: function(i) {
                                          $.ajax({
                                              type: "GET",
                                              url: "reorder_embeddables",
                                              data: $("#sort_embeddables").sortable("serialize")
                                          });
                                      }
                                   });
    $('#sort-pages').sortable({ handle: '.drag_handle',
                                opacity: 0.8,
                                tolerance: 'pointer',
                                update: function(i) {
                                    $.ajax({
                                        type: "GET",
                                        url: "reorder_pages",
                                        data: $('#sort-pages').sortable("serialize")
                                    });
                                }
                              });
});

var $content_height;
var $content_offset;
var $content_top;
var $content_bottom;
var $last_scroll_pos = $(document).scrollTop();
var $stop_scrolltop;
var $model_width;
var $model_height;

var $scroll_handler = function() {
    // 90px is header and its margin
    var $header_height = 90;
    if ($(document).scrollTop() > $header_height && (($(document).scrollTop() - $content_top) < (($content_bottom - $model_height) + $header_height))) {
        // Case 1: moving with scroll
        $('.model-container').css({'position': 'absolute', 'top': ($(document).scrollTop() + $header_height) + 'px', 'width': $model_width});
    } else if (($(document).scrollTop() - $content_top) >= ($content_bottom - $model_height + $header_height)) {
        // Case 2: fixed to bottom
        $('.model-container').css({'position': 'absolute', 'top': (($content_top - $header_height) + ($content_height - $model_height)) + 'px', 'width': $model_width});
    } else {
        // Case 3: fixed to top
        $('.model-container').css({'position': 'absolute', 'top': ($content_top - $header_height) + 'px', 'width': $model_width});
    }
};

function calculateDimensions(){
    $content_height = $('.text').height();
    $content_offset = $('.text').offset();
    $content_top = $content_offset.top;
    $content_bottom = $(document).height() - ($content_top + $content_height);
    $model_height = $('.model-container').height() + 35; // 25 is the height of the blue bar
    $model_width = $('.model-container').css('width');
}

$(window).resize(function(){
    calculateDimensions();
});

function checkAnswer() {
    // check for valid answer
    if (!$('input:radio[name=q1]:checked').val()) {
        alert('Please select an answer before checking.');
    } else {
        // TODO: $.ajax call to find correct answer for this question
        if ($('input:radio[name=q1]:checked').val() == 50) {
            // TODO: Use custom question response here if provided
            // TODO: Replace alert() with lightbox (look at modals.js.coffee for how)
            alert('Yes! You are correct.');
            $('#next').removeClass('disabled');
        } else {
            // TODO: Use custom question response here if provided
            alert('Sorry, that is incorrect.');
            $('#next').addClass('disabled');
        }
    }
}

function maxHeader() {
    $('#header').unbind('click').click(function(){
        minHeader();
    }).animate({'height': '130px'}, 300, function(){
        $('#header nav').fadeIn();
    });
    $('#header #mw-logo').animate({'height': '78px', 'width': '372px'}, 300);
    $('#header #cc-logo').animate({'height': '56px', 'margin-top': '15px', 'width': '182px'}, 300);
}

function minHeader() {
    $('#header nav').fadeOut();
    $('#header #mw-logo').animate({'height': '50px', 'width': '238px'}, 300);
    $('#header #cc-logo').animate({'height': '40px', 'margin-top': '10px', 'width': '130px'}, 300);
    $('#header').click(function(){
        maxHeader();
    }).animate({'height': '60px'}, 300);
}

function fullScreen() {
    $(document).unbind('scroll');
    $('#overlay').fadeIn('fast');
    $('.model').fadeOut('fast');

    $('.full-screen-toggle').attr('onclick', '').click(function(){
        exitFullScreen();
        return false;
    });
    $('.full-screen-toggle').html('Exit Full Screen');
    $('.model').css({'height': '90%', 'left': '5%', 'margin': '0', 'position': 'fixed', 'top': '5%', 'width': '90%', 'z-index': '100'});
    $('.model iframe').css({'height': '100%', 'width': '100%'});
    $('.model').fadeIn('fast');
}

function showTutorial() {
    $('#overlay').fadeIn('fast');
    $('#tutorial').fadeIn('fast');
}

function setIframeHeight() {
    // This depends on a data-aspect_ratio attribute being set in the HTML.
    var aspectRatio = $('iframe[data-aspect_ratio]').attr('data-aspect_ratio');
    var targetHeight = $('iframe[data-aspect_ratio]').width() / aspectRatio;
    $('iframe[data-aspect_ratio]').height(targetHeight);
}

function exitFullScreen() {
    if (!($('body').hasClass('full'))) {
        $(document).bind('scroll', scrollHandler());
    }
    $('#tutorial').fadeOut('fast');
    $('.model').fadeOut('fast');
    $('.full-screen-toggle').unbind('click').click(function(){
        fullScreen();
        return false;
    });
    $('.full-screen-toggle').html('Full Screen');
    $('.model').css({'height': '510px', 'left': 'auto', 'margin': '13px 0 20px', 'position': 'relative', 'top': 'auto', 'width': '100%', 'z-index': '1'});
    $('#overlay').fadeOut('slow');
    $('.model').fadeIn('fast');
}

function nextQuestion(num) {
    var curr_q = '.q' + (num - 1);
    var next_q = '.q' + num;
    $(curr_q).fadeOut('fast', function(){$(next_q).fadeIn();});
}

function prevQuestion(num) {
    var curr_q = '.q' + (num + 1);
    var next_q = '.q' + num;
    $(curr_q).fadeOut('fast', function(){$(next_q).fadeIn();});
}

function adjustWidth() {
    var model_width;
    var width;
    if ($('.content').css('width') == '960px') {
        model_width = '60%';
        width = '95%';
    } else {
        model_width = '576px';
        width = '960px';
    }

    $('#header div').css('width', width);
    $('.content').css('width', width);
    $('div.model').css('width', model_width);
    $('#footer div').css('width', width);
}

// Update the modal edit window with a returned partial
$(function() {
    $('[data-remote][data-replace]')
        .data('type', 'html')
        .live('ajax:success', function(event, data) {
                var $this = $(this);
                $($this.data('replace')).html(data.html);
                $this.trigger('ajax:replaced');
            });
});
<|endoftext|>


<commit_before>// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

var toggler = function() {
  var display = {
    errorTextToggle: document.querySelector('.error-text-toggle'),
    errorText: document.querySelector('.error-text'),

    doToggle: function(e) {
      e.preventDefault();
      this.errorText.classList.toggle('expanded');
    }
  };

  display.errorTextToggle.addEventListener('click', function(e) { display.doToggle(e); });
};

toggler();
<commit_msg>Fix javascript on non-500 pages<commit_after>// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

var toggler = function() {
  var display = {
    errorTextToggle: document.querySelector('.error-text-toggle'),
    errorText: document.querySelector('.error-text'),

    doToggle: function(e) {
      e.preventDefault();
      this.errorText.classList.toggle('expanded');
    }
  };

  if (display.errorTextToggle) {
    display.errorTextToggle.addEventListener('click', function(e) { display.doToggle(e); });
  }
};

toggler();
<|endoftext|>


<commit_before>
var renderPost = function (post, bgColor) {
  var postContainer = $(document.createElement("div")).addClass('post-container item')

  postContainer.append("

");
  postContainer.find(".post-id").text(unescapeHtml(post.id));

  postContainer.append("

");
  postContainer.find(".post-text").text(unescapeHtml(post.text));

  postContainer.append("

");
  postContainer.find(".post-username").html(" @" + post.screen_name);

  postContainer.append("

");
  if (post.media_url){
    postContainer.find(".post-picture").html("");
  }

  var formattedDate = formatDateToLocalTimezone(new Date(post.formatted_time_of_post));

  postContainer.addClass("background-color-"+bgColor);
  postContainer.append("
" + formattedDate  +"
");
  return postContainer;
}

var create_post_content = function(response) {
  var bgColor = getColorNumber();
  newPosts = [];
  for (var i = 0; i < response.length; i++){
    var postContainer = renderPost(response[i], bgColor);
    newPosts.push(postContainer)
    if (bgColor >= 4){bgColor = 0;}
    bgColor += 1;
  }

    return newPosts;
}

var getColorNumber = function() {
  return Math.floor((Math.random() * 10)) % 4 + 1;
}

var layOutMasonry = function () {
  var masonryList = document.querySelector('#posts-list');
  var msnry = new Masonry(masonryList);
  imagesLoaded( masonryList, function() {
    msnry.layout();
  });
}
<commit_msg>Fixed Shared.js conflict<commit_after>
var renderPost = function (post, bgColor) {
  var postContainer = $(document.createElement("div")).addClass('post-container item')

  postContainer.append("

");
  postContainer.find(".post-id").html((post.id));

  postContainer.append("

");
  postContainer.find(".post-text").html((post.text));

  postContainer.append("

");
  postContainer.find(".post-username").html(" @" + post.screen_name);

  postContainer.append("

");
  if (post.media_url){
    postContainer.find(".post-picture").html("");
  }

  var formattedDate = formatDateToLocalTimezone(new Date(post.formatted_time_of_post));

  postContainer.addClass("background-color-"+bgColor);
  postContainer.append("
" + formattedDate  +"
");
  return postContainer;
}

var create_post_content = function(response) {
  var bgColor = getColorNumber();
  newPosts = [];
  for (var i = 0; i < response.length; i++){
    var postContainer = renderPost(response[i], bgColor);
    newPosts.push(postContainer)
    if (bgColor >= 4){bgColor = 0;}
    bgColor += 1;
  }

    return newPosts;
}

var getColorNumber = function() {
  return Math.floor((Math.random() * 10)) % 4 + 1;
}

var layOutMasonry = function () {
  var masonryList = document.querySelector('#posts-list');
  var msnry = new Masonry(masonryList);
  imagesLoaded( masonryList, function() {
    msnry.layout();
  });
}
<|endoftext|>


<commit_before>'use strict';
var getReporter = require('jscs/lib/cli-config').getReporter;

module.exports = function (reporter) {
	// we want the function
	if (typeof reporter === 'function') return reporter;

	// load JSCS built-in or full-path or module reporters
	if (typeof reporter === 'string' || !reporter) {
		var rpt = getReporter(reporter).writer;
		if (rpt) return rpt;
		try {
			return require(reporter);
		} catch (err) {}
	}
};
<commit_msg>loadReporter: clean up<commit_after>'use strict';
var getReporter = require('jscs/lib/cli-config').getReporter;

module.exports = function (reporter) {
	// we want the function
	if (typeof reporter === 'function') return reporter;

	// load JSCS built-in or absolute path or module reporters
	return getReporter(reporter).writer;
};
<|endoftext|>


<commit_before>OV.CalculateTriangleNormal = function (v0, v1, v2)
{
    let v = OV.SubCoord3D (v1, v0);
    let w = OV.SubCoord3D (v2, v0);
    let normal = OV.CrossVector3D (v, w);
    normal.Normalize ();
    return normal;
};

OV.TransformMesh = function (mesh, transformation)
{
    if (transformation.IsIdentity ()) {
        return;
    }

    for (let i = 0; i < mesh.VertexCount (); i++) {
        let vertex = mesh.GetVertex (i);
        let transformed = transformation.TransformCoord3D (vertex);
        vertex.x = transformed.x;
        vertex.y = transformed.y;
        vertex.z = transformed.z;
    }

    if (mesh.NormalCount () > 0) {
        let trs = transformation.GetMatrix ().DecomposeTRS ();
        let normalMatrix = new OV.Matrix ().ComposeTRS (new OV.Coord3D (0.0, 0.0, 0.0), trs.rotation, new OV.Coord3D (1.0, 1.0, 1.0));
        let normalTransformation = new OV.Transformation (normalMatrix);
        for (let i = 0; i < mesh.NormalCount (); i++) {
            let normal = mesh.GetNormal (i);
            let transformed = normalTransformation.TransformCoord3D (normal);
            normal.x = transformed.x;
            normal.y = transformed.y;
            normal.z = transformed.z;
        }
    }
};

OV.FlipMeshTrianglesOrientation = function (mesh)
{
    for (let i = 0; i < mesh.TriangleCount (); i++) {
        let triangle = mesh.GetTriangle (i);
        let tmp = triangle.v1;
        triangle.v1 = triangle.v2;
        triangle.v2 = tmp;
    }
};

OV.IsModelEmpty = function (model)
{
    let isEmpty = true;
    model.EnumerateMeshInstances ((meshInstance) => {
        if (meshInstance.TriangleCount () > 0) {
            isEmpty = false;
        }
    });
    return isEmpty;
};

OV.CloneMesh = function (mesh)
{
    let cloned = new OV.Mesh ();

    cloned.SetName (mesh.GetName ());

    for (let i = 0; i < mesh.VertexCount (); i++) {
        let vertex = mesh.GetVertex (i);
        cloned.AddVertex (vertex.Clone ());
    }

    for (let i = 0; i < mesh.VertexColorCount (); i++) {
        let color = mesh.GetVertexColor (i);
        cloned.AddVertexColor (color.Clone ());
    }

    for (let i = 0; i < mesh.NormalCount (); i++) {
        let normal = mesh.GetNormal (i);
        cloned.AddNormal (normal.Clone ());
    }

    for (let i = 0; i < mesh.TextureUVCount (); i++) {
        let uv = mesh.GetTextureUV (i);
        cloned.AddTextureUV (uv.Clone ());
    }

    for (let i = 0; i < mesh.TriangleCount (); i++) {
        let triangle = mesh.GetTriangle (i);
        cloned.AddTriangle (triangle.Clone ());
    }

    return cloned;
};

OV.GetBoundingBox = function (object3D)
{
    let calculator = new OV.BoundingBoxCalculator3D ();
    object3D.EnumerateVertices ((vertex) => {
        calculator.AddPoint (vertex);
    });
    return calculator.GetBox ();
};

OV.GetTopology = function (object3D)
{
    function GetVertexIndex (vertex, octree, topology)
    {
        let index = octree.FindPoint (vertex);
        if (index === null) {
            index = topology.AddVertex ();
            octree.AddPoint (vertex, index);
        }
        return index;
    }

    let boundingBox = OV.GetBoundingBox (object3D);
    let octree = new OV.Octree (boundingBox);
    let topology = new OV.Topology ();

    object3D.EnumerateTriangleVertices ((v0, v1, v2) => {
        let v0Index = GetVertexIndex (v0, octree, topology);
        let v1Index = GetVertexIndex (v1, octree, topology);
        let v2Index = GetVertexIndex (v2, octree, topology);
        topology.AddTriangle (v0Index, v1Index, v2Index);
    });
    return topology;
};

OV.IsSolid = function (object3D)
{
    function GetEdgeOrientationInTriangle (topology, triangleIndex, edgeIndex)
    {
        const triangle = topology.triangles[triangleIndex];
        const triEdge1 = topology.triangleEdges[triangle.triEdge1];
        const triEdge2 = topology.triangleEdges[triangle.triEdge2];
        const triEdge3 = topology.triangleEdges[triangle.triEdge3];
        if (triEdge1.edge === edgeIndex) {
            return triEdge1.reversed;
        }
        if (triEdge2.edge === edgeIndex) {
            return triEdge2.reversed;
        }
        if (triEdge3.edge === edgeIndex) {
            return triEdge3.reversed;
        }
        return null;
    }

    const topology = OV.GetTopology (object3D);
    for (let edgeIndex = 0; edgeIndex < topology.edges.length; edgeIndex++) {
        const edge = topology.edges[edgeIndex];
        let triCount = edge.triangles.length;
        if (triCount === 0 || triCount % 2 !== 0) {
            return false;
        }
        let edgesDirection = 0;
        for (let triIndex = 0; triIndex < edge.triangles.length; triIndex++) {
            const triangleIndex = edge.triangles[triIndex];
            const edgeOrientation = GetEdgeOrientationInTriangle (topology, triangleIndex, edgeIndex);
            if (edgeOrientation) {
                edgesDirection += 1;
            } else {
                edgesDirection -= 1;
            }
        }
        if (edgesDirection !== 0) {
            return false;
        }
    }
    return true;
};

OV.HasDefaultMaterial = function (model)
{
    for (let i = 0; i < model.MaterialCount (); i++) {
        let material = model.GetMaterial (i);
        if (material.isDefault) {
            return true;
        }
    }
    return false;
};

OV.ReplaceDefaultMaterialColor = function (model, color)
{
    for (let i = 0; i < model.MaterialCount (); i++) {
        let material = model.GetMaterial (i);
        if (material.isDefault) {
            material.color = color;
        }
    }
};
<commit_msg>Do not show default material popup when there are vertex colors.<commit_after>OV.CalculateTriangleNormal = function (v0, v1, v2)
{
    let v = OV.SubCoord3D (v1, v0);
    let w = OV.SubCoord3D (v2, v0);
    let normal = OV.CrossVector3D (v, w);
    normal.Normalize ();
    return normal;
};

OV.TransformMesh = function (mesh, transformation)
{
    if (transformation.IsIdentity ()) {
        return;
    }

    for (let i = 0; i < mesh.VertexCount (); i++) {
        let vertex = mesh.GetVertex (i);
        let transformed = transformation.TransformCoord3D (vertex);
        vertex.x = transformed.x;
        vertex.y = transformed.y;
        vertex.z = transformed.z;
    }

    if (mesh.NormalCount () > 0) {
        let trs = transformation.GetMatrix ().DecomposeTRS ();
        let normalMatrix = new OV.Matrix ().ComposeTRS (new OV.Coord3D (0.0, 0.0, 0.0), trs.rotation, new OV.Coord3D (1.0, 1.0, 1.0));
        let normalTransformation = new OV.Transformation (normalMatrix);
        for (let i = 0; i < mesh.NormalCount (); i++) {
            let normal = mesh.GetNormal (i);
            let transformed = normalTransformation.TransformCoord3D (normal);
            normal.x = transformed.x;
            normal.y = transformed.y;
            normal.z = transformed.z;
        }
    }
};

OV.FlipMeshTrianglesOrientation = function (mesh)
{
    for (let i = 0; i < mesh.TriangleCount (); i++) {
        let triangle = mesh.GetTriangle (i);
        let tmp = triangle.v1;
        triangle.v1 = triangle.v2;
        triangle.v2 = tmp;
    }
};

OV.IsModelEmpty = function (model)
{
    let isEmpty = true;
    model.EnumerateMeshInstances ((meshInstance) => {
        if (meshInstance.TriangleCount () > 0) {
            isEmpty = false;
        }
    });
    return isEmpty;
};

OV.CloneMesh = function (mesh)
{
    let cloned = new OV.Mesh ();

    cloned.SetName (mesh.GetName ());

    for (let i = 0; i < mesh.VertexCount (); i++) {
        let vertex = mesh.GetVertex (i);
        cloned.AddVertex (vertex.Clone ());
    }

    for (let i = 0; i < mesh.VertexColorCount (); i++) {
        let color = mesh.GetVertexColor (i);
        cloned.AddVertexColor (color.Clone ());
    }

    for (let i = 0; i < mesh.NormalCount (); i++) {
        let normal = mesh.GetNormal (i);
        cloned.AddNormal (normal.Clone ());
    }

    for (let i = 0; i < mesh.TextureUVCount (); i++) {
        let uv = mesh.GetTextureUV (i);
        cloned.AddTextureUV (uv.Clone ());
    }

    for (let i = 0; i < mesh.TriangleCount (); i++) {
        let triangle = mesh.GetTriangle (i);
        cloned.AddTriangle (triangle.Clone ());
    }

    return cloned;
};

OV.GetBoundingBox = function (object3D)
{
    let calculator = new OV.BoundingBoxCalculator3D ();
    object3D.EnumerateVertices ((vertex) => {
        calculator.AddPoint (vertex);
    });
    return calculator.GetBox ();
};

OV.GetTopology = function (object3D)
{
    function GetVertexIndex (vertex, octree, topology)
    {
        let index = octree.FindPoint (vertex);
        if (index === null) {
            index = topology.AddVertex ();
            octree.AddPoint (vertex, index);
        }
        return index;
    }

    let boundingBox = OV.GetBoundingBox (object3D);
    let octree = new OV.Octree (boundingBox);
    let topology = new OV.Topology ();

    object3D.EnumerateTriangleVertices ((v0, v1, v2) => {
        let v0Index = GetVertexIndex (v0, octree, topology);
        let v1Index = GetVertexIndex (v1, octree, topology);
        let v2Index = GetVertexIndex (v2, octree, topology);
        topology.AddTriangle (v0Index, v1Index, v2Index);
    });
    return topology;
};

OV.IsSolid = function (object3D)
{
    function GetEdgeOrientationInTriangle (topology, triangleIndex, edgeIndex)
    {
        const triangle = topology.triangles[triangleIndex];
        const triEdge1 = topology.triangleEdges[triangle.triEdge1];
        const triEdge2 = topology.triangleEdges[triangle.triEdge2];
        const triEdge3 = topology.triangleEdges[triangle.triEdge3];
        if (triEdge1.edge === edgeIndex) {
            return triEdge1.reversed;
        }
        if (triEdge2.edge === edgeIndex) {
            return triEdge2.reversed;
        }
        if (triEdge3.edge === edgeIndex) {
            return triEdge3.reversed;
        }
        return null;
    }

    const topology = OV.GetTopology (object3D);
    for (let edgeIndex = 0; edgeIndex < topology.edges.length; edgeIndex++) {
        const edge = topology.edges[edgeIndex];
        let triCount = edge.triangles.length;
        if (triCount === 0 || triCount % 2 !== 0) {
            return false;
        }
        let edgesDirection = 0;
        for (let triIndex = 0; triIndex < edge.triangles.length; triIndex++) {
            const triangleIndex = edge.triangles[triIndex];
            const edgeOrientation = GetEdgeOrientationInTriangle (topology, triangleIndex, edgeIndex);
            if (edgeOrientation) {
                edgesDirection += 1;
            } else {
                edgesDirection -= 1;
            }
        }
        if (edgesDirection !== 0) {
            return false;
        }
    }
    return true;
};

OV.HasDefaultMaterial = function (model)
{
    for (let i = 0; i < model.MaterialCount (); i++) {
        let material = model.GetMaterial (i);
        if (material.isDefault && !material.vertexColors) {
            return true;
        }
    }
    return false;
};

OV.ReplaceDefaultMaterialColor = function (model, color)
{
    for (let i = 0; i < model.MaterialCount (); i++) {
        let material = model.GetMaterial (i);
        if (material.isDefault) {
            material.color = color;
        }
    }
};
<|endoftext|>


<commit_before>'use strict';

// Node modules
const He = require('he');
const Marked = require('marked');
const Striptags = require('striptags');
const Trim = require('trim');

// Create a custom renderer
let renderer = new Marked.Renderer();

// Convert code blocks to
 instead of

renderer.code = (code, lang) => {
  let pre;

  pre = lang ? '
' : '
';
  pre += He.encode(code, { useNamedReferences: true });
  pre += '
';

  return pre;
};

const self = {

  //
  // Converts a markdown string to HTML.
  //
  //  text* (string) - The markdown string to convert.
  //
  // Returns an HTML string.
  //
  toHtml: (text) => {
    text = typeof text === 'string' ? text : '';

    return Marked(text, {
      renderer: renderer
    });
  },

  //
  // Converts a markdown string to plain text.
  //
  //  text* (string) - The markdown string to convert.
  //
  toText: (text) => {
    text = typeof text === 'string' ? text : '';

    return Trim(Striptags(He.decode(Marked(text, {
      sanitize: true
    }))));
  }

};

module.exports = self;
<commit_msg>Fix bug where Quick Post generated wrong markup for code blocks<commit_after>'use strict';

// Node modules
const He = require('he');
const Marked = require('marked');
const Striptags = require('striptags');
const Trim = require('trim');

// Create a custom renderer
let renderer = new Marked.Renderer();

// Convert code blocks to
 instead of

renderer.code = (code, lang) => {
  let pre;

  pre = lang ? '
' : '
';
  pre += He.encode(code, { useNamedReferences: true });
  pre += '
';

  return pre;
};

const self = {

  //
  // Converts a markdown string to HTML.
  //
  //  text* (string) - The markdown string to convert.
  //
  // Returns an HTML string.
  //
  toHtml: (text) => {
    text = typeof text === 'string' ? text : '';

    return Marked(text, {
      renderer: renderer
    });
  },

  //
  // Converts a markdown string to plain text.
  //
  //  text* (string) - The markdown string to convert.
  //
  toText: (text) => {
    text = typeof text === 'string' ? text : '';

    return Trim(Striptags(He.decode(Marked(text, {
      sanitize: true
    }))));
  }

};

module.exports = self;
<|endoftext|>


<commit_before>/* This file constructs project tree based on information provided in package.json */

module.exports = function () {
  var packageJson = require('./readPackageJson')();
  if (!packageJson) {
    return; // How could this happen?
  }

  this.packageName = packageJson.name;
  this.packageLicense = packageJson.license;
  this.packageDescription = packageJson.description;

  this.copy('.gitignore', '.gitignore');
  this.template('_readme.md', 'README.md');
};
<commit_msg>Added creation of main package file<commit_after>/* This file constructs project tree based on information provided in package.json */
var fs = require('fs');

module.exports = function () {
  var packageJson = require('./readPackageJson')();
  if (!packageJson) {
    return; // How could this happen?
  }

  initPackageVariables.bind(this)(packageJson);
  copyTemplates.bind(this)(packageJson);
  createEntryPoint.bind(this)(packageJson.main);
};

function copyTemplates(packageJson) {
  this.copy('.gitignore', '.gitignore');
  this.template('_readme.md', 'README.md');
}

function createEntryPoint(mainFileName) {
  if (!mainFileName) {
    this.log.error('Main package file name is missing. File will not be created');
    return;
  }
  // create file if it does not exist:
  var fd = fs.openSync(mainFileName, 'a');
  fs.closeSync(fd);
}

function initPackageVariables(packageJson) {
  this.packageName = packageJson.name;
  this.packageLicense = packageJson.license;
  this.packageDescription = packageJson.description;
}
<|endoftext|>


<commit_before>const cli = require('cli');
const Gpio = require('chip-gpio').Gpio;
const sensor = require('./ds18x20-async.js');
const express = require('express');
const Program = require('./Program.js');

const app = express();

// CLI options
var options = cli.parse();

// Interval for checking/updating temperature
var interval = 2000;

// Threshold temperature for turning the heater on
var threshold = new Program(21.3);

// Hysteresis on threshold
// When heater is on, threshold is increased by half of this amount.
// When heater is off, threshold is reduced by half this amount.
var hysteresis = .1;

// Most recent temperature reading
var temperature = false;

/**
 * Extract just the time component, in local timezone, in 24-hour format, from a Date
 */
function getTime(date) {
  return (new Date(date)).toLocaleTimeString('en-US', {hour12: false});
}

var nightEnd = '07:30:00';
var nightStart = '21:00:00';
var nightThreshold = 17;

/**
 * Threshold function for thermostat program
 * If not night, return undefined
 */
function nightThreshold() {
  var time = getTime();
  if (time < nightEnd || time > nightStart) {
    return nightThreshold;
  }
}

/**
 * Simple HTTP endpoint for setting a new temperature value
 */
app.get('/:temp?', (req, res) => {
  // Make sure `temperature` is a string before `send()` uses it
  res.send('' + temperature);
  // Parse target temperature
  var temp = parseFloat(req.params.temp);
  // praseFloat returns NaN if string was not parseable
  if (isNaN(temp)) return;
  // Update default threshold
  console.log('Threshold set:', threshold.setDefaultThreshold(temp));
});

// Listen on port 80. We're assuming we're run as root, for now.
app.listen(80);

// String used to idicate degreeC units
const degC = '\u00B0C';

// Gpio to control heater output
var heater = new Gpio(0, 'out');

/**
 * Read the current heater output state.
 *
 * @return true iff heater is on
 */
function getHeater() {
  return heater.read() == 0;
}

/**
 * Set heater output to some state. true means on.
 *
 * Does nothing if heater is already in the correct state.
 */
function setHeater(on) {
  if (getHeater() == on) return;
  console.log('Heater:', on ? 'on' : 'off');
  heater.write(on ? 0 : 1);
}

/**
 * Simple utility function that returns the negative of a value if the second argument is true-ish
 */
function negateIf(num, neg) {
  return neg ? -num : num;
}

/**
 * workhorse function.
 *
 * This is the guts of how we decide if the heater should be on or not.
 */
async function doThermostat() {
  var temps = await sensor.getTemperatures();

  // Just in case no temperature sensors are available
  if (temps.reduced.count == 0) {
    console.log('No temperatures read');
    return;
  }

  // Print valid temperature readings. Record average temperature
  console.log(temperature = temps.average, degC, temps.temps.map(t => t === false ? t : t + ' ' + degC));

  // Set the output to the desired state
  setHeater(temps.average < threshold.getCurrentThreshold() - negateIf(hysteresis / 2, getHeater()));
}

/**
 * program entry point.
 *
 * Starts an interval that the 'doThermostat' function is called from.
 */
(async function main() {
  // Just in case, check if kernel driver is loaded.
  var isLoaded = await sensor.isDriverLoaded();
  if (!isLoaded) {
    console.log('Driver not loaded');
    return;
  }

  // During startup, get the list of temperature devices currently plugged in.
  // This value is not used later.
  // Every interval it scans for all available temperature sensors.
  var listOfDeviceIds = await sensor.list();

  // Print found temperature sensors
  console.log('Found devices:');
  console.log(listOfDeviceIds);

  // Keep track of the number of running instances of this interval
  var running = 0;

  setInterval(async () => {
    // If this interval is already running somehow, don't start another.
    if (running > 0) return;
    running++;
    await doThermostat();
    running--;
  }, interval);
})();
<commit_msg>Print current threshold to terminal<commit_after>const cli = require('cli');
const Gpio = require('chip-gpio').Gpio;
const sensor = require('./ds18x20-async.js');
const express = require('express');
const Program = require('./Program.js');

const app = express();

// CLI options
var options = cli.parse();

// Interval for checking/updating temperature
var interval = 2000;

// Threshold temperature for turning the heater on
var threshold = new Program(21.3);

// Hysteresis on threshold
// When heater is on, threshold is increased by half of this amount.
// When heater is off, threshold is reduced by half this amount.
var hysteresis = .1;

// Most recent temperature reading
var temperature = false;

/**
 * Extract just the time component, in local timezone, in 24-hour format, from a Date
 */
function getTime(date) {
  return (new Date(date)).toLocaleTimeString('en-US', {hour12: false});
}

var nightEnd = '07:30:00';
var nightStart = '21:00:00';
var nightThreshold = 17;

/**
 * Threshold function for thermostat program
 * If not night, return undefined
 */
function nightThreshold() {
  var time = getTime();
  if (time < nightEnd || time > nightStart) {
    return nightThreshold;
  }
}

/**
 * Simple HTTP endpoint for setting a new temperature value
 */
app.get('/:temp?', (req, res) => {
  // Make sure `temperature` is a string before `send()` uses it
  res.send('' + temperature);
  // Parse target temperature
  var temp = parseFloat(req.params.temp);
  // praseFloat returns NaN if string was not parseable
  if (isNaN(temp)) return;
  // Update default threshold
  console.log('Threshold set:', threshold.setDefaultThreshold(temp));
});

// Listen on port 80. We're assuming we're run as root, for now.
app.listen(80);

// String used to idicate degreeC units
const degC = '\u00B0C';

// Gpio to control heater output
var heater = new Gpio(0, 'out');

/**
 * Read the current heater output state.
 *
 * @return true iff heater is on
 */
function getHeater() {
  return heater.read() == 0;
}

/**
 * Set heater output to some state. true means on.
 *
 * Does nothing if heater is already in the correct state.
 */
function setHeater(on) {
  if (getHeater() == on) return;
  console.log('Heater:', on ? 'on' : 'off');
  heater.write(on ? 0 : 1);
}

/**
 * Simple utility function that returns the negative of a value if the second argument is true-ish
 */
function negateIf(num, neg) {
  return neg ? -num : num;
}

/**
 * workhorse function.
 *
 * This is the guts of how we decide if the heater should be on or not.
 */
async function doThermostat() {
  var temps = await sensor.getTemperatures();

  // Just in case no temperature sensors are available
  if (temps.reduced.count == 0) {
    console.log('No temperatures read');
    return;
  }

  // Record average temperature
  temperature = temps.average;

  // Print valid temperature readings. Record average temperature
  console.log(temperature.toFixed(2) + degC, '/', threshold.getCurrentThreshold().toFixed(2) + degC, temps.temps.map(t => t === false ? t : t.toFixed(1) + degC));

  // Set the output to the desired state
  setHeater(temperature < threshold.getCurrentThreshold() - negateIf(hysteresis / 2, getHeater()));
}

/**
 * program entry point.
 *
 * Starts an interval that the 'doThermostat' function is called from.
 */
(async function main() {
  // Just in case, check if kernel driver is loaded.
  var isLoaded = await sensor.isDriverLoaded();
  if (!isLoaded) {
    console.log('Driver not loaded');
    return;
  }

  // During startup, get the list of temperature devices currently plugged in.
  // This value is not used later.
  // Every interval it scans for all available temperature sensors.
  var listOfDeviceIds = await sensor.list();

  // Print found temperature sensors
  console.log('Found devices:');
  console.log(listOfDeviceIds);

  // Keep track of the number of running instances of this interval
  var running = 0;

  setInterval(async () => {
    // If this interval is already running somehow, don't start another.
    if (running > 0) return;
    running++;
    await doThermostat();
    running--;
  }, interval);
})();
<|endoftext|>


<commit_before>import React from 'react';
import RaisedButton from 'material-ui/RaisedButton';
import { browserHistory } from 'react-router';
import RecoLink from '../RecoLink';

const RecoList = ({recos}) => {
  if(recos && recos.length) {
    return getRecoList(recos);
  } else {
    return getEmptyState();
  }
};

RecoList.propTypes = {
  recos: React.PropTypes.arrayOf(React.PropTypes.object).isRequired
};

const getRecoList = (recos) => (

    {
      recos.map( (reco, index) => {
          return (
            <RecoLink
              key={`reco-${reco.id}`}
              reco={reco}
              ></RecoLink>
          );
      })
    }

);

const getEmptyState = () => (

No recommendations yet.

    <Link
      to={'add'}
    >
      <RaisedButton
        label={'Add new reco'}
        primary={true}/>
    </Link>

);

export default RecoList;
<commit_msg>Missing lib<commit_after>import React from 'react';
import RaisedButton from 'material-ui/RaisedButton';
import { browserHistory } from 'react-router';
import RecoLink from '../RecoLink';
import { Link } from 'react-router';

const RecoList = ({recos}) => {
  if(recos && recos.length) {
    return getRecoList(recos);
  } else {
    return getEmptyState();
  }
};

RecoList.propTypes = {
  recos: React.PropTypes.arrayOf(React.PropTypes.object).isRequired
};

const getRecoList = (recos) => (

    {
      recos.map( (reco, index) => {
          return (
            <RecoLink
              key={`reco-${reco.id}`}
              reco={reco}
              ></RecoLink>
          );
      })
    }

);

const getEmptyState = () => (

No recommendations yet.

    <Link
      to={'add'}
    >
      <RaisedButton
        label={'Add new reco'}
        primary={true}/>
    </Link>

);

export default RecoList;
<|endoftext|>