<commit_before>import React, { Component, PropTypes } from 'react'
import { Link } from 'react-router'
import { connect } from 'react-redux'
import * as MAPPING_TYPES from '../../constants/mapping_types'
import { getLinkObject } from '../base/json_helper'
import { body, repostedBody, setModels } from './RegionParser'
import Avatar from '../assets/Avatar'
import UserAvatars from '../../components/users/UserAvatars'
import ContentWarningButton from '../posts/ContentWarningButton'
import PostTools from '../posts/PostTools'
import CommentStream from '../streams/CommentStream'
import { HeartIcon, RepostIcon } from '../posts/PostIcons'
import RelationsGroup from '../relationships/RelationsGroup'
import Editor from '../../components/editor/Editor'
import { postLovers, postReposters } from '../../networking/api'

function getPostDetailPath(author, post) {
  return `/${author.username}/post/${post.token}`
}

function postLoversDrawer(post) {
  return (
    <UserAvatars
      endpoint={ postLovers(post.id) }
      icon={ <HeartIcon /> }
      key={ `userAvatarsLovers_${post.id}${post.lovesCount}` }
      post={ post }
      resultType="love"
    />
  )
}

function postRepostersDrawer(post) {
  return (
    <UserAvatars
      endpoint={ postReposters(post.id) }
      icon={ <RepostIcon /> }
      key={ `userAvatarsReposters_${post.id}${post.repostsCount}` }
      post={ post }
      resultType="repost"
    />
  )
}

function commentStream(post, author) {
  return (
    <CommentStream
      key={ `commentStream_${post.id}${post.commentsCount}` }
      post={ post }
      author={ author }
    />
  )
}

const PostHeaderTimeAgoLink = ({ to, createdAt }) =>
  <Link className="PostHeaderTimeAgoLink" to={ to }>
    {new Date(createdAt).timeAgoInWords()}
  </Link>

PostHeaderTimeAgoLink.propTypes = {
  createdAt: PropTypes.string,
  to: PropTypes.string,
}

function header(post, author) {
  if (!post || !author) { return null }
  const postDetailPath = getPostDetailPath(author, post)
  return (
    <header className="PostHeader" key={ `PostHeader_${post.id}` }>

        <Link className="PostHeaderLink" to={ `/${author.username}` }>
          <Avatar
            priority={ author.relationshipPriority }
            sources={ author.avatar }
            userId={ `${author.id}` }
            username={ author.username }
          />
          { `@${author.username}` }
        </Link>

      <RelationsGroup user={ author } classList="inHeader" />
      <PostHeaderTimeAgoLink to={ postDetailPath } createdAt={ post.createdAt } />

  )
}

function repostHeader(post, repostAuthor, repostSource, repostedBy) {
  if (!post || !repostedBy) { return null }
  const postDetailPath = getPostDetailPath(repostAuthor, post)
  return (
    <header className="RepostHeader" key={ `RepostHeader_${post.id}` }>

        <Link className="PostHeaderLink" to={ `/${repostAuthor.username}` }>
          <Avatar
            priority={ repostAuthor.relationshipPriority }
            sources={ repostAuthor.avatar }
            userId={ `${repostAuthor.id}` }
            username={ repostAuthor.username }
          />
          { `@${repostAuthor.username}` }
        </Link>

      <RelationsGroup user={ repostAuthor } classList="inHeader" />

        <Link className="PostHeaderLink" to={ `/${repostedBy.username}` }>
          <RepostIcon />
          { ` by @${repostedBy.username}` }
        </Link>

      <PostHeaderTimeAgoLink to={ postDetailPath } createdAt={ post.createdAt } />

  )
}

function footer(post, author, currentUser, isGridLayout, isRepostAnimating) {
  if (!author) { return null }
  return (
    <PostTools
      author={ author }
      post={ post }
      isGridLayout={ isGridLayout }
      isRepostAnimating={ isRepostAnimating }
      key={ `PostTools_${post.id}` }
    />
  )
}

export function parsePost(post, author, currentUser,
  isGridLayout = true, isRepostAnimating = false
) {
  if (!post) { return null }
  const cells = []
  const postDetailPath = getPostDetailPath(author, post)

  if (post.contentWarning) {
    cells.push(<ContentWarningButton key={ `contentWarning_${post.id}` } post={ post } />)
  }

  if (post.repostContent && post.repostContent.length) {
    // this is weird, but the post summary is
    // actually the repost summary on reposts
    if (isGridLayout) {
      cells.push(body(post.summary, post.id, isGridLayout, postDetailPath))
    } else {
      cells.push(body(post.repostContent, `repost_${post.id}`, isGridLayout, postDetailPath))
      if (post.content && post.content.length) {
        cells.push(repostedBody(author, post.content, post.id, isGridLayout, postDetailPath))
      }
    }
  } else {
    const content = isGridLayout ? post.summary : post.content
    cells.push(body(content, post.id, isGridLayout, postDetailPath))
  }
  cells.push(footer(post, author, currentUser, isGridLayout, isRepostAnimating))
  setModels({})
  return cells
}

function isRepost(post) {
  return post.repostContent && post.repostContent.length
}

/* eslint-disable react/prefer-stateless-function */
class PostParser extends Component {
  static propTypes = {
    assets: PropTypes.any,
    author: PropTypes.object,
    authorLinkObject: PropTypes.object,
    commentsCount: PropTypes.number,
    currentUser: PropTypes.object,
    isEditing: PropTypes.bool,
    isGridLayout: PropTypes.bool,
    isPostDetail: PropTypes.bool,
    isReposting: PropTypes.bool,
    lovesCount: PropTypes.number,
    repostsCount: PropTypes.number,
    post: PropTypes.object,
    postBody: PropTypes.array,
    showComments: PropTypes.bool,
    showLovers: PropTypes.bool,
    showReposters: PropTypes.bool,
    sourceLinkObject: PropTypes.object,
  }

  render() {
    const {
      assets,
      author,
      commentsCount,
      currentUser,
      isEditing,
      isGridLayout,
      isPostDetail,
      isReposting,
      lovesCount,
      post,
      postBody,
      repostsCount,
      showComments,
      showLovers,
      showReposters,
    } = this.props
    if (!post) { return null }
    setModels({ assets })

    const showEditor = (isEditing || isReposting) && postBody
    const reallyShowLovers = !showEditor && !isGridLayout && showLovers && lovesCount > 0
    const reallyShowReposters = !showEditor && !isGridLayout && showReposters && repostsCount > 0
    const reallyShowComments = !showEditor && !isPostDetail && showComments

    let postHeader
    if (isRepost(post)) {
      const { authorLinkObject, sourceLinkObject } = this.props
      postHeader = repostHeader(post, authorLinkObject, sourceLinkObject, author)
    } else {
      postHeader = header(post, author)
    }

    const isRepostAnimating = isReposting && !postBody
    return (

        { postHeader }
        { showEditor ?
          <Editor post={ post } /> :
          parsePost(post, author, currentUser, isGridLayout, isRepostAnimating)}
        { reallyShowLovers ? postLoversDrawer(post) : null }
        { reallyShowReposters ? postRepostersDrawer(post) : null }
        { reallyShowComments ? <Editor post={ post } isComment /> : null }
        {
          reallyShowComments && commentsCount > 0 ?
            commentStream(post, author, currentUser) :
            null
        }

)
  }
}

const mapStateToProps = ({ json, profile: currentUser }, ownProps) => {
  const post = json[MAPPING_TYPES.POSTS][ownProps.post.id]
  const author = json[MAPPING_TYPES.USERS][post.authorId]
  const assets = json.assets

  let newProps = {
    assets,
    author,
    commentsCount: post.commentsCount,
    currentUser,
    isEditing: post.isEditing || false,
    isReposting: post.isReposting || false,
    lovesCount: post.lovesCount,
    repostsCount: post.repostsCount,
    showComments: post.showComments || false,
    showLovers: post.showLovers || false,
    showReposters: post.showReposters || false,
    postBody: post.body,
    post,
  }

  if (isRepost(post)) {
    newProps = {
      ...newProps,
      authorLinkObject: post.repostAuthor || getLinkObject(post, 'repostAuthor', json) || author,
      sourceLinkObject: getLinkObject(post, 'repostedSource', json),
    }
  }

  return newProps
}

export default connect(mapStateToProps)(PostParser)

<commit_msg>Toggle embeds/nsfw content based off user setting.<commit_after>import React, { Component, PropTypes } from 'react'
import { Link } from 'react-router'
import { connect } from 'react-redux'
import * as MAPPING_TYPES from '../../constants/mapping_types'
import { getLinkObject } from '../base/json_helper'
import { body, repostedBody, setModels } from './RegionParser'
import Avatar from '../assets/Avatar'
import UserAvatars from '../../components/users/UserAvatars'
import ContentWarningButton from '../posts/ContentWarningButton'
import PostTools from '../posts/PostTools'
import CommentStream from '../streams/CommentStream'
import { HeartIcon, RepostIcon } from '../posts/PostIcons'
import RelationsGroup from '../relationships/RelationsGroup'
import Editor from '../../components/editor/Editor'
import { postLovers, postReposters } from '../../networking/api'

function getPostDetailPath(author, post) {
  return `/${author.username}/post/${post.token}`
}

function postLoversDrawer(post) {
  return (
    <UserAvatars
      endpoint={ postLovers(post.id) }
      icon={ <HeartIcon /> }
      key={ `userAvatarsLovers_${post.id}${post.lovesCount}` }
      post={ post }
      resultType="love"
    />
  )
}

function postRepostersDrawer(post) {
  return (
    <UserAvatars
      endpoint={ postReposters(post.id) }
      icon={ <RepostIcon /> }
      key={ `userAvatarsReposters_${post.id}${post.repostsCount}` }
      post={ post }
      resultType="repost"
    />
  )
}

function commentStream(post, author) {
  return (
    <CommentStream
      key={ `commentStream_${post.id}${post.commentsCount}` }
      post={ post }
      author={ author }
    />
  )
}

const PostHeaderTimeAgoLink = ({ to, createdAt }) =>
  <Link className="PostHeaderTimeAgoLink" to={ to }>
    {new Date(createdAt).timeAgoInWords()}
  </Link>

PostHeaderTimeAgoLink.propTypes = {
  createdAt: PropTypes.string,
  to: PropTypes.string,
}

function header(post, author) {
  if (!post || !author) { return null }
  const postDetailPath = getPostDetailPath(author, post)
  return (
    <header className="PostHeader" key={ `PostHeader_${post.id}` }>

        <Link className="PostHeaderLink" to={ `/${author.username}` }>
          <Avatar
            priority={ author.relationshipPriority }
            sources={ author.avatar }
            userId={ `${author.id}` }
            username={ author.username }
          />
          { `@${author.username}` }
        </Link>

      <RelationsGroup user={ author } classList="inHeader" />
      <PostHeaderTimeAgoLink to={ postDetailPath } createdAt={ post.createdAt } />

  )
}

function repostHeader(post, repostAuthor, repostSource, repostedBy) {
  if (!post || !repostedBy) { return null }
  const postDetailPath = getPostDetailPath(repostAuthor, post)
  return (
    <header className="RepostHeader" key={ `RepostHeader_${post.id}` }>

        <Link className="PostHeaderLink" to={ `/${repostAuthor.username}` }>
          <Avatar
            priority={ repostAuthor.relationshipPriority }
            sources={ repostAuthor.avatar }
            userId={ `${repostAuthor.id}` }
            username={ repostAuthor.username }
          />
          { `@${repostAuthor.username}` }
        </Link>

      <RelationsGroup user={ repostAuthor } classList="inHeader" />

        <Link className="PostHeaderLink" to={ `/${repostedBy.username}` }>
          <RepostIcon />
          { ` by @${repostedBy.username}` }
        </Link>

      <PostHeaderTimeAgoLink to={ postDetailPath } createdAt={ post.createdAt } />

  )
}

function footer(post, author, currentUser, isGridLayout, isRepostAnimating) {
  if (!author) { return null }
  return (
    <PostTools
      author={ author }
      post={ post }
      isGridLayout={ isGridLayout }
      isRepostAnimating={ isRepostAnimating }
      key={ `PostTools_${post.id}` }
    />
  )
}

export function parsePost(post, author, currentUser,
  isGridLayout = true, isRepostAnimating = false, contentWarning = null,
) {
  if (!post) { return null }
  const cells = []
  const postDetailPath = getPostDetailPath(author, post)

  if (contentWarning) {
    cells.push(<ContentWarningButton key={ `contentWarning_${post.id}` } post={ post } />)
  }

  if (post.repostContent && post.repostContent.length) {
    // this is weird, but the post summary is
    // actually the repost summary on reposts
    if (isGridLayout) {
      cells.push(body(post.summary, post.id, isGridLayout, postDetailPath))
    } else {
      cells.push(body(post.repostContent, `repost_${post.id}`, isGridLayout, postDetailPath))
      if (post.content && post.content.length) {
        cells.push(repostedBody(author, post.content, post.id, isGridLayout, postDetailPath))
      }
    }
  } else {
    const content = isGridLayout ? post.summary : post.content
    cells.push(body(content, post.id, isGridLayout, postDetailPath))
  }
  cells.push(footer(post, author, currentUser, isGridLayout, isRepostAnimating))
  setModels({})
  return cells
}

function isRepost(post) {
  return post.repostContent && post.repostContent.length
}

/* eslint-disable react/prefer-stateless-function */
class PostParser extends Component {
  static propTypes = {
    assets: PropTypes.any,
    author: PropTypes.object,
    authorLinkObject: PropTypes.object,
    commentsCount: PropTypes.number,
    contentWarning: PropTypes.string,
    currentUser: PropTypes.object,
    isEditing: PropTypes.bool,
    isGridLayout: PropTypes.bool,
    isPostDetail: PropTypes.bool,
    isReposting: PropTypes.bool,
    lovesCount: PropTypes.number,
    repostsCount: PropTypes.number,
    post: PropTypes.object,
    postBody: PropTypes.array,
    showComments: PropTypes.bool,
    showLovers: PropTypes.bool,
    showReposters: PropTypes.bool,
    sourceLinkObject: PropTypes.object,
  }

  render() {
    const {
      assets,
      author,
      commentsCount,
      contentWarning,
      currentUser,
      isEditing,
      isGridLayout,
      isPostDetail,
      isReposting,
      lovesCount,
      post,
      postBody,
      repostsCount,
      showComments,
      showLovers,
      showReposters,
    } = this.props
    if (!post) { return null }
    setModels({ assets })

    const showEditor = (isEditing || isReposting) && postBody
    const reallyShowLovers = !showEditor && !isGridLayout && showLovers && lovesCount > 0
    const reallyShowReposters = !showEditor && !isGridLayout && showReposters && repostsCount > 0
    const reallyShowComments = !showEditor && !isPostDetail && showComments

    let postHeader
    if (isRepost(post)) {
      const { authorLinkObject, sourceLinkObject } = this.props
      postHeader = repostHeader(post, authorLinkObject, sourceLinkObject, author)
    } else {
      postHeader = header(post, author)
    }

    const isRepostAnimating = isReposting && !postBody
    return (

        { postHeader }
        { showEditor ?
          <Editor post={ post } /> :
          parsePost(post, author, currentUser, isGridLayout, isRepostAnimating, contentWarning)}
        { reallyShowLovers ? postLoversDrawer(post) : null }
        { reallyShowReposters ? postRepostersDrawer(post) : null }
        { reallyShowComments ? <Editor post={ post } isComment /> : null }
        {
          reallyShowComments && commentsCount > 0 ?
            commentStream(post, author, currentUser) :
            null
        }

)
  }
}

const mapStateToProps = ({ json, profile: currentUser }, ownProps) => {
  const post = json[MAPPING_TYPES.POSTS][ownProps.post.id]
  const author = json[MAPPING_TYPES.USERS][post.authorId]
  const assets = json.assets

  let newProps = {
    assets,
    author,
    commentsCount: post.commentsCount,
    contentWarning: post.contentWarning,
    currentUser,
    isEditing: post.isEditing || false,
    isReposting: post.isReposting || false,
    lovesCount: post.lovesCount,
    repostsCount: post.repostsCount,
    showComments: post.showComments || false,
    showLovers: post.showLovers || false,
    showReposters: post.showReposters || false,
    postBody: post.body,
    post,
  }

  if (isRepost(post)) {
    newProps = {
      ...newProps,
      authorLinkObject: post.repostAuthor || getLinkObject(post, 'repostAuthor', json) || author,
      sourceLinkObject: getLinkObject(post, 'repostedSource', json),
    }
  }

  return newProps
}

export default connect(mapStateToProps)(PostParser)

<|endoftext|>


<commit_before>export default {
  methods: {
    genTBody () {
      let children = []

      if (!this.itemsLength) {
        children = [this.genEmptyBody(this.noDataText)]
      } else if (!this.filteredItems.length) {
        children = [this.genEmptyBody(this.noResultsText)]
      } else {
        children = this.filteredItems.map((item, index) => {
          const props = { item, index }
          const key = this.selectedKey

          Object.defineProperty(props, 'selected', {
            get: () => this.selected[item[this.selectedKey]],
            set: (value) => {
              let selected = this.value.slice()
              if (value) {
                selected.push(item)
              } else {
                selected = selected.filter(i => i[key] !== item[key])
              }
              this.$emit('input', selected)
            }
          })

          const row = this.$scopedSlots.items(props)

          if (row.length && row[0].tag === 'td') {
            return this.genTR(row, { attrs: { active: this.isSelected(item) } })
          } else {
            return row
          }
        })
      }

      return this.$createElement('tbody', children)
    },
    genEmptyBody (text) {
      return this.genTR([this.$createElement('td', {
        'class': 'text-xs-center',
        attrs: { colspan: '100%' }
      }, text)])
    }
  }
}
<commit_msg>cleaned up data table body mixin<commit_after>export default {
  methods: {
    genTBody () {
      const children = []

      if (!this.itemsLength) {
        children.push(this.genEmptyBody(this.noDataText))
      } else if (!this.filteredItems.length) {
        children.push(this.genEmptyBody(this.noResultsText))
      } else {
        children.push(this.genFilteredItems())
      }

      return this.$createElement('tbody', children)
    },
    genFilteredItems () {
      return this.filteredItems.map((item, index) => {
        const props = { item, index }
        const key = this.selectedKey
        const row = this.$scopedSlots.items(props)
        const needsTableRow = row.length && row[0].tag === 'td'

        Object.defineProperty(props, 'selected', {
          get: () => this.selected[item[this.selectedKey]],
          set: (value) => {
            let selected = this.value.slice()
            if (value) selected.push(item)
            else selected = selected.filter(i => i[key] !== item[key])

            this.$emit('input', selected)
          }
        })

        return needsTableRow
          ? this.genTR(row, {
            attrs: { active: this.isSelected(item) }
          })
          : row
      })
    },
    genEmptyBody (text) {
      return this.genTR([this.$createElement('td', {
        'class': 'text-xs-center',
        attrs: { colspan: '100%' }
      }, text)])
    }
  }
}
<|endoftext|>


<commit_before>import React from 'react'
import Wizard from 'components/MaterialDashboardPro/Wizard'
import Step1 from './WizardSteps/Step1'
import Step2 from './WizardSteps/Step2'
import Step3 from './WizardSteps/Step3'
// redux
import { connect } from 'react-redux'
import { createWallet, resetWallet, setWalletSaved, finishClicked } from 'store/modules/components/CreateWallet'
import { setWallet } from 'store/modules/data/wallet'
import { toastr } from 'react-redux-toastr'
// helpers
import { saveWalletToLocalStorage } from 'helpers/wallet';
import { downloadWallet as downloadWalletFile } from 'helpers/wallet'
import { pick } from 'lodash'

function SignupWizard(props) {

    function downloadWallet() {
        const { wallet, walletCreated } = props
        if (wallet && wallet.did) {
            downloadWalletFile(pick(wallet, ['did', 'bitcoinMnemonic', 'testnet']))
        } else {
            downloadWalletFile(walletCreated)
        }
        props.setWalletSaved(true)
    }

    function areWalletKeysSaved() {
        const { walletSaved } = props
        return walletSaved
    }

    function validate(step) {
        const { wallet } = props
        if (step === 1 && !(areWalletKeysSaved() || (wallet && wallet.did))) {
            toastr.warning(
                'Please save your wallet',
                'Once you have saved it you will be able to access the wallet'
            )
            return false
        }
        return true
    }

    function onChangeStep(from, to) {
        const { walletCreated, createWallet, resetWallet, setWallet, wallet } = props
        if (to === 1 && !walletCreated) createWallet()
        if (to === 2 && !(wallet && wallet.did)) {
            // set and save full wallet
            setWallet(walletCreated)
            saveWalletToLocalStorage(walletCreated)
            resetWallet() // deletes temp wallet
            toastr.success('Wallet Created', 'Your Wallet is ready to go!')
        }
    }

  return <Wizard
             validate={validate}
             onChangeStep={onChangeStep}
             finishButtonClick={props.finishClicked}

             steps={[
               {
                 stepName: '1: Create Your Wallet',
                 stepComponent: Step1,
                 stepId: 'get started',
                 stepProps: {
                   ...props
                 }
               },
               {
                 stepName: '2: Save Your D.I.D.',
                 stepComponent: Step2,
                 stepId: 'about',
                 stepProps: {
                   ...props,
                   downloadWallet
                 }
               },
               {
                 stepName: '3: Claim Your Reputation',
                 stepComponent: Step3,
                 stepId: 'reviews'
               },
             ]}
             title="Let's Get Started"
             subtitle='Follow The Three Easy Steps Below To Begin'
         />
}

const mapStateToProps = store => ({
  loading: store.components.createWallet.loading,
  walletSaved: store.components.createWallet.walletSaved,
  walletCreated: store.components.createWallet.walletCreated,
  wallet: store.data.wallet
})

const mapDispatchToProps = {
    finishClicked,
    createWallet,
    setWallet,
    resetWallet,
    setWalletSaved
}

export default connect(mapStateToProps, mapDispatchToProps)(SignupWizard)
<commit_msg>start the signup wizard on the right step<commit_after>import React from 'react'
import Wizard from 'components/MaterialDashboardPro/Wizard'
import Step1 from './WizardSteps/Step1'
import Step2 from './WizardSteps/Step2'
import Step3 from './WizardSteps/Step3'
// redux
import { connect } from 'react-redux'
import { createWallet, resetWallet, setWalletSaved, finishClicked } from 'store/modules/components/CreateWallet'
import { setWallet } from 'store/modules/data/wallet'
import { toastr } from 'react-redux-toastr'
// helpers
import { saveWalletToLocalStorage } from 'helpers/wallet';
import { downloadWallet as downloadWalletFile } from 'helpers/wallet'
import { pick } from 'lodash'

function SignupWizard(props) {

    function downloadWallet() {
        const { wallet, walletCreated } = props
        if (wallet && wallet.did) {
            downloadWalletFile(pick(wallet, ['did', 'bitcoinMnemonic', 'testnet']))
        } else {
            downloadWalletFile(walletCreated)
        }
        props.setWalletSaved(true)
    }

    function areWalletKeysSaved() {
        const { walletSaved } = props
        return walletSaved
    }

    function validate(step) {
        const { wallet } = props
        if (step === 1 && !(areWalletKeysSaved() || (wallet && wallet.did))) {
            toastr.warning(
                'Please save your wallet',
                'Once you have saved it you will be able to access the wallet'
            )
            return false
        }
        return true
    }

    function onChangeStep(from, to) {
        const { walletCreated, createWallet, resetWallet, setWallet, wallet } = props
        if (to === 1 && !walletCreated) createWallet()
        if (to === 2 && !(wallet && wallet.did)) {
            // set and save full wallet
            setWallet(walletCreated)
            saveWalletToLocalStorage(walletCreated)
            resetWallet() // deletes temp wallet
            toastr.success('Wallet Created', 'Your Wallet is ready to go!')
        }
    }

    const initialStep = props.wallet.did ? 2 : (props.walletCreated ? 1 : 0)

  return <Wizard
             validate={validate}
             currentStep={initialStep}
             onChangeStep={onChangeStep}
             finishButtonClick={props.finishClicked}

             steps={[
               {
                 stepName: '1: Create Your Wallet',
                 stepComponent: Step1,
                 stepId: 'get started',
                 stepProps: {
                   ...props
                 }
               },
               {
                 stepName: '2: Save Your D.I.D.',
                 stepComponent: Step2,
                 stepId: 'about',
                 stepProps: {
                   ...props,
                   downloadWallet
                 }
               },
               {
                 stepName: '3: Claim Your Reputation',
                 stepComponent: Step3,
                 stepId: 'reviews'
               },
             ]}
             title="Let's Get Started"
             subtitle='Follow The Three Easy Steps Below To Begin'
         />
}

const mapStateToProps = store => ({
  loading: store.components.createWallet.loading,
  walletSaved: store.components.createWallet.walletSaved,
  walletCreated: store.components.createWallet.walletCreated,
  wallet: store.data.wallet
})

const mapDispatchToProps = {
    finishClicked,
    createWallet,
    setWallet,
    resetWallet,
    setWalletSaved
}

export default connect(mapStateToProps, mapDispatchToProps)(SignupWizard)
<|endoftext|>


<commit_before>/**
 * Things Controller.
 *
 * Manages HTTP requests to /things.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

'use strict';

const express = require('express');
const AdapterManager = require('../adapter-manager');
const Constants = require('../constants.js');
const Things = require('../models/things');

const ThingsController = express.Router();

/**
 * Get a list of Things.
 */
ThingsController.get('/', function (request, response) {
  Things.getThingDescriptions().then(function(things) {
    response.status(200).json(things);
  });
});

/**
 * Handle creating a new thing.
 */
ThingsController.post('/', function (request, response) {
  if (!request.body || !request.body.id) {
    response.status(400).send('No id in thing description');
    return;
  }
  var description = request.body;
  var id = description.id;
  delete description.id;
  Things.createThing(id, description).then(function(thing) {
    console.log('Successfully created new thing ' + thing);
    response.status(201).send(thing);
  }).catch(function(error) {
    console.error('Error saving new thing');
    console.error(error);
    response.status(500).send(error);
  });
});

/**
 * Get a Thing.
 */
 ThingsController.get('/:thingId', function(request, response) {
   var id = request.params.thingId;
   Things.getThingDescription(id).then(function(thing) {
     response.status(200).json(thing);
   }).catch(function(error) {
     console.error('Error getting thing description for thing with id ' + id);
     console.error('Error: ' + error);
     response.status(404).send(error);
   });
 });

/**
 * Get a property of a Thing.
 */
ThingsController.get('/:thingId/properties/:propertyName',
  function(request, response) {
  var thingId = request.params.thingId;
  var propertyName = request.params.propertyName;
  AdapterManager.getProperty(thingId, propertyName).then((value) => {
    var result = {};
    result[propertyName] = value;
    response.status(200).json(result);
  }).catch((error) => {
    console.error('Error getting value for thingId:', thingId,
                  'property:', propertyName);
    console.error(error);
    response.status(500).send(error);
  });
});

/**
 * Set a property of a Thing.
 */
ThingsController.put('/:thingId/properties/:propertyName',
  function(request, response) {
  var thingId = request.params.thingId;
  var propertyName = request.params.propertyName;
  if(!request.body || request.body[propertyName] === undefined) {
    response.status(400).send('Invalid property name');
    return;
  }
  var value = request.body[propertyName];
  AdapterManager.setProperty(thingId, propertyName, value)
    .then((updatedValue) => {
      // Note: it's possible that updatedValue doesn't match value.
      var result = {};
      result[propertyName] = updatedValue;
      response.status(200).json(result);
    }).catch((error) => {
      console.error('Error setting value for thingId:', thingId,
                    'property:', propertyName,
                    'value:', value);
      response.status(500).send(error);
    });
});

/**
 * Remove a Thing.
 */
ThingsController.delete('/:thingId', function(request, response) {
  var thingId = request.params.thingId;
  try {
    Things.removeThing(thingId).then(function() {
      console.log('Successfully deleted ' + thingId + ' from database.');
      response.status(204).send();
    });
  } catch(e) {
    response.status(500).send('Failed to remove thing ' + thingId);
  }
});

/**
 * Connect to receive messages from a Thing
 */
ThingsController.ws('/:thingId/', function(websocket, request) {
  let thingId = request.params.thingId;

  function onPropertyChanged(property) {
    if (property.device.id !== thingId) {
      return;
    }
    websocket.send(JSON.stringify({
      messageType: Constants.PROPERTY_STATUS,
      data: {
        [property.name]: property.value
      }
    }));
  }

  AdapterManager.on('property-changed', onPropertyChanged);

  websocket.on('close', function() {
    AdapterManager.removeListener('property-changed', onPropertyChanged);
  });

  websocket.on('message', function(requestText) {
    let request = null;
    try {
      request = JSON.parse(requestText);
    } catch(e) {
      websocket.send(JSON.stringify({
        messageType: Constants.ERROR,
        data: {
          status: '400 Bad Request',
          message: 'Parsing request failed',
        }
      }));
      return;
    }

    let device = AdapterManager.getDevice(thingId);
    if (!device) {
      websocket.send(JSON.stringify({
        messageType: Constants.ERROR,
        data: {
          status: '400 Bad Request',
          message: `Thing ${thingId} not found`,
          request: request
        }
      }));
      return;
    }
    if (request.messageType === Constants.SET_PROPERTY) {
      let setRequests = Object.keys(request.data).map(property => {
        let value = request.data[property];
        return device.setProperty(property, value);
      });
      Promise.all(setRequests).catch(err => {
        // If any set fails, send an error
        websocket.send(JSON.stringify({
          messageType: Constants.ERROR,
          data: {
            status: '400 Bad Request',
            message: err,
            request: request
          }
        }));
      });
    }
  });
});

module.exports = ThingsController;
<commit_msg>Add context to logging statements<commit_after>/**
 * Things Controller.
 *
 * Manages HTTP requests to /things.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

'use strict';

const express = require('express');
const AdapterManager = require('../adapter-manager');
const Constants = require('../constants.js');
const Things = require('../models/things');

const ThingsController = express.Router();

/**
 * Get a list of Things.
 */
ThingsController.get('/', function (request, response) {
  Things.getThingDescriptions().then(function(things) {
    response.status(200).json(things);
  });
});

/**
 * Handle creating a new thing.
 */
ThingsController.post('/', function (request, response) {
  if (!request.body || !request.body.id) {
    response.status(400).send('No id in thing description');
    return;
  }
  var description = request.body;
  var id = description.id;
  delete description.id;
  Things.createThing(id, description).then(function(thing) {
    console.log('Successfully created new thing ' + thing.name);
    response.status(201).send(thing);
  }).catch(function(error) {
    console.error('Error saving new thing', id, description);
    console.error(error);
    response.status(500).send(error);
  });
});

/**
 * Get a Thing.
 */
 ThingsController.get('/:thingId', function(request, response) {
   var id = request.params.thingId;
   Things.getThingDescription(id).then(function(thing) {
     response.status(200).json(thing);
   }).catch(function(error) {
     console.error('Error getting thing description for thing with id ' + id);
     console.error('Error: ' + error);
     response.status(404).send(error);
   });
 });

/**
 * Get a property of a Thing.
 */
ThingsController.get('/:thingId/properties/:propertyName',
  function(request, response) {
  var thingId = request.params.thingId;
  var propertyName = request.params.propertyName;
  AdapterManager.getProperty(thingId, propertyName).then((value) => {
    var result = {};
    result[propertyName] = value;
    response.status(200).json(result);
  }).catch((error) => {
    console.error('Error getting value for thingId:', thingId,
                  'property:', propertyName);
    console.error(error);
    response.status(500).send(error);
  });
});

/**
 * Set a property of a Thing.
 */
ThingsController.put('/:thingId/properties/:propertyName',
  function(request, response) {
  var thingId = request.params.thingId;
  var propertyName = request.params.propertyName;
  if(!request.body || request.body[propertyName] === undefined) {
    response.status(400).send('Invalid property name');
    return;
  }
  var value = request.body[propertyName];
  AdapterManager.setProperty(thingId, propertyName, value)
    .then((updatedValue) => {
      // Note: it's possible that updatedValue doesn't match value.
      var result = {};
      result[propertyName] = updatedValue;
      response.status(200).json(result);
    }).catch((error) => {
      console.error('Error setting value for thingId:', thingId,
                    'property:', propertyName,
                    'value:', value);
      response.status(500).send(error);
    });
});

/**
 * Remove a Thing.
 */
ThingsController.delete('/:thingId', function(request, response) {
  var thingId = request.params.thingId;
  try {
    Things.removeThing(thingId).then(function() {
      console.log('Successfully deleted ' + thingId + ' from database.');
      response.status(204).send();
    });
  } catch(e) {
    response.status(500).send('Failed to remove thing ' + thingId);
  }
});

/**
 * Connect to receive messages from a Thing
 */
ThingsController.ws('/:thingId/', function(websocket, request) {
  let thingId = request.params.thingId;

  function onPropertyChanged(property) {
    if (property.device.id !== thingId) {
      return;
    }
    websocket.send(JSON.stringify({
      messageType: Constants.PROPERTY_STATUS,
      data: {
        [property.name]: property.value
      }
    }));
  }

  AdapterManager.on('property-changed', onPropertyChanged);

  websocket.on('close', function() {
    AdapterManager.removeListener('property-changed', onPropertyChanged);
  });

  websocket.on('message', function(requestText) {
    let request = null;
    try {
      request = JSON.parse(requestText);
    } catch(e) {
      websocket.send(JSON.stringify({
        messageType: Constants.ERROR,
        data: {
          status: '400 Bad Request',
          message: 'Parsing request failed',
        }
      }));
      return;
    }

    let device = AdapterManager.getDevice(thingId);
    if (!device) {
      websocket.send(JSON.stringify({
        messageType: Constants.ERROR,
        data: {
          status: '400 Bad Request',
          message: `Thing ${thingId} not found`,
          request: request
        }
      }));
      return;
    }
    if (request.messageType === Constants.SET_PROPERTY) {
      let setRequests = Object.keys(request.data).map(property => {
        let value = request.data[property];
        return device.setProperty(property, value);
      });
      Promise.all(setRequests).catch(err => {
        // If any set fails, send an error
        websocket.send(JSON.stringify({
          messageType: Constants.ERROR,
          data: {
            status: '400 Bad Request',
            message: err,
            request: request
          }
        }));
      });
    }
  });
});

module.exports = ThingsController;
<|endoftext|>


<commit_before>import {Command} from '@grid/core/command';
import {noop} from '../utility';

export class Composite {
	static func(list, reduce = noop, memo = null) {
		return (...args) => {
			for (const f of list) {
				memo = reduce(memo, f(...args));
			}

			return memo;
		};
	}

	static command(list) {
		return new Command({
			source: 'composite',
			canExecute: (...args) => {
				return list.reduce((memo, cmd) => memo || cmd.canExecute(...args), false);
			},
			execute: (...args) => {
				return list
					.filter(cmd => cmd.canExecute(...args))
					.reduce((memo, cmd) => cmd.execute(...args) || memo, false);
			}
		});
	}

	static list(list) {
		return list.reduce((memo, xs) => memo.concat(xs), []);
	}

	static object(list, memo = {}) {
		return Object.assign(memo, ...list);
	}
}<commit_msg>Set command reducer memo to undefined<commit_after>import {Command} from '@grid/core/command';
import {noop} from '../utility';

export class Composite {
	static func(list, reduce = noop, memo = null) {
		return (...args) => {
			for (const f of list) {
				memo = reduce(memo, f(...args));
			}

			return memo;
		};
	}

	static command(list) {
		return new Command({
			source: 'composite',
			canExecute: (...args) => {
				return list.reduce((memo, cmd) => memo || cmd.canExecute(...args), false);
			},
			execute: (...args) => {
				return list
					.filter(cmd => cmd.canExecute(...args))
					.reduce((memo, cmd) => cmd.execute(...args) || memo);
			}
		});
	}

	static list(list) {
		return list.reduce((memo, xs) => memo.concat(xs), []);
	}

	static object(list, memo = {}) {
		return Object.assign(memo, ...list);
	}
}<|endoftext|>


<commit_before>import { sayHello, hex2string, hex2rgb } from '../utils';
import { Matrix, Rectangle } from '../math';
import { RENDERER_TYPE } from '../const';
import settings from '../settings';
import Container from '../display/Container';
import RenderTexture from '../textures/RenderTexture';
import EventEmitter from 'eventemitter3';

const tempMatrix = new Matrix();

/**
 * The SystemRenderer is the base for a PixiJS Renderer. It is extended by the {@link PIXI.CanvasRenderer}
 * and {@link PIXI.WebGLRenderer} which can be used for rendering a PixiJS scene.
 *
 * @abstract
 * @class
 * @extends EventEmitter
 * @memberof PIXI
 */
export default class SystemRenderer extends EventEmitter
{
    // eslint-disable-next-line valid-jsdoc
    /**
     * @param {string} system - The name of the system this renderer is for.
     * @param {object} [options] - The optional renderer parameters
     * @param {number} [options.width=800] - the width of the screen
     * @param {number} [options.height=600] - the height of the screen
     * @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
     * @param {boolean} [options.transparent=false] - If the render view is transparent, default false
     * @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
     * @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
     * @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer. The
     *  resolution of the renderer retina would be 2.
     * @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation,
     *  enable this if you need to call toDataUrl on the webgl context.
     * @param {boolean} [options.clearBeforeRender=true] - This sets if the renderer will clear the canvas or
     *      not before the new render pass.
     * @param {number} [options.backgroundColor=0x000000] - The background color of the rendered area
     *  (shown if not transparent).
     * @param {boolean} [options.roundPixels=false] - If true PixiJS will Math.floor() x/y values when rendering,
     *  stopping pixel interpolation.
     */
    constructor(system, options, arg2, arg3)
    {
        super();

        sayHello(system);

        // Support for constructor(system, screenWidth, screenHeight, options)
        if (typeof options === 'number')
        {
            options = Object.assign({
                width: options,
                height: arg2 || settings.RENDER_OPTIONS.height,
            }, arg3);
        }

        // Add the default render options
        options = Object.assign({}, settings.RENDER_OPTIONS, options);

        /**
         * The supplied constructor options.
         *
         * @member {Object}
         * @readOnly
         */
        this.options = options;

        /**
         * The type of the renderer.
         *
         * @member {number}
         * @default PIXI.RENDERER_TYPE.UNKNOWN
         * @see PIXI.RENDERER_TYPE
         */
        this.type = RENDERER_TYPE.UNKNOWN;

        /**
         * Measurements of the screen. (0, 0, screenWidth, screenHeight)
         *
         * Its safe to use as filterArea or hitArea for whole stage
         *
         * @member {PIXI.Rectangle}
         */
        this.screen = new Rectangle(0, 0, options.width, options.height);

        /**
         * The canvas element that everything is drawn to
         *
         * @member {HTMLCanvasElement}
         */
        this.view = options.view || document.createElement('canvas');

        /**
         * The resolution / device pixel ratio of the renderer
         *
         * @member {number}
         * @default 1
         */
        this.resolution = options.resolution || settings.RESOLUTION;

        /**
         * Whether the render view is transparent
         *
         * @member {boolean}
         */
        this.transparent = options.transparent;

        /**
         * Whether css dimensions of canvas view should be resized to screen dimensions automatically
         *
         * @member {boolean}
         */
        this.autoResize = options.autoResize || false;

        /**
         * Tracks the blend modes useful for this renderer.
         *
         * @member {object<string, mixed>}
         */
        this.blendModes = null;

        /**
         * The value of the preserveDrawingBuffer flag affects whether or not the contents of
         * the stencil buffer is retained after rendering.
         *
         * @member {boolean}
         */
        this.preserveDrawingBuffer = options.preserveDrawingBuffer;

        /**
         * This sets if the CanvasRenderer will clear the canvas or not before the new render pass.
         * If the scene is NOT transparent PixiJS will use a canvas sized fillRect operation every
         * frame to set the canvas background color. If the scene is transparent PixiJS will use clearRect
         * to clear the canvas every frame. Disable this by setting this to false. For example if
         * your game has a canvas filling background image you often don't need this set.
         *
         * @member {boolean}
         * @default
         */
        this.clearBeforeRender = options.clearBeforeRender;

        /**
         * If true PixiJS will Math.floor() x/y values when rendering, stopping pixel interpolation.
         * Handy for crisp pixel art and speed on legacy devices.
         *
         * @member {boolean}
         */
        this.roundPixels = options.roundPixels;

        /**
         * The background color as a number.
         *
         * @member {number}
         * @private
         */
        this._backgroundColor = 0x000000;

        /**
         * The background color as an [R, G, B] array.
         *
         * @member {number[]}
         * @private
         */
        this._backgroundColorRgba = [0, 0, 0, 0];

        /**
         * The background color as a string.
         *
         * @member {string}
         * @private
         */
        this._backgroundColorString = '#000000';

        this.backgroundColor = options.backgroundColor || this._backgroundColor; // run bg color setter

        /**
         * This temporary display object used as the parent of the currently being rendered item
         *
         * @member {PIXI.DisplayObject}
         * @private
         */
        this._tempDisplayObjectParent = new Container();

        /**
         * The last root object that the renderer tried to render.
         *
         * @member {PIXI.DisplayObject}
         * @private
         */
        this._lastObjectRendered = this._tempDisplayObjectParent;
    }

    /**
     * Same as view.width, actual number of pixels in the canvas by horizontal
     *
     * @member {number}
     * @readonly
     * @default 800
     */
    get width()
    {
        return this.view.width;
    }

    /**
     * Same as view.height, actual number of pixels in the canvas by vertical
     *
     * @member {number}
     * @readonly
     * @default 600
     */
    get height()
    {
        return this.view.height;
    }

    /**
     * Resizes the screen and canvas to the specified width and height
     * Canvas dimensions are multiplied by resolution
     *
     * @param {number} screenWidth - the new width of the screen
     * @param {number} screenHeight - the new height of the screen
     */
    resize(screenWidth, screenHeight)
    {
        this.screen.width = screenWidth;
        this.screen.height = screenHeight;

        this.view.width = screenWidth * this.resolution;
        this.view.height = screenHeight * this.resolution;

        if (this.autoResize)
        {
            this.view.style.width = `${screenWidth}px`;
            this.view.style.height = `${screenHeight}px`;
        }
    }

    /**
     * Useful function that returns a texture of the display object that can then be used to create sprites
     * This can be quite useful if your displayObject is complicated and needs to be reused multiple times.
     *
     * @param {PIXI.DisplayObject} displayObject - The displayObject the object will be generated from
     * @param {number} scaleMode - Should be one of the scaleMode consts
     * @param {number} resolution - The resolution / device pixel ratio of the texture being generated
     * @return {PIXI.Texture} a texture of the graphics object
     */
    generateTexture(displayObject, scaleMode, resolution)
    {
        const bounds = displayObject.getLocalBounds();

        const renderTexture = RenderTexture.create(bounds.width | 0, bounds.height | 0, scaleMode, resolution);

        tempMatrix.tx = -bounds.x;
        tempMatrix.ty = -bounds.y;

        this.render(displayObject, renderTexture, false, tempMatrix, true);

        return renderTexture;
    }

    /**
     * Removes everything from the renderer and optionally removes the Canvas DOM element.
     *
     * @param {boolean} [removeView=false] - Removes the Canvas element from the DOM.
     */
    destroy(removeView)
    {
        if (removeView && this.view.parentNode)
        {
            this.view.parentNode.removeChild(this.view);
        }

        this.type = RENDERER_TYPE.UNKNOWN;

        this.view = null;

        this.screen = null;

        this.resolution = 0;

        this.transparent = false;

        this.autoResize = false;

        this.blendModes = null;

        this.options = null;

        this.preserveDrawingBuffer = false;
        this.clearBeforeRender = false;

        this.roundPixels = false;

        this._backgroundColor = 0;
        this._backgroundColorRgba = null;
        this._backgroundColorString = null;

        this._tempDisplayObjectParent = null;
        this._lastObjectRendered = null;
    }

    /**
     * The background color to fill if not transparent
     *
     * @member {number}
     */
    get backgroundColor()
    {
        return this._backgroundColor;
    }

    set backgroundColor(value) // eslint-disable-line require-jsdoc
    {
        this._backgroundColor = value;
        this._backgroundColorString = hex2string(value);
        hex2rgb(value, this._backgroundColorRgba);
    }
}
<commit_msg>Region parameter for Renderer.generateTexture() (#4477)<commit_after>import { sayHello, hex2string, hex2rgb } from '../utils';
import { Matrix, Rectangle } from '../math';
import { RENDERER_TYPE } from '../const';
import settings from '../settings';
import Container from '../display/Container';
import RenderTexture from '../textures/RenderTexture';
import EventEmitter from 'eventemitter3';

const tempMatrix = new Matrix();

/**
 * The SystemRenderer is the base for a PixiJS Renderer. It is extended by the {@link PIXI.CanvasRenderer}
 * and {@link PIXI.WebGLRenderer} which can be used for rendering a PixiJS scene.
 *
 * @abstract
 * @class
 * @extends EventEmitter
 * @memberof PIXI
 */
export default class SystemRenderer extends EventEmitter
{
    // eslint-disable-next-line valid-jsdoc
    /**
     * @param {string} system - The name of the system this renderer is for.
     * @param {object} [options] - The optional renderer parameters
     * @param {number} [options.width=800] - the width of the screen
     * @param {number} [options.height=600] - the height of the screen
     * @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
     * @param {boolean} [options.transparent=false] - If the render view is transparent, default false
     * @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
     * @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
     * @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer. The
     *  resolution of the renderer retina would be 2.
     * @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation,
     *  enable this if you need to call toDataUrl on the webgl context.
     * @param {boolean} [options.clearBeforeRender=true] - This sets if the renderer will clear the canvas or
     *      not before the new render pass.
     * @param {number} [options.backgroundColor=0x000000] - The background color of the rendered area
     *  (shown if not transparent).
     * @param {boolean} [options.roundPixels=false] - If true PixiJS will Math.floor() x/y values when rendering,
     *  stopping pixel interpolation.
     */
    constructor(system, options, arg2, arg3)
    {
        super();

        sayHello(system);

        // Support for constructor(system, screenWidth, screenHeight, options)
        if (typeof options === 'number')
        {
            options = Object.assign({
                width: options,
                height: arg2 || settings.RENDER_OPTIONS.height,
            }, arg3);
        }

        // Add the default render options
        options = Object.assign({}, settings.RENDER_OPTIONS, options);

        /**
         * The supplied constructor options.
         *
         * @member {Object}
         * @readOnly
         */
        this.options = options;

        /**
         * The type of the renderer.
         *
         * @member {number}
         * @default PIXI.RENDERER_TYPE.UNKNOWN
         * @see PIXI.RENDERER_TYPE
         */
        this.type = RENDERER_TYPE.UNKNOWN;

        /**
         * Measurements of the screen. (0, 0, screenWidth, screenHeight)
         *
         * Its safe to use as filterArea or hitArea for whole stage
         *
         * @member {PIXI.Rectangle}
         */
        this.screen = new Rectangle(0, 0, options.width, options.height);

        /**
         * The canvas element that everything is drawn to
         *
         * @member {HTMLCanvasElement}
         */
        this.view = options.view || document.createElement('canvas');

        /**
         * The resolution / device pixel ratio of the renderer
         *
         * @member {number}
         * @default 1
         */
        this.resolution = options.resolution || settings.RESOLUTION;

        /**
         * Whether the render view is transparent
         *
         * @member {boolean}
         */
        this.transparent = options.transparent;

        /**
         * Whether css dimensions of canvas view should be resized to screen dimensions automatically
         *
         * @member {boolean}
         */
        this.autoResize = options.autoResize || false;

        /**
         * Tracks the blend modes useful for this renderer.
         *
         * @member {object<string, mixed>}
         */
        this.blendModes = null;

        /**
         * The value of the preserveDrawingBuffer flag affects whether or not the contents of
         * the stencil buffer is retained after rendering.
         *
         * @member {boolean}
         */
        this.preserveDrawingBuffer = options.preserveDrawingBuffer;

        /**
         * This sets if the CanvasRenderer will clear the canvas or not before the new render pass.
         * If the scene is NOT transparent PixiJS will use a canvas sized fillRect operation every
         * frame to set the canvas background color. If the scene is transparent PixiJS will use clearRect
         * to clear the canvas every frame. Disable this by setting this to false. For example if
         * your game has a canvas filling background image you often don't need this set.
         *
         * @member {boolean}
         * @default
         */
        this.clearBeforeRender = options.clearBeforeRender;

        /**
         * If true PixiJS will Math.floor() x/y values when rendering, stopping pixel interpolation.
         * Handy for crisp pixel art and speed on legacy devices.
         *
         * @member {boolean}
         */
        this.roundPixels = options.roundPixels;

        /**
         * The background color as a number.
         *
         * @member {number}
         * @private
         */
        this._backgroundColor = 0x000000;

        /**
         * The background color as an [R, G, B] array.
         *
         * @member {number[]}
         * @private
         */
        this._backgroundColorRgba = [0, 0, 0, 0];

        /**
         * The background color as a string.
         *
         * @member {string}
         * @private
         */
        this._backgroundColorString = '#000000';

        this.backgroundColor = options.backgroundColor || this._backgroundColor; // run bg color setter

        /**
         * This temporary display object used as the parent of the currently being rendered item
         *
         * @member {PIXI.DisplayObject}
         * @private
         */
        this._tempDisplayObjectParent = new Container();

        /**
         * The last root object that the renderer tried to render.
         *
         * @member {PIXI.DisplayObject}
         * @private
         */
        this._lastObjectRendered = this._tempDisplayObjectParent;
    }

    /**
     * Same as view.width, actual number of pixels in the canvas by horizontal
     *
     * @member {number}
     * @readonly
     * @default 800
     */
    get width()
    {
        return this.view.width;
    }

    /**
     * Same as view.height, actual number of pixels in the canvas by vertical
     *
     * @member {number}
     * @readonly
     * @default 600
     */
    get height()
    {
        return this.view.height;
    }

    /**
     * Resizes the screen and canvas to the specified width and height
     * Canvas dimensions are multiplied by resolution
     *
     * @param {number} screenWidth - the new width of the screen
     * @param {number} screenHeight - the new height of the screen
     */
    resize(screenWidth, screenHeight)
    {
        this.screen.width = screenWidth;
        this.screen.height = screenHeight;

        this.view.width = screenWidth * this.resolution;
        this.view.height = screenHeight * this.resolution;

        if (this.autoResize)
        {
            this.view.style.width = `${screenWidth}px`;
            this.view.style.height = `${screenHeight}px`;
        }
    }

    /**
     * Useful function that returns a texture of the display object that can then be used to create sprites
     * This can be quite useful if your displayObject is complicated and needs to be reused multiple times.
     *
     * @param {PIXI.DisplayObject} displayObject - The displayObject the object will be generated from
     * @param {number} scaleMode - Should be one of the scaleMode consts
     * @param {number} resolution - The resolution / device pixel ratio of the texture being generated
     * @param {PIXI.Rectangle} [region] - The region of the displayObject, that shall be rendered,
     *        if no region is specified, defaults to the local bounds of the displayObject.
     * @return {PIXI.Texture} a texture of the graphics object
     */
    generateTexture(displayObject, scaleMode, resolution, region)
    {
        region = region || displayObject.getLocalBounds();

        const renderTexture = RenderTexture.create(region.width | 0, region.height | 0, scaleMode, resolution);

        tempMatrix.tx = -region.x;
        tempMatrix.ty = -region.y;

        this.render(displayObject, renderTexture, false, tempMatrix, true);

        return renderTexture;
    }

    /**
     * Removes everything from the renderer and optionally removes the Canvas DOM element.
     *
     * @param {boolean} [removeView=false] - Removes the Canvas element from the DOM.
     */
    destroy(removeView)
    {
        if (removeView && this.view.parentNode)
        {
            this.view.parentNode.removeChild(this.view);
        }

        this.type = RENDERER_TYPE.UNKNOWN;

        this.view = null;

        this.screen = null;

        this.resolution = 0;

        this.transparent = false;

        this.autoResize = false;

        this.blendModes = null;

        this.options = null;

        this.preserveDrawingBuffer = false;
        this.clearBeforeRender = false;

        this.roundPixels = false;

        this._backgroundColor = 0;
        this._backgroundColorRgba = null;
        this._backgroundColorString = null;

        this._tempDisplayObjectParent = null;
        this._lastObjectRendered = null;
    }

    /**
     * The background color to fill if not transparent
     *
     * @member {number}
     */
    get backgroundColor()
    {
        return this._backgroundColor;
    }

    set backgroundColor(value) // eslint-disable-line require-jsdoc
    {
        this._backgroundColor = value;
        this._backgroundColorString = hex2string(value);
        hex2rgb(value, this._backgroundColorRgba);
    }
}
<|endoftext|>


<commit_before>describe("better-dateinput-polyfill", function() {
    var calendar, dateinput, calendarCaption, calendarDays;

    beforeEach(function() {
        calendar = DOM.mock();
        calendarCaption = DOM.mock();
        calendarDays = DOM.mock();
        dateinput = DOM.mock("input[type=date]");

        spyOn(dateinput, "getData").andCallFake(function(key) {
            if (key === "calendar") return calendar;
            else if (key === "calendarCaption") return calendarCaption;
            else if (key === "calendarDays") return calendarDays;
        });
    });

    it("should toggle calendar visibility on enter key", function() {
        spyOn(dateinput, "getCalendarDate").andReturn(new Date());
        spyOn(dateinput, "get").andReturn("");

        var toggleSpy = spyOn(calendar, "toggle");

        dateinput.handleCalendarKeyDown(13, false);
        expect(toggleSpy).toHaveBeenCalled();
    });

    it("should hide calendar on escape key", function() {
        var spy = spyOn(calendar, "hide");

        dateinput.handleCalendarKeyDown(27, false);
        expect(spy).toHaveBeenCalled();
    });

    it("should prevent default action on any key except tab", function() {
        expect(dateinput.handleCalendarKeyDown(9, false)).not.toBe(false);
        expect(dateinput.handleCalendarKeyDown(111, false)).toBe(false);
        expect(dateinput.handleCalendarKeyDown(13, false)).toBe(false);
    });

    it("should reset calendar value on backspace or delete keys", function() {
        var spy = spyOn(dateinput, "set");

        spy.andCallFake(function(value) {
            expect(value).toBe("");

            return dateinput;
        });

        dateinput.handleCalendarKeyDown(8, false);
        expect(spy).toHaveBeenCalled();
        dateinput.handleCalendarKeyDown(46, false);
        expect(spy.callCount).toBe(2);
    });

    it("should handle arrow keys with optional shiftKey", function() {
        var now = new Date(),
            nowCopy = new Date(now.getTime()),
            getSpy = spyOn(dateinput, "getCalendarDate"),
            setSpy = spyOn(dateinput, "setCalendarDate").andReturn(dateinput),
            expectKey = function(key, altKey, expected) {
                getSpy.andReturn(new Date(now.getTime()));

                dateinput.handleCalendarKeyDown(key, altKey);
                expect(setSpy).toHaveBeenCalledWith(expected);
            };

        expectKey(74, false, new Date(now.getTime() + 604800000));
        expectKey(40, false, new Date(now.getTime() + 604800000));
        expectKey(75, false, new Date(now.getTime() - 604800000));
        expectKey(38, false, new Date(now.getTime() - 604800000));
        expectKey(76, false, new Date(now.getTime() + 86400000));
        expectKey(39, false, new Date(now.getTime() + 86400000));
        expectKey(72, false, new Date(now.getTime() - 86400000));
        expectKey(37, false, new Date(now.getTime() - 86400000));

        // cases with shift key
        nowCopy.setMonth(nowCopy.getMonth() + 1);
        expectKey(39, true, nowCopy);
        nowCopy.setMonth(nowCopy.getMonth() - 2);
        expectKey(37, true, nowCopy);
        nowCopy.setMonth(nowCopy.getMonth() + 1);
        nowCopy.setFullYear(nowCopy.getFullYear() + 1);
        expectKey(40, true, nowCopy);
        nowCopy.setFullYear(nowCopy.getFullYear() - 2);
        expectKey(38, true, nowCopy);
    });

    it("should change month on nav buttons click", function() {
        var now = new Date(),
            spy = spyOn(calendar, "hasClass"),
            getSpy = spyOn(dateinput, "getCalendarDate").andReturn(now),
            setSpy = spyOn(dateinput, "setCalendarDate").andReturn(dateinput);

        spy.andReturn(true);
        dateinput.handleCalendarNavClick(calendar);
        expect(spy).toHaveBeenCalled();
        expect(getSpy).toHaveBeenCalled();
        expect(setSpy).toHaveBeenCalledWith(new Date(now.getFullYear(), now.getMonth() + 1, 1));

        spy.andReturn(false);
        dateinput.handleCalendarNavClick(calendar);
        expect(spy).toHaveBeenCalled();
        expect(getSpy).toHaveBeenCalled();
        expect(setSpy).toHaveBeenCalledWith(new Date(now.getFullYear(), now.getMonth() - 1, 1));
    });

    it("should select appropriate day on calendar click", function() {
        var now = new Date(),
            target = DOM.mock(),
            parent = DOM.mock(),
            colSpy = spyOn(target, "get"),
            rowSpy = spyOn(parent, "get"),
            getSpy = spyOn(dateinput, "getCalendarDate"),
            setSpy = spyOn(dateinput, "setCalendarDate");

        spyOn(target, "parent").andReturn(parent);

        rowSpy.andReturn(2); // the third week of current month
        colSpy.andReturn(5); // the 5th day of the week
        getSpy.andReturn(now);
        dateinput.handleCalendarDayClick(target);
        expect(rowSpy).toHaveBeenCalled();
        expect(colSpy).toHaveBeenCalled();
        expect(getSpy).toHaveBeenCalled();

        now.setDate(1);

        expect(setSpy).toHaveBeenCalledWith(new Date(
            now.getFullYear(), now.getMonth(), (2 - 1) * 7 + (5 + 2) - now.getDay()));
    });

    it("should hide calendar on outer focus", function() {
        var focusedSpy = spyOn(dateinput, "isFocused"),
            hideSpy = spyOn(calendar, "hide");

        focusedSpy.andReturn(true);
        dateinput.handleDocumentClick();
        expect(hideSpy).not.toHaveBeenCalled();

        focusedSpy.andReturn(false);
        dateinput.handleDocumentClick();
        expect(hideSpy).toHaveBeenCalled();
    });

});
<commit_msg>trying to fix travis<commit_after>describe("better-dateinput-polyfill", function() {
    var calendar, dateinput, calendarCaption, calendarDays,
        DOM = window.DOM;

    beforeEach(function() {
        calendar = DOM.mock();
        calendarCaption = DOM.mock();
        calendarDays = DOM.mock();
        dateinput = DOM.mock("input[type=date]");

        spyOn(dateinput, "getData").andCallFake(function(key) {
            if (key === "calendar") return calendar;
            else if (key === "calendarCaption") return calendarCaption;
            else if (key === "calendarDays") return calendarDays;
        });
    });

    it("should toggle calendar visibility on enter key", function() {
        spyOn(dateinput, "getCalendarDate").andReturn(new Date());
        spyOn(dateinput, "get").andReturn("");

        var toggleSpy = spyOn(calendar, "toggle");

        dateinput.handleCalendarKeyDown(13, false);
        expect(toggleSpy).toHaveBeenCalled();
    });

    it("should hide calendar on escape key", function() {
        var spy = spyOn(calendar, "hide");

        dateinput.handleCalendarKeyDown(27, false);
        expect(spy).toHaveBeenCalled();
    });

    it("should prevent default action on any key except tab", function() {
        expect(dateinput.handleCalendarKeyDown(9, false)).not.toBe(false);
        expect(dateinput.handleCalendarKeyDown(111, false)).toBe(false);
        expect(dateinput.handleCalendarKeyDown(13, false)).toBe(false);
    });

    it("should reset calendar value on backspace or delete keys", function() {
        var spy = spyOn(dateinput, "set");

        spy.andCallFake(function(value) {
            expect(value).toBe("");

            return dateinput;
        });

        dateinput.handleCalendarKeyDown(8, false);
        expect(spy).toHaveBeenCalled();
        dateinput.handleCalendarKeyDown(46, false);
        expect(spy.callCount).toBe(2);
    });

    it("should handle arrow keys with optional shiftKey", function() {
        var now = new Date(),
            nowCopy = new Date(now.getTime()),
            getSpy = spyOn(dateinput, "getCalendarDate"),
            setSpy = spyOn(dateinput, "setCalendarDate").andReturn(dateinput),
            expectKey = function(key, altKey, expected) {
                getSpy.andReturn(new Date(now.getTime()));

                dateinput.handleCalendarKeyDown(key, altKey);
                expect(setSpy).toHaveBeenCalledWith(expected);
            };

        expectKey(74, false, new Date(now.getTime() + 604800000));
        expectKey(40, false, new Date(now.getTime() + 604800000));
        expectKey(75, false, new Date(now.getTime() - 604800000));
        expectKey(38, false, new Date(now.getTime() - 604800000));
        expectKey(76, false, new Date(now.getTime() + 86400000));
        expectKey(39, false, new Date(now.getTime() + 86400000));
        expectKey(72, false, new Date(now.getTime() - 86400000));
        expectKey(37, false, new Date(now.getTime() - 86400000));

        // cases with shift key
        nowCopy.setMonth(nowCopy.getMonth() + 1);
        expectKey(39, true, nowCopy);
        nowCopy.setMonth(nowCopy.getMonth() - 2);
        expectKey(37, true, nowCopy);
        nowCopy.setMonth(nowCopy.getMonth() + 1);
        nowCopy.setFullYear(nowCopy.getFullYear() + 1);
        expectKey(40, true, nowCopy);
        nowCopy.setFullYear(nowCopy.getFullYear() - 2);
        expectKey(38, true, nowCopy);
    });

    it("should change month on nav buttons click", function() {
        var now = new Date(),
            spy = spyOn(calendar, "hasClass"),
            getSpy = spyOn(dateinput, "getCalendarDate").andReturn(now),
            setSpy = spyOn(dateinput, "setCalendarDate").andReturn(dateinput);

        spy.andReturn(true);
        dateinput.handleCalendarNavClick(calendar);
        expect(spy).toHaveBeenCalled();
        expect(getSpy).toHaveBeenCalled();
        expect(setSpy).toHaveBeenCalledWith(new Date(now.getFullYear(), now.getMonth() + 1, 1));

        spy.andReturn(false);
        dateinput.handleCalendarNavClick(calendar);
        expect(spy).toHaveBeenCalled();
        expect(getSpy).toHaveBeenCalled();
        expect(setSpy).toHaveBeenCalledWith(new Date(now.getFullYear(), now.getMonth() - 1, 1));
    });

    it("should select appropriate day on calendar click", function() {
        var now = new Date(),
            target = DOM.mock(),
            parent = DOM.mock(),
            colSpy = spyOn(target, "get"),
            rowSpy = spyOn(parent, "get"),
            getSpy = spyOn(dateinput, "getCalendarDate"),
            setSpy = spyOn(dateinput, "setCalendarDate");

        spyOn(target, "parent").andReturn(parent);

        rowSpy.andReturn(2); // the third week of current month
        colSpy.andReturn(5); // the 5th day of the week
        getSpy.andReturn(now);
        dateinput.handleCalendarDayClick(target);
        expect(rowSpy).toHaveBeenCalled();
        expect(colSpy).toHaveBeenCalled();
        expect(getSpy).toHaveBeenCalled();

        now.setDate(1);

        expect(setSpy).toHaveBeenCalledWith(new Date(
            now.getFullYear(), now.getMonth(), (2 - 1) * 7 + (5 + 2) - now.getDay()));
    });

    it("should hide calendar on outer focus", function() {
        var focusedSpy = spyOn(dateinput, "isFocused"),
            hideSpy = spyOn(calendar, "hide");

        focusedSpy.andReturn(true);
        dateinput.handleDocumentClick();
        expect(hideSpy).not.toHaveBeenCalled();

        focusedSpy.andReturn(false);
        dateinput.handleDocumentClick();
        expect(hideSpy).toHaveBeenCalled();
    });

});
<|endoftext|>


<commit_before>module.exports = [
	[/Module parse failed/, /dump-file\.txt/, /templates sync \^\\\.\\\/\.\*\$/],
	[/Critical dependency/, /templateLoader\.js/],
	[/Critical dependency/, /templateLoaderIndirect\.js/],
	[/Critical dependency/, /templateLoaderIndirect\.js/],
];
<commit_msg>be less strict in test case<commit_after>module.exports = [
	[/Module parse failed/, /dump-file\.txt/, /templates sync/],
	[/Critical dependency/, /templateLoader\.js/],
	[/Critical dependency/, /templateLoaderIndirect\.js/],
	[/Critical dependency/, /templateLoaderIndirect\.js/],
];
<|endoftext|>


<commit_before>var _ = require("lodash");
var should = require("should");

var daily = require("../../../controllers/crawler/daily");
var dbhelper = require("../../../controllers/dbhelper");
var utils = require("../../../controllers/utils");

describe("controllers/crawler/daily", function ()
{
    before(function (done)
    {
        if (dbhelper.connected())
        {
            dbhelper.dropAllCollections(done);
        }
        else
        {
            dbhelper.connect(function (err)
            {
                should.not.exist(err);
                dbhelper.dropAllCollections(done);
            });
        }
    });

    describe("1.fetchLatestStoryIndexes", function ()
    {
        it("should fetch the latest story indexes", function (done)
        {
            daily.fetchLatestStoryIndexes(function (err, res)
            {
                should.not.exist(err);
                res.date.should.equal(utils.convertToZhihuDate(new Date()));
                done();
            });
        });
    });

    describe("2.fetchStoryIndexes", function ()
    {
        it("should fetch the story indexes of date: 20130519", function (done)
        {
            var date = "20130519"
            var target = {
                date: "20130519",
                indexes: [401, 396, 395, 394, 390, 388]
            };
            daily.fetchStoryIndexes(date, function (err, res)
            {
                should.not.exist(err);
                res.date.should.equal(date);
                res.should.deepEqual(target);
                done();
            });
        });

        it("should not fetch the story indexes of date: 20130518", function (done)
        {
            var date = "20130518"
            var target = {};
            daily.fetchStoryIndexes(date, function (err, res)
            {
                should.not.exist(err);
                res.should.deepEqual(target);
                done();
            });
        });

        it("should not fetch the story indexes of date: 20133030", function (done)
        {
            var date = "20133030"
            daily.fetchStoryIndexes(date, function (err, res)
            {
                should.exist(err);
                done();
            });
        });
    });

    describe("3.fetchStory", function ()
    {
        it("should fetch the story of id: 401", function (done)
        {
            var id = 401;
            var title = "学英语才是正经事儿";
            var imageSource = "人民教育出版社";
            var shareURL = "http://daily.zhihu.com/story/401";
            daily.fetchStory(id, function (err, res)
            {
                should.not.exist(err);
                res.id.should.equal(id);
                res.title.should.equal(title);
                res.imageSource.should.equal(imageSource);
                res.shareURL.should.equal(shareURL);
                done();
            });
        });
    });

    describe("4.cacheStory", function ()
    {
        var id = 401;
        it("should cache the story of id: " + id, function (done)
        {
            daily.cacheStory(id, function (err, res)
            {
                should.not.exist(err);
                res.id.should.equal(id);
                res.cached.should.be.true();
                done();
            });
        });
    });

    describe("5.fetchStories", function ()
    {
        var date = "20130519";
        it("should fetch the stories of date: " + date, function (done)
        {
            daily.cacheStories(date, function (err, res)
            {
                should.not.exist(err);
                done();
            });
        });
    });
});
<commit_msg>update<commit_after>var _ = require("lodash");
var should = require("should");

var daily = require("../../../controllers/crawler/daily");
var dbhelper = require("../../../controllers/dbhelper");
var utils = require("../../../controllers/utils");

describe("controllers/crawler/daily", function ()
{
    before(function (done)
    {
        if (dbhelper.connected())
        {
            dbhelper.dropAllCollections(done);
        }
        else
        {
            dbhelper.connect(function (err)
            {
                should.not.exist(err);
                dbhelper.dropAllCollections(done);
            });
        }
    });

    describe("1.fetchLatestStoryIDs", function ()
    {
        it("should fetch the latest story IDs", function (done)
        {
            daily.fetchLatestStoryIDs(function (err, res)
            {
                should.not.exist(err);
                res.date.should.equal(utils.convertToZhihuDate(new Date()));
                done();
            });
        });
    });

    describe("2.fetchStoryIDs", function ()
    {
        it("should fetch the story IDs of date: 20130519", function (done)
        {
            var date = "20130519"
            var target = {
                date: "20130519",
                ids: [401, 396, 395, 394, 390, 388]
            };
            daily.fetchStoryIDs(date, function (err, res)
            {
                should.not.exist(err);
                res.date.should.equal(date);
                res.should.deepEqual(target);
                done();
            });
        });

        it("should not fetch the story IDs of date: 20130518", function (done)
        {
            var date = "20130518"
            var target = {};
            daily.fetchStoryIDs(date, function (err, res)
            {
                should.not.exist(err);
                res.should.deepEqual(target);
                done();
            });
        });

        it("should not fetch the story IDs of date: 20133030", function (done)
        {
            var date = "20133030"
            daily.fetchStoryIDs(date, function (err, res)
            {
                should.exist(err);
                done();
            });
        });
    });

    describe("3.fetchStory", function ()
    {
        it("should fetch the story of id: 401", function (done)
        {
            var id = 401;
            var title = "学英语才是正经事儿";
            var imageSource = "人民教育出版社";
            var shareURL = "http://daily.zhihu.com/story/401";
            daily.fetchStory(id, function (err, res)
            {
                should.not.exist(err);
                res.id.should.equal(id);
                res.title.should.equal(title);
                res.imageSource.should.equal(imageSource);
                res.shareURL.should.equal(shareURL);
                done();
            });
        });
    });

    describe("4.cacheStory", function ()
    {
        var id = 401;
        var date = "20130520";
        it("should cache the story of id: " + id, function (done)
        {
            daily.cacheStory(id, date, function (err, res)
            {
                should.not.exist(err);
                res.id.should.equal(id);
                res.date.should.equal(date);
                res.cached.should.be.true();
                done();
            });
        });
    });

    describe("5.cacheLatestStories", function ()
    {
        var date = "20130519";
        it("should cache the latest stories", function (done)
        {
            daily.cacheLatestStories(function (err, res)
            {
                should.not.exist(err);
                done();
            });
        });
    });

    describe("6.cacheStoriesOfDate", function ()
    {
        var date = "20130519";
        it("should cache the stories of date: " + date, function (done)
        {
            daily.cacheStoriesOfDate(date, function (err, res)
            {
                should.not.exist(err);
                done();
            });
        });
    });

    describe("7.cacheStories", function ()
    {
        var date = "20130519";
        it("should cache the stories of date: " + date + " and  IDs", function (done)
        {
            daily.fetchStoryIDs(date, function (err, res)
            {
                should.not.exist(err);
                daily.cacheStories(res.ids, date, function (err, res)
                {
                    should.not.exist(err);
                    done();
                });
            });
        });
    });
});
<|endoftext|>


<commit_before>/*    Copyright 2021 Firewalla LLC
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
'use strict';

const log = require('../net2/logger.js')(__filename);

const Sensor = require('./Sensor.js').Sensor;

const f = require('../net2/Firewalla.js');

const userConfigFolder = f.getUserConfigFolder();
const dnsmasqConfigFolder = `${userConfigFolder}/dnsmasq`;
const systemConfigFile = `${dnsmasqConfigFolder}/clash_system.conf`;

const fs = require('fs');
const Promise = require('bluebird');
Promise.promisifyAll(fs);

const DNSMASQ = require('../extension/dnsmasq/dnsmasq.js');
const dnsmasq = new DNSMASQ();

const exec = require('child-process-promise').exec;

const sysManager = require('../net2/SysManager.js');

const extensionManager = require('./ExtensionManager.js');

const featureName = "clash";
const policyKeyName = "clash";

const clash = require('../extension/clash_tun/clash_tun.js');

const platformLoader = require('../platform/PlatformLoader.js');
const platform = platformLoader.getPlatform();

class ClashPlugin extends Sensor {
  async run() {
    if(platform.getName() !== 'gold') {
      return;
    }

    this.adminSystemSwitch = false;
    await exec(`mkdir -p ${dnsmasqConfigFolder}`);
    extensionManager.registerExtension(policyKeyName, this, {
      applyPolicy: this.applyPolicy
    });

    this.hookFeature(featureName);

  }

  async applyAll(options = {}) {
    log.info("Applying...");
    const config = await this.getFeatureConfig();
    clash.config = Object.assign({}, config,  {dns: sysManager.myDefaultDns()});
    await clash.start();
    this.ready = true;

    await this.applyClash();
  }

  async applyPolicy(host, ip, policy) {
    log.info("Applying clash policy:", ip, policy);
    if (ip === '0.0.0.0') {
      // not supported
      return;
    }

    if (!host)
      return;

    // only support Host
    if (host.constructor.name !== "Host") {
      return;
    }

    const macAddress = host && host.o && host.o.mac;
    if (!macAddress) {
      return;
    }

    if (policy === false) {
      await exec(`sudo ipset add fw_clash_whitelist_mac ${macAddress}`);
    } else {
      await exec(`sudo ipset del fw_clash_whitelist_mac ${macAddress}`);
    }
  }

  async applyClash() {
    if (!this.ready) {
      log.info("Service clash is not ready.");
      return;
    }

    if (this.adminSystemSwitch) {
      return this.systemStart();
    } else {
      return this.systemStop();
    }
  }

  async systemStart() {
    log.info("Starting Clash at global level...");
    const entry = "server=127.0.0.1#9953\n";
    await fs.writeFileAsync(systemConfigFile, entry);
    await dnsmasq.scheduleRestartDNSService();

    await clash.redirectTraffic();
  }

  async systemStop() {
    log.info("Stopping Clash at global level...");
    await fs.unlinkAsync(systemConfigFile).catch(() => undefined);
    dnsmasq.scheduleRestartDNSService();

    await clash.stop();
  }

  // global on/off
  async globalOn(options) {
    this.adminSystemSwitch = true;
    await this.applyAll(options);
  }

  async globalOff() {
    this.adminSystemSwitch = false;
    await clash.stop();
    await this.applyClash();
  }

}

module.exports = ClashPlugin;
<commit_msg>bug fix<commit_after>/*    Copyright 2021 Firewalla LLC
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
'use strict';

const log = require('../net2/logger.js')(__filename);

const Sensor = require('./Sensor.js').Sensor;

const f = require('../net2/Firewalla.js');

const userConfigFolder = f.getUserConfigFolder();
const dnsmasqConfigFolder = `${userConfigFolder}/dnsmasq`;
const systemConfigFile = `${dnsmasqConfigFolder}/clash_system.conf`;

const fs = require('fs');
const Promise = require('bluebird');
Promise.promisifyAll(fs);

const DNSMASQ = require('../extension/dnsmasq/dnsmasq.js');
const dnsmasq = new DNSMASQ();

const exec = require('child-process-promise').exec;

const sysManager = require('../net2/SysManager.js');

const extensionManager = require('./ExtensionManager.js');

const featureName = "clash";
const policyKeyName = "clash";

const clash = require('../extension/clash_tun/clash_tun.js');

const platformLoader = require('../platform/PlatformLoader.js');
const platform = platformLoader.getPlatform();

class ClashPlugin extends Sensor {
  async run() {
    if(platform.getName() !== 'gold') {
      return;
    }

    this.adminSystemSwitch = false;
    await exec(`mkdir -p ${dnsmasqConfigFolder}`);
    extensionManager.registerExtension(policyKeyName, this, {
      applyPolicy: this.applyPolicy
    });

    this.hookFeature(featureName);

  }

  async applyAll(options = {}) {
    log.info("Applying...");
    const config = await this.getFeatureConfig();
    clash.config = Object.assign({}, config,  {dns: sysManager.myDefaultDns()});
    await clash.start();
    this.ready = true;

    await this.applyClash();
  }

  async applyPolicy(host, ip, policy) {
    log.info("Applying clash policy:", ip, policy);
    if (ip === '0.0.0.0') {
      // not supported
      return;
    }

    if (!host)
      return;

    // only support Host
    if (host.constructor.name !== "Host") {
      return;
    }

    const macAddress = host && host.o && host.o.mac;
    if (!macAddress) {
      return;
    }

    if (policy === false) {
      await exec(`sudo ipset -! add fw_clash_whitelist_mac ${macAddress}`).catch(() => {});
    } else {
      await exec(`sudo ipset -! del fw_clash_whitelist_mac ${macAddress}`).catch(() => {});
    }
  }

  async applyClash() {
    if (!this.ready) {
      log.info("Service clash is not ready.");
      return;
    }

    if (this.adminSystemSwitch) {
      return this.systemStart();
    } else {
      return this.systemStop();
    }
  }

  async systemStart() {
    log.info("Starting Clash at global level...");
    const entry = "server=127.0.0.1#9953\n";
    await fs.writeFileAsync(systemConfigFile, entry);
    await dnsmasq.scheduleRestartDNSService();

    await clash.redirectTraffic();
  }

  async systemStop() {
    log.info("Stopping Clash at global level...");
    await fs.unlinkAsync(systemConfigFile).catch(() => undefined);
    dnsmasq.scheduleRestartDNSService();

    await clash.stop();
  }

  // global on/off
  async globalOn(options) {
    this.adminSystemSwitch = true;
    await this.applyAll(options);
  }

  async globalOff() {
    this.adminSystemSwitch = false;
    await clash.stop();
    await this.applyClash();
  }

}

module.exports = ClashPlugin;
<|endoftext|>


<commit_before><commit_msg>Update minified version<commit_after><|endoftext|>


<commit_before>var path = require('path');
var express = require('express');
var webpack = require('webpack');
var config = require('./webpack-development.config');
var port = process.env.PORT || 8080;
var app = express();
var compiler = webpack(config);

app.use('/', express.static(path.join(__dirname, 'assets')));

app.use(require('webpack-dev-middleware')(compiler, {
    quiet: true,
    noInfo: true,
    publicPath: config.output.publicPath
}));

app.use(require("webpack-hot-middleware")(compiler, {
    log: console.log,
    path: '/__webpack_hmr',
    heartbeat: 10 * 1000
}));

app.get('*', function (req, res) {
    res.sendFile(path.join(__dirname, 'index.html'));
});

app.listen(port, 'localhost', function (err) {
    if (err) {
        console.log(err);
        return;
    }
    console.log('Listening at http://localhost:' + port);
});<commit_msg>code: update webpack config<commit_after>var path = require('path');
var express = require('express');
var webpack = require('webpack');
var config = require('./webpack.dev');
var port = process.env.PORT || 8080;
var app = express();
var compiler = webpack(config);

app.use('/', express.static(path.join(__dirname, 'assets')));

app.use(require('webpack-dev-middleware')(compiler, {
    quiet: true,
    noInfo: true,
    publicPath: config.output.publicPath
}));

app.use(require("webpack-hot-middleware")(compiler, {
    log: console.log,
    path: '/__webpack_hmr',
    heartbeat: 10 * 1000
}));

app.get('*', function (req, res) {
    res.sendFile(path.join(__dirname, 'index.html'));
});

app.listen(port, 'localhost', function (err) {
    if (err) {
        console.log(err);
        return;
    }
    console.log('Listening at http://localhost:' + port);
});<|endoftext|>


<commit_before>/*global artoo*/

;(function($) {
	'use strict';

	var firstPage;
	var throttle = artoo.settings.throttle || 5000;

	var scraper = {
		iterator: '.wanted',
		data: {
			first_name: {
				sel: '.titre',
				method: function($) {
					var html = $(this).html().trim();

					return html.substr(html.indexOf('
') + 4);
				}
			},
			last_name: {
				sel: '.titre',
				method: function($) {
					var html = $(this).html().trim();

					return html.substr(0, html.indexOf('
'));
				}
			},
			url: {
				sel: '.links a.details',
				method: function($) {

					// Get the full URL.
					return this.href;
				}
			}
		}
	};

	var nextUrl = function($page) {
		return $page.find('.pagenavigator .select').next('.other').find('a').attr('href');
	};

	artoo.log.debug('Starting the scraper...');
	firstPage = artoo.scrape(scraper);

	artoo.ajaxSpider(
		function(i, $data) {
			var url = nextUrl(!i ? artoo.$(document) : $data);

			artoo.log.debug('Scraping URL "' + url + '"...');
			return url;
		},
		{
			scrape: scraper,
			concat: true,
			throttle: throttle
		},
		function(data) {
			artoo.log.debug('Finished retrieving data. Downloading...');

			artoo.saveCsv(firstPage.concat(data), {
				filename: 'interpol.csv'
			});
		}
	);

})(this, artoo.$);
<commit_msg>Only extract path<commit_after>/*global artoo*/

;(function($) {
	'use strict';

	var firstPage;
	var throttle = artoo.settings.throttle || 5000;

	var scraper = {
		iterator: '.wanted',
		data: {
			first_name: {
				sel: '.titre',
				method: function($) {
					var html = $(this).html().trim();

					return html.substr(html.indexOf('
') + 4);
				}
			},
			last_name: {
				sel: '.titre',
				method: function($) {
					var html = $(this).html().trim();

					return html.substr(0, html.indexOf('
'));
				}
			},
			url: {
				sel: '.links a.details',
				attr: 'href'
			}
		}
	};

	var nextUrl = function($page) {
		return $page.find('.pagenavigator .select').next('.other').find('a').attr('href');
	};

	artoo.log.debug('Starting the scraper...');
	firstPage = artoo.scrape(scraper);

	artoo.ajaxSpider(
		function(i, $data) {
			var url = nextUrl(!i ? artoo.$(document) : $data);

			artoo.log.debug('Scraping URL "' + url + '"...');
			return url;
		},
		{
			scrape: scraper,
			concat: true,
			throttle: throttle
		},
		function(data) {
			artoo.log.debug('Finished retrieving data. Downloading...');

			artoo.saveCsv(firstPage.concat(data), {
				filename: 'interpol.csv'
			});
		}
	);

})(this, artoo.$);
<|endoftext|>