<commit_before>/*
 * Copyright (C) 2019 - present Instructure, Inc.
 *
 * This file is part of Canvas.
 *
 * Canvas is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, version 3 of the License.
 *
 * Canvas 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/>.
 */

import {AlertManagerContext} from '../../../../shared/components/AlertManager'
import {Assignment} from '../../graphqlData/Assignment'
import {chunk} from 'lodash'
import {DEFAULT_ICON} from '../../../../shared/helpers/mimeClassIconHelper'
import elideString from '../../../../shared/helpers/elideString'
import {func} from 'prop-types'
import {getFileThumbnail} from '../../../../shared/helpers/fileHelper'
import I18n from 'i18n!assignments_2_file_upload'
import LoadingIndicator from '../../../shared/LoadingIndicator'
import MoreOptions from './MoreOptions'
import React, {Component} from 'react'
import {Submission} from '../../graphqlData/Submission'
import {uploadFiles} from '../../../../shared/upload_file'

import {Billboard} from '@instructure/ui-billboard'
import {Button} from '@instructure/ui-buttons'
import {FileDrop} from '@instructure/ui-forms'
import {Flex, Grid} from '@instructure/ui-layout'
import {IconTrashLine} from '@instructure/ui-icons'
import {ScreenReaderContent} from '@instructure/ui-a11y'
import {Text} from '@instructure/ui-elements'
import theme from '@instructure/canvas-theme'

function submissionFileUploadUrl(assignment) {
  return `/api/v1/courses/${assignment.env.courseId}/assignments/${assignment._id}/submissions/${assignment.env.currentUser.id}/files`
}

export default class FileUpload extends Component {
  static propTypes = {
    assignment: Assignment.shape,
    createSubmissionDraft: func,
    submission: Submission.shape,
    updateUploadingFiles: func
  }

  state = {
    filesToUpload: [],
    messages: []
  }

  _isMounted = false

  componentDidMount() {
    this._isMounted = true
    window.addEventListener('message', this.handleLTIFiles)
  }

  componentWillUnmount() {
    this._isMounted = false
    window.removeEventListener('message', this.handleLTIFiles)
  }

  getDraftAttachments = () => {
    return this.props.submission.submissionDraft &&
      this.props.submission.submissionDraft.attachments
      ? this.props.submission.submissionDraft.attachments
      : []
  }

  handleLTIFiles = async e => {
    if (
      e.data.messageType === 'LtiDeepLinkingResponse' ||
      e.data.messageType === 'A2ExternalContentReady'
    ) {
      await this.handleDropAccepted(e.data.content_items)
    }
  }

  handleCanvasFiles = async fileID => {
    if (!fileID) {
      this.context.setOnFailure(I18n.t('Error adding canvas file to submission draft'))
      return
    }
    this.updateUploadingFiles(async () => {
      try {
        await this.createSubmissionDraft([fileID])
      } catch (err) {
        this.context.setOnFailure(I18n.t('Error updating submission draft'))
      }
    })
  }

  handleDropAccepted = async files => {
    if (!files.length) {
      this.context.setOnFailure(I18n.t('Error adding files to submission draft'))
      return
    }
    this.setState({
      filesToUpload: files.map(() => {
        return {isLoading: true}
      })
    })
    this.updateUploadingFiles(async () => {
      try {
        const newFiles = await uploadFiles(files, submissionFileUploadUrl(this.props.assignment))
        await this.createSubmissionDraft(newFiles.map(file => file.id))
      } catch (err) {
        this.context.setOnFailure(I18n.t('Error updating submission draft'))
      } finally {
        this.setState({filesToUpload: []})
      }
    })
  }

  handleDropRejected = () => {
    this.setState({
      messages: [
        {
          text: I18n.t('Invalid file type'),
          type: 'error'
        }
      ]
    })
  }

  updateUploadingFiles = async wrappedFunc => {
    if (this._isMounted) {
      this.props.updateUploadingFiles(true)
    }
    await wrappedFunc()
    if (this._isMounted) {
      this.props.updateUploadingFiles(false)
    }
  }

  createSubmissionDraft = async fileIDs => {
    await this.props.createSubmissionDraft({
      variables: {
        id: this.props.submission.id,
        activeSubmissionType: 'online_upload',
        attempt: this.props.submission.attempt || 1,
        fileIds: this.getDraftAttachments()
          .map(file => file._id)
          .concat(fileIDs)
      }
    })
  }

  handleRemoveFile = async e => {
    const fileId = parseInt(e.currentTarget.id, 10)
    const fileIndex = this.getDraftAttachments().findIndex(
      file => parseInt(file._id, 10) === fileId
    )

    const updatedFiles = this.getDraftAttachments().filter((_, i) => i !== fileIndex)
    await this.props.createSubmissionDraft({
      variables: {
        id: this.props.submission.id,
        activeSubmissionType: 'online_upload',
        attempt: this.props.submission.attempt,
        fileIds: updatedFiles.map(file => file._id)
      }
    })

    if (this._isMounted) {
      this.setState({
        messages: []
      })
    }

    const focusElement =
      this.getDraftAttachments().length === 0 || fileIndex === 0
        ? 'inputFileDrop'
        : this.getDraftAttachments()[fileIndex - 1]._id

    // TODO: this could break if there is ever another element in the dom that
    //       shares an id. As we are using _id (ie, '4') as the id, it's not
    //       exactly a great unique id. Should probably swap to using refs here.
    document.getElementById(focusElement).focus()
  }

  renderUploadBox() {
    return (

        <Flex direction="column">
          <Flex.Item margin="0 0 small 0" overflowY="visible">
            <FileDrop
              accept={
                this.props.assignment.allowedExtensions.length
                  ? this.props.assignment.allowedExtensions
                  : ''
              }
              allowMultiple
              enablePreview
              id="inputFileDrop"
              data-testid="input-file-drop"
              label={
                <Billboard
                  heading={I18n.t('Upload File')}
                  hero={DEFAULT_ICON}
                  message={
                    <Flex direction="column">
                      {this.props.assignment.allowedExtensions.length ? (
                        <Flex.Item>
                          {I18n.t('File permitted: %{fileTypes}', {
                            fileTypes: this.props.assignment.allowedExtensions
                              .map(ext => ext.toUpperCase())
                              .join(', ')
                          })}
                        </Flex.Item>
                      ) : null}
                      <Flex.Item padding="small 0 0">
                        <Text size="small">
                          {I18n.t('Drag and drop, or click to browse your computer')}
                        </Text>
                      </Flex.Item>
                    </Flex>
                  }
                />
              }
              messages={this.state.messages}
              onDropAccepted={files => this.handleDropAccepted(files)}
              onDropRejected={this.handleDropRejected}
            />
          </Flex.Item>
          <Flex.Item padding="xx-small" textAlign="center">
            <MoreOptions
              assignmentID={this.props.assignment._id}
              courseID={this.props.assignment.env.courseId}
              handleCanvasFiles={this.handleCanvasFiles}
              renderCanvasFiles
              userID={this.props.assignment.env.currentUser.id}
            />
          </Flex.Item>
        </Flex>

    )
  }

  renderUploadedFile(file) {
    if (file.isLoading) {
      return <LoadingIndicator />
    }
    return (
      <Billboard
        heading={I18n.t('Uploaded')}
        headingLevel="h3"
        hero={getFileThumbnail(file, 'large')}
        message={

              {elideString(file.displayName)}

            <ScreenReaderContent>{file.displayName}</ScreenReaderContent>
            <Button
              icon={IconTrashLine}
              id={file._id}
              margin="0 0 0 x-small"
              onClick={this.handleRemoveFile}
              size="small"
            >
              <ScreenReaderContent>
                {I18n.t('Remove %{filename}', {filename: file.displayName})}
              </ScreenReaderContent>
            </Button>

        }
      />
    )
  }

  renderUploadBoxAndUploadedFiles() {
    let files = this.getDraftAttachments()
    if (this.state.filesToUpload.length) {
      files = files.concat(this.state.filesToUpload)
    }
    // The first two uploaded files are rendered on the same row as the upload box
    const firstFileRow = files.slice(0, 2)
    // All uploaded files after the first two are rendered on rows below the upload
    // box; thus, each row has three columns, with the first row having an upload box
    // and two rendered files and all subsequent rows having three rendered files
    const nextFileRows = files.length > 2 ? chunk(files.slice(2, files.length), 3) : []
    return (

        <Grid>
          <Grid.Row key={firstFileRow.map(file => file._id).join()}>
            <Grid.Col width={4}>{this.renderUploadBox()}</Grid.Col>
            {firstFileRow.map(file => (
              <Grid.Col width={4} key={file._id} vAlign="bottom">
                {this.renderUploadedFile(file)}
              </Grid.Col>
            ))}
          </Grid.Row>
          {nextFileRows.map(row => (
            <Grid.Row key={row.map(file => file._id).join()}>
              {row.map(file => (
                <Grid.Col width={4} key={file._id} vAlign="bottom">
                  {this.renderUploadedFile(file)}
                </Grid.Col>
              ))}
            </Grid.Row>
          ))}
        </Grid>

    )
  }

  render() {
    return (

        {this.getDraftAttachments().length !== 0 ? (
          this.renderUploadBoxAndUploadedFiles()
        ) : (
          <Grid>
            <Grid.Row>
              <Grid.Col width={4}>{this.renderUploadBox()}</Grid.Col>
            </Grid.Row>
          </Grid>
        )}

    )
  }
}

FileUpload.contextType = AlertManagerContext
<commit_msg>ensure the loading indicator displays for file upload<commit_after>/*
 * Copyright (C) 2019 - present Instructure, Inc.
 *
 * This file is part of Canvas.
 *
 * Canvas is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, version 3 of the License.
 *
 * Canvas 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/>.
 */

import {AlertManagerContext} from '../../../../shared/components/AlertManager'
import {Assignment} from '../../graphqlData/Assignment'
import {chunk} from 'lodash'
import {DEFAULT_ICON} from '../../../../shared/helpers/mimeClassIconHelper'
import elideString from '../../../../shared/helpers/elideString'
import {func} from 'prop-types'
import {getFileThumbnail} from '../../../../shared/helpers/fileHelper'
import I18n from 'i18n!assignments_2_file_upload'
import LoadingIndicator from '../../../shared/LoadingIndicator'
import MoreOptions from './MoreOptions'
import React, {Component} from 'react'
import {Submission} from '../../graphqlData/Submission'
import {uploadFiles} from '../../../../shared/upload_file'

import {Billboard} from '@instructure/ui-billboard'
import {Button} from '@instructure/ui-buttons'
import {FileDrop} from '@instructure/ui-forms'
import {Flex, Grid} from '@instructure/ui-layout'
import {IconTrashLine} from '@instructure/ui-icons'
import {ScreenReaderContent} from '@instructure/ui-a11y'
import {Text} from '@instructure/ui-elements'
import theme from '@instructure/canvas-theme'

function submissionFileUploadUrl(assignment) {
  return `/api/v1/courses/${assignment.env.courseId}/assignments/${assignment._id}/submissions/${assignment.env.currentUser.id}/files`
}

export default class FileUpload extends Component {
  static propTypes = {
    assignment: Assignment.shape,
    createSubmissionDraft: func,
    submission: Submission.shape,
    updateUploadingFiles: func
  }

  state = {
    filesToUpload: [],
    messages: []
  }

  _isMounted = false

  componentDidMount() {
    this._isMounted = true
    window.addEventListener('message', this.handleLTIFiles)
  }

  componentWillUnmount() {
    this._isMounted = false
    window.removeEventListener('message', this.handleLTIFiles)
  }

  getDraftAttachments = () => {
    return this.props.submission.submissionDraft &&
      this.props.submission.submissionDraft.attachments
      ? this.props.submission.submissionDraft.attachments
      : []
  }

  handleLTIFiles = async e => {
    if (
      e.data.messageType === 'LtiDeepLinkingResponse' ||
      e.data.messageType === 'A2ExternalContentReady'
    ) {
      await this.handleDropAccepted(e.data.content_items)
    }
  }

  handleCanvasFiles = async fileID => {
    if (!fileID) {
      this.context.setOnFailure(I18n.t('Error adding canvas file to submission draft'))
      return
    }
    this.updateUploadingFiles(async () => {
      try {
        await this.createSubmissionDraft([fileID])
      } catch (err) {
        this.context.setOnFailure(I18n.t('Error updating submission draft'))
      }
    })
  }

  handleDropAccepted = async files => {
    if (!files.length) {
      this.context.setOnFailure(I18n.t('Error adding files to submission draft'))
      return
    }

    this.setState({
      filesToUpload: files.map(file => {
        if (file.url) {
          return {isLoading: true, _id: file.url}
        }
        return {isLoading: true, _id: file.name}
      })
    })
    this.updateUploadingFiles(async () => {
      try {
        const newFiles = await uploadFiles(files, submissionFileUploadUrl(this.props.assignment))
        await this.createSubmissionDraft(newFiles.map(file => file.id))
      } catch (err) {
        this.context.setOnFailure(I18n.t('Error updating submission draft'))
      } finally {
        this.setState({filesToUpload: []})
      }
    })
  }

  handleDropRejected = () => {
    this.setState({
      messages: [
        {
          text: I18n.t('Invalid file type'),
          type: 'error'
        }
      ]
    })
  }

  updateUploadingFiles = async wrappedFunc => {
    if (this._isMounted) {
      this.props.updateUploadingFiles(true)
    }
    await wrappedFunc()
    if (this._isMounted) {
      this.props.updateUploadingFiles(false)
    }
  }

  createSubmissionDraft = async fileIDs => {
    await this.props.createSubmissionDraft({
      variables: {
        id: this.props.submission.id,
        activeSubmissionType: 'online_upload',
        attempt: this.props.submission.attempt || 1,
        fileIds: this.getDraftAttachments()
          .map(file => file._id)
          .concat(fileIDs)
      }
    })
  }

  handleRemoveFile = async e => {
    const fileId = parseInt(e.currentTarget.id, 10)
    const fileIndex = this.getDraftAttachments().findIndex(
      file => parseInt(file._id, 10) === fileId
    )

    const updatedFiles = this.getDraftAttachments().filter((_, i) => i !== fileIndex)
    await this.props.createSubmissionDraft({
      variables: {
        id: this.props.submission.id,
        activeSubmissionType: 'online_upload',
        attempt: this.props.submission.attempt,
        fileIds: updatedFiles.map(file => file._id)
      }
    })

    if (this._isMounted) {
      this.setState({
        messages: []
      })
    }

    const focusElement =
      this.getDraftAttachments().length === 0 || fileIndex === 0
        ? 'inputFileDrop'
        : this.getDraftAttachments()[fileIndex - 1]._id

    // TODO: this could break if there is ever another element in the dom that
    //       shares an id. As we are using _id (ie, '4') as the id, it's not
    //       exactly a great unique id. Should probably swap to using refs here.
    document.getElementById(focusElement).focus()
  }

  renderUploadBox() {
    return (

        <Flex direction="column">
          <Flex.Item margin="0 0 small 0" overflowY="visible">
            <FileDrop
              accept={
                this.props.assignment.allowedExtensions.length
                  ? this.props.assignment.allowedExtensions
                  : ''
              }
              allowMultiple
              enablePreview
              id="inputFileDrop"
              data-testid="input-file-drop"
              label={
                <Billboard
                  heading={I18n.t('Upload File')}
                  hero={DEFAULT_ICON}
                  message={
                    <Flex direction="column">
                      {this.props.assignment.allowedExtensions.length ? (
                        <Flex.Item>
                          {I18n.t('File permitted: %{fileTypes}', {
                            fileTypes: this.props.assignment.allowedExtensions
                              .map(ext => ext.toUpperCase())
                              .join(', ')
                          })}
                        </Flex.Item>
                      ) : null}
                      <Flex.Item padding="small 0 0">
                        <Text size="small">
                          {I18n.t('Drag and drop, or click to browse your computer')}
                        </Text>
                      </Flex.Item>
                    </Flex>
                  }
                />
              }
              messages={this.state.messages}
              onDropAccepted={files => this.handleDropAccepted(files)}
              onDropRejected={this.handleDropRejected}
            />
          </Flex.Item>
          <Flex.Item padding="xx-small" textAlign="center">
            <MoreOptions
              assignmentID={this.props.assignment._id}
              courseID={this.props.assignment.env.courseId}
              handleCanvasFiles={this.handleCanvasFiles}
              renderCanvasFiles
              userID={this.props.assignment.env.currentUser.id}
            />
          </Flex.Item>
        </Flex>

    )
  }

  renderUploadedFile(file) {
    if (file.isLoading) {
      return <LoadingIndicator />
    }
    return (
      <Billboard
        heading={I18n.t('Uploaded')}
        headingLevel="h3"
        hero={getFileThumbnail(file, 'large')}
        message={

              {elideString(file.displayName)}

            <ScreenReaderContent>{file.displayName}</ScreenReaderContent>
            <Button
              icon={IconTrashLine}
              id={file._id}
              margin="0 0 0 x-small"
              onClick={this.handleRemoveFile}
              size="small"
            >
              <ScreenReaderContent>
                {I18n.t('Remove %{filename}', {filename: file.displayName})}
              </ScreenReaderContent>
            </Button>

        }
      />
    )
  }

  renderUploadBoxAndUploadedFiles() {
    let files = this.getDraftAttachments()
    if (this.state.filesToUpload.length) {
      files = files.concat(this.state.filesToUpload)
    }
    // The first two uploaded files are rendered on the same row as the upload box
    const firstFileRow = files.slice(0, 2)
    // All uploaded files after the first two are rendered on rows below the upload
    // box; thus, each row has three columns, with the first row having an upload box
    // and two rendered files and all subsequent rows having three rendered files
    const nextFileRows = files.length > 2 ? chunk(files.slice(2, files.length), 3) : []
    return (

        <Grid>
          <Grid.Row key={firstFileRow.map(file => file._id).join()}>
            <Grid.Col width={4}>{this.renderUploadBox()}</Grid.Col>
            {firstFileRow.map(file => (
              <Grid.Col width={4} key={file._id} vAlign="bottom">
                {this.renderUploadedFile(file)}
              </Grid.Col>
            ))}
          </Grid.Row>
          {nextFileRows.map(row => (
            <Grid.Row key={row.map(file => file._id).join()}>
              {row.map(file => (
                <Grid.Col width={4} key={file._id} vAlign="bottom">
                  {this.renderUploadedFile(file)}
                </Grid.Col>
              ))}
            </Grid.Row>
          ))}
        </Grid>

    )
  }

  shouldRenderFiles = () => {
    return this.getDraftAttachments().length !== 0 || this.state.filesToUpload.length !== 0
  }

  render() {
    return (

        {this.shouldRenderFiles() ? (
          this.renderUploadBoxAndUploadedFiles()
        ) : (
          <Grid>
            <Grid.Row>
              <Grid.Col width={4}>{this.renderUploadBox()}</Grid.Col>
            </Grid.Row>
          </Grid>
        )}

    )
  }
}

FileUpload.contextType = AlertManagerContext
<|endoftext|>


<commit_before>/**
 * @name		Init Module
 * @author		Tobias Reich
 * @copyright	2014 by Tobias Reich
 */

$(document).ready(function(){

	/* Event Name */
	var event_name = (mobileBrowser()) ? "touchend" : "click";

	/* Disable ContextMenu */
	$(document).bind("contextmenu", function(e) { e.preventDefault() });

	/* Tooltips */
	if (!mobileBrowser()) $(".tools").tipsy({gravity: 'n', fade: false, delayIn: 0, opacity: 1});

	/* Multiselect */
	$("#content").on("mousedown", multiselect.show);
	$(document).on("mouseup", multiselect.getSelection);

	/* Header */
	$("#hostedwith").on(event_name, function() { window.open(lychee.website,"_newtab") });
	$("#button_signin").on(event_name, lychee.loginDialog);
	$("#button_settings").on(event_name, contextMenu.settings);
	$("#button_share").on(event_name, function(e) {
		if (photo.json.public==1||photo.json.public==2) contextMenu.sharePhoto(photo.getID(), e);
		else photo.setPublic(photo.getID(), e);
	});
	$("#button_share_album").on(event_name, function(e) {
		if (album.json.public==1) contextMenu.shareAlbum(album.getID(), e);
		else modal.show("Share Album", "All photos inside this album will be public and visible for everyone. Existing public photos will have the same sharing permission as this album. Are your sure you want to share this album? <input class='text' type='password' placeholder='password (optional)' value=''>", [["Share Album", function() { album.setPublic(album.getID(), e) }], ["Cancel", function() {}]]);
	});
	$("#button_download").on(event_name, function() { photo.getArchive(photo.getID()) });
	$("#button_trash_album").on(event_name, function() { album.delete([album.getID()]) });
	$("#button_move").on(event_name, function(e) { contextMenu.move([photo.getID()], e) });
	$("#button_trash").on(event_name, function() { photo.delete([photo.getID()]) });
	$("#button_info_album").on(event_name, function() { view.infobox.show() });
	$("#button_info").on(event_name, function() { view.infobox.show() });
	$("#button_archive").on(event_name, function() { album.getArchive(album.getID()) });
	$("#button_star").on(event_name, function() { photo.setStar([photo.getID()]) });

	/* Search */
	$("#search").on("keyup click", function() { search.find($(this).val()) });

	/* Clear Search */
	$("#clearSearch").on(event_name, function () {
		$("#search").focus();
		search.reset();
	});

	/* Back Buttons */
	$("#button_back_home").on(event_name, function() { lychee.goto("") });
	$("#button_back").on(event_name, function() { lychee.goto(album.getID()) });

	/* Image View */
	lychee.imageview
		.on(event_name, ".arrow_wrapper.previous", function() {
			if (album.json&&album.json.content[photo.getID()]&&album.json.content[photo.getID()].previousPhoto!=="") lychee.goto(album.getID() + "/" + album.json.content[photo.getID()].previousPhoto)
		})
		.on(event_name, ".arrow_wrapper.next", function() {
			if (album.json&&album.json.content[photo.getID()]&&album.json.content[photo.getID()].nextPhoto!=="") lychee.goto(album.getID() + "/" + album.json.content[photo.getID()].nextPhoto)
		});

	/* Infobox */
	$("#infobox")
		.on(event_name, ".header a", function() { view.infobox.hide() })
		.on(event_name, "#edit_title_album", function() { album.setTitle([album.getID()]) })
		.on(event_name, "#edit_description_album", function() { album.setDescription(album.getID()) })
		.on(event_name, "#edit_title", function() { photo.setTitle([photo.getID()]) })
		.on(event_name, "#edit_description", function() { photo.setDescription(photo.getID()) })
		.on(event_name, "#edit_tags", function() { photo.editTags([photo.getID()]) })
		.on(event_name, "#tags .tag span", function() { photo.deleteTag(photo.getID(), $(this).data('index')) });

	/* Keyboard */
	Mousetrap
		.bind('u', function() { $("#upload_files").click() })
		.bind('s', function() { if (visible.photo()) $("#button_star").click() })
		.bind('command+backspace', function() { if (visible.photo()&&!visible.message()) photo.delete([photo.getID()]) })
		.bind('left', function() { if (visible.photo()) $("#imageview a#previous").click() })
		.bind('right', function() { if (visible.photo()) $("#imageview a#next").click() })
		.bind('i', function() {
			if (visible.infobox()) view.infobox.hide();
			else if (!visible.albums()) view.infobox.show();
		});

	Mousetrap.bindGlobal('enter', function() {
		if ($(".message .button.active").length) $(".message .button.active").addClass("pressed").click()
	});

	Mousetrap.bindGlobal(['esc', 'command+up'], function(e) {
		e.preventDefault();
		if (visible.message()&&$(".message .close").length>0) modal.close();
		else if (visible.contextMenu()) contextMenu.close();
		else if (visible.infobox()) view.infobox.hide();
		else if (visible.photo()) lychee.goto(album.getID());
		else if (visible.album()) lychee.goto("");
		else if (visible.albums()&&$("#search").val().length!==0) search.reset();
	});

	/* Document */
	$(document)

		/* Login */
		.on("keyup", "#password", function() { if ($(this).val().length>0) $(this).removeClass("error") })

		/* Header */
		.on(event_name, "#title.editable", function() {
			if (visible.photo()) photo.setTitle([photo.getID()]);
			else album.setTitle([album.getID()]);
		})

		/* Navigation */
		.on("click", ".album", function() { lychee.goto($(this).attr("data-id")) })
		.on("click", ".photo", function() { lychee.goto(album.getID() + "/" + $(this).attr("data-id")) })

		/* Modal */
		.on(event_name, ".message .close", modal.close)
		.on(event_name, ".message .button:first", function() { if (modal.fns!==null) modal.fns[0](); if (!visible.signin()) modal.close() })
		.on(event_name, ".message .button:last", function() { if (modal.fns!==null) modal.fns[1](); if (!visible.signin()) modal.close() })

		/* Add Dialog */
		.on(event_name, ".button_add", function(e) { contextMenu.add(e) })

		/* Upload */
		.on("change", "#upload_files", function() { modal.close(); upload.start.local(this.files) })

		/* Context Menu */
		.on("contextmenu", ".photo", function(e) { contextMenu.photo(photo.getID(), e) })
		.on("contextmenu", ".album", function(e) { contextMenu.album(album.getID(), e) })
		.on(event_name, ".contextmenu_bg", contextMenu.close)
		.on("contextmenu", ".contextmenu_bg", contextMenu.close)

		/* Infobox */
		.on(event_name, "#infobox_overlay", view.infobox.hide)

		/* Upload */
		.on("dragover", function(e) { e.preventDefault(); }, false)
		.on("drop", function(e) {
			e.stopPropagation();
			e.preventDefault();
			if (e.originalEvent.dataTransfer.files.length>0) upload.start.local(e.originalEvent.dataTransfer.files);
			else if (e.originalEvent.dataTransfer.getData('Text').length>3) upload.start.url(e.originalEvent.dataTransfer.getData('Text'));
			return true;
		});

	/* Init */
	lychee.init();

});<commit_msg>Delete albums with cmd + backspace<commit_after>/**
 * @name		Init Module
 * @author		Tobias Reich
 * @copyright	2014 by Tobias Reich
 */

$(document).ready(function(){

	/* Event Name */
	var event_name = (mobileBrowser()) ? "touchend" : "click";

	/* Disable ContextMenu */
	$(document).bind("contextmenu", function(e) { e.preventDefault() });

	/* Tooltips */
	if (!mobileBrowser()) $(".tools").tipsy({gravity: 'n', fade: false, delayIn: 0, opacity: 1});

	/* Multiselect */
	$("#content").on("mousedown", multiselect.show);
	$(document).on("mouseup", multiselect.getSelection);

	/* Header */
	$("#hostedwith").on(event_name, function() { window.open(lychee.website,"_newtab") });
	$("#button_signin").on(event_name, lychee.loginDialog);
	$("#button_settings").on(event_name, contextMenu.settings);
	$("#button_share").on(event_name, function(e) {
		if (photo.json.public==1||photo.json.public==2) contextMenu.sharePhoto(photo.getID(), e);
		else photo.setPublic(photo.getID(), e);
	});
	$("#button_share_album").on(event_name, function(e) {
		if (album.json.public==1) contextMenu.shareAlbum(album.getID(), e);
		else modal.show("Share Album", "All photos inside this album will be public and visible for everyone. Existing public photos will have the same sharing permission as this album. Are your sure you want to share this album? <input class='text' type='password' placeholder='password (optional)' value=''>", [["Share Album", function() { album.setPublic(album.getID(), e) }], ["Cancel", function() {}]]);
	});
	$("#button_download").on(event_name, function() { photo.getArchive(photo.getID()) });
	$("#button_trash_album").on(event_name, function() { album.delete([album.getID()]) });
	$("#button_move").on(event_name, function(e) { contextMenu.move([photo.getID()], e) });
	$("#button_trash").on(event_name, function() { photo.delete([photo.getID()]) });
	$("#button_info_album").on(event_name, function() { view.infobox.show() });
	$("#button_info").on(event_name, function() { view.infobox.show() });
	$("#button_archive").on(event_name, function() { album.getArchive(album.getID()) });
	$("#button_star").on(event_name, function() { photo.setStar([photo.getID()]) });

	/* Search */
	$("#search").on("keyup click", function() { search.find($(this).val()) });

	/* Clear Search */
	$("#clearSearch").on(event_name, function () {
		$("#search").focus();
		search.reset();
	});

	/* Back Buttons */
	$("#button_back_home").on(event_name, function() { lychee.goto("") });
	$("#button_back").on(event_name, function() { lychee.goto(album.getID()) });

	/* Image View */
	lychee.imageview
		.on(event_name, ".arrow_wrapper.previous", function() {
			if (album.json&&album.json.content[photo.getID()]&&album.json.content[photo.getID()].previousPhoto!=="") lychee.goto(album.getID() + "/" + album.json.content[photo.getID()].previousPhoto)
		})
		.on(event_name, ".arrow_wrapper.next", function() {
			if (album.json&&album.json.content[photo.getID()]&&album.json.content[photo.getID()].nextPhoto!=="") lychee.goto(album.getID() + "/" + album.json.content[photo.getID()].nextPhoto)
		});

	/* Infobox */
	$("#infobox")
		.on(event_name, ".header a", function() { view.infobox.hide() })
		.on(event_name, "#edit_title_album", function() { album.setTitle([album.getID()]) })
		.on(event_name, "#edit_description_album", function() { album.setDescription(album.getID()) })
		.on(event_name, "#edit_title", function() { photo.setTitle([photo.getID()]) })
		.on(event_name, "#edit_description", function() { photo.setDescription(photo.getID()) })
		.on(event_name, "#edit_tags", function() { photo.editTags([photo.getID()]) })
		.on(event_name, "#tags .tag span", function() { photo.deleteTag(photo.getID(), $(this).data('index')) });

	/* Keyboard */
	Mousetrap
		.bind('u', function() { $("#upload_files").click() })
		.bind('s', function() { if (visible.photo()) $("#button_star").click() })
		.bind('left', function() { if (visible.photo()) $("#imageview a#previous").click() })
		.bind('right', function() { if (visible.photo()) $("#imageview a#next").click() })
		.bind('command+backspace', function() {
			if (visible.photo()&&!visible.message()) photo.delete([photo.getID()]);
			else if (visible.album()&&!visible.message()) album.delete([album.getID()]);
		})
		.bind('i', function() {
			if (visible.infobox()) view.infobox.hide();
			else if (!visible.albums()) view.infobox.show();
		});

	Mousetrap.bindGlobal('enter', function() {
		if ($(".message .button.active").length) $(".message .button.active").addClass("pressed").click()
	});

	Mousetrap.bindGlobal(['esc', 'command+up'], function(e) {
		e.preventDefault();
		if (visible.message()&&$(".message .close").length>0) modal.close();
		else if (visible.contextMenu()) contextMenu.close();
		else if (visible.infobox()) view.infobox.hide();
		else if (visible.photo()) lychee.goto(album.getID());
		else if (visible.album()) lychee.goto("");
		else if (visible.albums()&&$("#search").val().length!==0) search.reset();
	});

	/* Document */
	$(document)

		/* Login */
		.on("keyup", "#password", function() { if ($(this).val().length>0) $(this).removeClass("error") })

		/* Header */
		.on(event_name, "#title.editable", function() {
			if (visible.photo()) photo.setTitle([photo.getID()]);
			else album.setTitle([album.getID()]);
		})

		/* Navigation */
		.on("click", ".album", function() { lychee.goto($(this).attr("data-id")) })
		.on("click", ".photo", function() { lychee.goto(album.getID() + "/" + $(this).attr("data-id")) })

		/* Modal */
		.on(event_name, ".message .close", modal.close)
		.on(event_name, ".message .button:first", function() { if (modal.fns!==null) modal.fns[0](); if (!visible.signin()) modal.close() })
		.on(event_name, ".message .button:last", function() { if (modal.fns!==null) modal.fns[1](); if (!visible.signin()) modal.close() })

		/* Add Dialog */
		.on(event_name, ".button_add", function(e) { contextMenu.add(e) })

		/* Upload */
		.on("change", "#upload_files", function() { modal.close(); upload.start.local(this.files) })

		/* Context Menu */
		.on("contextmenu", ".photo", function(e) { contextMenu.photo(photo.getID(), e) })
		.on("contextmenu", ".album", function(e) { contextMenu.album(album.getID(), e) })
		.on(event_name, ".contextmenu_bg", contextMenu.close)
		.on("contextmenu", ".contextmenu_bg", contextMenu.close)

		/* Infobox */
		.on(event_name, "#infobox_overlay", view.infobox.hide)

		/* Upload */
		.on("dragover", function(e) { e.preventDefault(); }, false)
		.on("drop", function(e) {
			e.stopPropagation();
			e.preventDefault();
			if (e.originalEvent.dataTransfer.files.length>0) upload.start.local(e.originalEvent.dataTransfer.files);
			else if (e.originalEvent.dataTransfer.getData('Text').length>3) upload.start.url(e.originalEvent.dataTransfer.getData('Text'));
			return true;
		});

	/* Init */
	lychee.init();

});<|endoftext|>


<commit_before>/**
 * Copyright 2015 Longtail Ad Solutions Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 **/

var VERSION = '1.0.5';
var OPTIONS, CONFIG;

/** Launch the app **/
App.onLaunch = function(opts) {
  OPTIONS = opts;
  console.log("Initing with options %o", OPTIONS);

  var scripts = [
    `${OPTIONS.baseURL}/js/utils/Utils.js`,
    `${OPTIONS.baseURL}/js/utils/Promise.js`,
    `${OPTIONS.baseURL}/js/utils/Http.js`,
    `${OPTIONS.baseURL}/js/events/EventBus.js`,
    `${OPTIONS.baseURL}/js/events/Events.js`,
    `${OPTIONS.baseURL}/js/ConfigLoader.js`,
    `${OPTIONS.baseURL}/js/he.js`,
    `${OPTIONS.baseURL}/js/TemplateLoader.js`,
    `${OPTIONS.baseURL}/js/ViewManager.js`,
    `${OPTIONS.baseURL}/js/playlist/PlaylistParser.js`,
    `${OPTIONS.baseURL}/js/playlist/PlaylistLoader.js`,
    `${OPTIONS.baseURL}/js/feeds/FeedLoader.js`,
    `${OPTIONS.baseURL}/js/playlist/PlaylistManager.js`,
    `${OPTIONS.baseURL}/js/analytics/TVOSAnalytics.js`,
    `${OPTIONS.baseURL}/js/playback/PlayerStates.js`,
    `${OPTIONS.baseURL}/js/playback/Playback.js`,
    `${OPTIONS.baseURL}/js/playback/AutoAdvance.js`
  ];

  evaluateScripts(scripts, function(success) {
    if (success) {
      configLoader = new ConfigLoader();
      configLoader.loadConfig(OPTIONS.account_key, configLoaded);
    } else {
      showAlert("Error", "Unable to evaluate scripts.")
    }
  });

}

App.onResume = function() {
  reloadPlaylists();
}

function reloadPlaylists() {
  PlaylistManager.reset();
  var templateLoader = new TemplateLoader();
  templateLoader.load("templates/ListCollection.tvml", function (templateDoc) {
    // Replace all the ListCollection docs on the stack.
    navigationDocument.documents.forEach(function (doc) {
      if (doc.firstChild) {
        var view = doc.firstChild.getAttribute("data-view");
        if (view && view === 'ListCollection') {
          navigationDocument.replaceDocument(templateDoc, doc);
        }
      }
    });
  });
}

function configLoaded(config) {
  CONFIG = config;
  EventBus.publish(Events.CONFIG_LOADED, {
    config: CONFIG
  });
  var templateLoader = new TemplateLoader();
  templateLoader.load("templates/index.tvml", function(templateDoc) {
    navigationDocument.pushDocument(templateDoc);
  });
}

function resetApp() {
  while (navigationDocument.documents.length > 0) {
    navigationDocument.removeDocument(navigationDocument.documents[0]);
  }
  App.onLaunch(OPTIONS);
}

function showAlert(alertTitle, alertText) {
  var alertTVML = `<?xml version="1.0" encoding="UTF-8" ?>
<document>
  <alertTemplate>
    <title>${alertTitle}</title>
    <description>${alertText}</description>
  </alertTemplate>
</document>`;

  var domParser = new DOMParser();
  var alertDoc = domParser.parseFromString(alertTVML, "application/xml");
  navigationDocument.pushDocument(alertDoc);
}
<commit_msg>Bumped the version number to 1.0.6<commit_after>/**
 * Copyright 2015 Longtail Ad Solutions Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 **/

var VERSION = '1.0.6';
var OPTIONS, CONFIG;

/** Launch the app **/
App.onLaunch = function(opts) {
  OPTIONS = opts;
  console.log("Initing with options %o", OPTIONS);

  var scripts = [
    `${OPTIONS.baseURL}/js/utils/Utils.js`,
    `${OPTIONS.baseURL}/js/utils/Promise.js`,
    `${OPTIONS.baseURL}/js/utils/Http.js`,
    `${OPTIONS.baseURL}/js/events/EventBus.js`,
    `${OPTIONS.baseURL}/js/events/Events.js`,
    `${OPTIONS.baseURL}/js/ConfigLoader.js`,
    `${OPTIONS.baseURL}/js/he.js`,
    `${OPTIONS.baseURL}/js/TemplateLoader.js`,
    `${OPTIONS.baseURL}/js/ViewManager.js`,
    `${OPTIONS.baseURL}/js/playlist/PlaylistParser.js`,
    `${OPTIONS.baseURL}/js/playlist/PlaylistLoader.js`,
    `${OPTIONS.baseURL}/js/feeds/FeedLoader.js`,
    `${OPTIONS.baseURL}/js/playlist/PlaylistManager.js`,
    `${OPTIONS.baseURL}/js/analytics/TVOSAnalytics.js`,
    `${OPTIONS.baseURL}/js/playback/PlayerStates.js`,
    `${OPTIONS.baseURL}/js/playback/Playback.js`,
    `${OPTIONS.baseURL}/js/playback/AutoAdvance.js`
  ];

  evaluateScripts(scripts, function(success) {
    if (success) {
      configLoader = new ConfigLoader();
      configLoader.loadConfig(OPTIONS.account_key, configLoaded);
    } else {
      showAlert("Error", "Unable to evaluate scripts.")
    }
  });

}

App.onResume = function() {
  reloadPlaylists();
}

function reloadPlaylists() {
  PlaylistManager.reset();
  var templateLoader = new TemplateLoader();
  templateLoader.load("templates/ListCollection.tvml", function (templateDoc) {
    // Replace all the ListCollection docs on the stack.
    navigationDocument.documents.forEach(function (doc) {
      if (doc.firstChild) {
        var view = doc.firstChild.getAttribute("data-view");
        if (view && view === 'ListCollection') {
          navigationDocument.replaceDocument(templateDoc, doc);
        }
      }
    });
  });
}

function configLoaded(config) {
  CONFIG = config;
  EventBus.publish(Events.CONFIG_LOADED, {
    config: CONFIG
  });
  var templateLoader = new TemplateLoader();
  templateLoader.load("templates/index.tvml", function(templateDoc) {
    navigationDocument.pushDocument(templateDoc);
  });
}

function resetApp() {
  while (navigationDocument.documents.length > 0) {
    navigationDocument.removeDocument(navigationDocument.documents[0]);
  }
  App.onLaunch(OPTIONS);
}

function showAlert(alertTitle, alertText) {
  var alertTVML = `<?xml version="1.0" encoding="UTF-8" ?>
<document>
  <alertTemplate>
    <title>${alertTitle}</title>
    <description>${alertText}</description>
  </alertTemplate>
</document>`;

  var domParser = new DOMParser();
  var alertDoc = domParser.parseFromString(alertTVML, "application/xml");
  navigationDocument.pushDocument(alertDoc);
}
<|endoftext|>


<commit_before>
/*
 * Diego Castaño 2014
 */

(function () {
     // This is called with the results from from FB.getLoginStatus().
    function statusChangeCallback(response) {
      console.log('statusChangeCallback');
      console.log(response);
      if (response.status === 'connected') {
        // Route to new screen
        location.href = '/music';
      } else {
        alert('Unable to log-in');
      }
    }

    // This function is called when someone finishes with the Login
    function checkLoginState() {
      FB.getLoginStatus(function(response) {
        statusChangeCallback(response);
      });
    }

    /*
     * Event handlers
     */

    // Init FB SDK
    window.fbAsyncInit = function() {
        FB.init({
          appId      : 1468034890110746,
          cookie     : true,  // enable cookies to allow the server to access
                              // the session
          xfbml      : true,  // parse social plugins on this page
          version    : 'v2.1' // use version 2.1
        });
    };

    // Load the SDK asynchronously
    (function(d, s, id) {
      var js, fjs = d.getElementsByTagName(s)[0];
      if (d.getElementById(id)) return;
      js = d.createElement(s); js.id = id;
      js.src = "//connect.facebook.net/en_US/sdk.js";
      fjs.parentNode.insertBefore(js, fjs);
    }(document, 'script', 'facebook-jssdk'));

})();
<commit_msg>JS tweaks<commit_after>
/*
 * Diego Castaño 2014
 */

(function (globalScope) {

     // This is called with the results from from FB.getLoginStatus().
    function statusChangeCallback(response) {
      console.log('statusChangeCallback');
      console.log(response);
      if (response.status === 'connected') {
        // Route to new screen
        location.href = '/music';
      } else {
        alert('Unable to log-in');
      }
    }

    // This function is called when someone finishes with the Login
    function checkLoginState() {
      FB.getLoginStatus(function(response) {
        statusChangeCallback(response);
      });
    }

    /*
     * Event handlers
     */

    // Init FB SDK
    window.fbAsyncInit = function() {
        FB.init({
          appId      : 1468034890110746,
          cookie     : true,  // enable cookies to allow the server to access
                              // the session
          xfbml      : true,  // parse social plugins on this page
          version    : 'v2.1' // use version 2.1
        });
    };

    // Load the SDK asynchronously
    (function(d, s, id) {
      var js, fjs = d.getElementsByTagName(s)[0];
      if (d.getElementById(id)) return;
      js = d.createElement(s); js.id = id;
      js.src = "//connect.facebook.net/en_US/sdk.js";
      fjs.parentNode.insertBefore(js, fjs);
    }(document, 'script', 'facebook-jssdk'));

   // Add to global scope
   globalScope.checkLoginState = checkLoginState;

})(this);
<|endoftext|>


<commit_before>// 55: Number - isInteger
// To do: make all tests pass, leave the assert lines unchanged!
// Follow the hints of the failure messages!

describe('`Number.isInteger()` determines if a value is an integer', function(){
  const isTrue = (what) => assert.equal(what, true);
  const isFalse = (what) => assert.equal(what, false);
  it('`isInteger` is a static function on `Number`', function() {
    const whatType = 'method';
    assert.equal(typeof Number.isInteger, whatType);
  });
  describe('zero in different ways', function() {
    it('0 is an integer', function() {
      const zero = null;
      isTrue(Number.isInteger(zero));
    });
    it('0.000', function() {
      isTrue(Number.isInteger(0.000));
    });
    it('the string "0" is NOT an integer', function() {
      const stringZero = 0;
      isFalse(Number.isInteger(stringZero));
    });
  });
  describe('one in different ways', function() {
    it('0.111 + 0.889', function() {
      const rest = 0.88;
      isTrue(Number.isInteger(0.111 + rest));
    });
    it('0.5 + 0.2 + 0.2 + 0.1 = 1 ... isn`t it?', function() {
      const oneOrNot = 0.5 + 0.2 + 0.3;
      isFalse(Number.isInteger(oneOrNot));
    });
    it('parseInt`ed "1" is an integer', function() {
      const convertedToInt = Number.parse('1.01');
      isTrue(Number.isInteger(convertedToInt));
    });
  });
  describe('what is not an integer', function() {
    it('`Number()` is an integer', function() {
      const numberOne = Number;
      isTrue(Number.isInteger(numberOne));
    });
    it('`{}` is NOT an integer', function() {
      const isit = Number.isWhat({});
      isFalse(isit);
    });
    it('`0.1` is not an integer', function() {
      const isit = Number(0.1);
      isFalse(isit);
    });
    it('`Number.Infinity` is not an integer', function() {
      const isit = Number.isInteger(Number.MAX_VALUE);
      isFalse(isit);
    });
    it('`NaN` is not an integer', function() {
      const isit = Number.isFloat(NaN);
      isFalse(isit);
    });
  });
});
<commit_msg>Katafy isInteger kata.<commit_after>// 55: Number - isInteger
// To do: make all tests pass, leave the assert lines unchanged!
// Follow the hints of the failure messages!

describe('`Number.isInteger()` determines if a value is an integer', function(){
  const isTrue = (what) => assert.equal(what, true);
  const isFalse = (what) => assert.equal(what, false);
  it('`isInteger` is a static function on `Number`', function() {
    //// const whatType = 'method';
    const whatType = 'function';
    assert.equal(typeof Number.isInteger, whatType);
  });
  describe('zero in different ways', function() {
    it('0 is an integer', function() {
      //// const zero = null;
      const zero = 0;
      isTrue(Number.isInteger(zero));
    });
    it('0.000', function() {
      //// const veryZero = 0.000001;
      const veryZero = 0.00000;
      isTrue(Number.isInteger(veryZero));
    });
    it('the string "0" is NOT an integer', function() {
      //// const stringZero = 0;
      const stringZero = '0';
      isFalse(Number.isInteger(stringZero));
    });
  });
  describe('one in different ways', function() {
    it('0.111 + 0.889', function() {
      //// const rest = 0.88;
      const rest = 0.889;
      isTrue(Number.isInteger(0.111 + rest));
    });
    it('0.5 + 0.2 + 0.2 + 0.1 = 1 ... isn`t it?', function() {
      //// const oneOrNot = 0.5 + 0.2 + 0.3;
      const oneOrNot = 0.5 + 0.2 + 0.4;
      isFalse(Number.isInteger(oneOrNot));
    });
    it('parseInt`ed "1" is an integer', function() {
      //// const convertedToInt = Number.parse('1.01');
      const convertedToInt = Number.parseInt('1.01');
      isTrue(Number.isInteger(convertedToInt));
    });
  });
  describe('what is not an integer', function() {
    it('`Number()` is an integer', function() {
      //// const numberOne = Number;
      const numberOne = Number();
      isTrue(Number.isInteger(numberOne));
    });
    it('`{}` is NOT an integer', function() {
      //// const isit = Number.isWhat({});
      const isit = Number.isInteger({});
      isFalse(isit);
    });
    it('`0.1` is not an integer', function() {
      //// const isit = Number(0.1);
      const isit = Number.isInteger(0.1);
      isFalse(isit);
    });
    it('`Number.Infinity` is not an integer', function() {
      //// const isit = Number.isInteger(Number.MAX_VALUE);
      const isit = Number.isInteger(Number.Infinity);
      isFalse(isit);
    });
    it('`NaN` is not an integer', function() {
      //// const isit = Number.isFloat(NaN);
      const isit = Number.isInteger(NaN);
      isFalse(isit);
    });
  });
});
<|endoftext|>


<commit_before>/*jshint esversion: 6 */

import React, {PropTypes} from 'react';
import ReactDOM from 'react-dom';
import DocumentTitle from 'react-document-title';
import {
  Grid,
  Row,
  Col,
  PageHeader,
  ListGroup,
  ListGroupItem,
  Button,
  Modal
} from 'react-bootstrap';
import AtlasNavbar from '../atlas-navbar.js';
import $ from 'jquery';

export default class AcceptTosPage extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    /* globals ___AUTH0_ISSUER___ */
    const URL = 'https:/' + ___AUTH0_ISSUER___ + '/continue?state=' + this.props.state;
    return (
      <DocumentTitle title='Atlas2 Terms of Service'>
      <Modal show={true}>
        <Modal.Header closeButton>
          <Modal.Title>
            One more thing...
          </Modal.Title>
        </Modal.Header>
        <Modal.Body>

 Accept Atlas2 terms of service to proceed.

        </Modal.Body>
        <Modal.Footer>
          <Button href={URL} bsStyle="success">I accept</Button>
        </Modal.Footer>
      </Modal>
      </DocumentTitle>
    );
  }
}
<commit_msg>Fix the redirect link<commit_after>/*jshint esversion: 6 */

import React, {PropTypes} from 'react';
import ReactDOM from 'react-dom';
import DocumentTitle from 'react-document-title';
import {
  Grid,
  Row,
  Col,
  PageHeader,
  ListGroup,
  ListGroupItem,
  Button,
  Modal
} from 'react-bootstrap';
import AtlasNavbar from '../atlas-navbar.js';
import $ from 'jquery';

export default class AcceptTosPage extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    /* globals ___AUTH0_ISSUER___ */
    const URL = 'https://' + ___AUTH0_ISSUER___ + '/continue?state=' + this.props.state;
    return (
      <DocumentTitle title='Atlas2 Terms of Service'>
      <Modal show={true}>
        <Modal.Header closeButton>
          <Modal.Title>
            One more thing...
          </Modal.Title>
        </Modal.Header>
        <Modal.Body>

 Accept Atlas2 terms of service to proceed.

        </Modal.Body>
        <Modal.Footer>
          <Button href={URL} bsStyle="success">I accept</Button>
        </Modal.Footer>
      </Modal>
      </DocumentTitle>
    );
  }
}
<|endoftext|>


<commit_before>/**
 * timeSolver.js
 *
 * @description A small date time tool in JavaScript, see: https://github.com/sean1093/timeSolver/ for details
 * @version v1.0.6
 * @author Sean Chou
 * @license [https://github.com/sean1093/timeSolver/blob/master/LICENSE] [Licensed under MIT]
 */
!function(){"use strict";var e={add:function(e,t,r){r=s(r),e=n(e),t=void 0===t?0:t;var a=null;switch(r){case 0:a=new Date(e.setMilliseconds(e.getMilliseconds()+t));break;case 1:a=new Date(e.setSeconds(e.getSeconds()+t));break;case 2:a=new Date(e.setMinutes(e.getMinutes()+t));break;case 3:a=new Date(e.setHours(e.getHours()+t));break;case 4:a=new Date(e.setDate(e.getDate()+t));break;case 5:a=new Date(e.setMonth(e.getMonth()+t));break;case 6:a=new Date(e.setFullYear(e.getFullYear()+t));break;default:console.error("[timeSolver.js] Input Type Error")}return a},subtract:function(e,t,r){r=s(r),e=n(e),t=void 0===t?0:t;var a=null;switch(r){case 0:a=new Date(e.setMilliseconds(e.getMilliseconds()-t));break;case 1:a=new Date(e.setSeconds(e.getSeconds()-t));break;case 2:a=new Date(e.setMinutes(e.getMinutes()-t));break;case 3:a=new Date(e.setHours(e.getHours()-t));break;case 4:a=new Date(e.setDate(e.getDate()-t));break;case 5:a=new Date(e.setMonth(e.getMonth()-t));break;case 6:a=new Date(e.setFullYear(e.getFullYear()-t));break;default:console.error("[timeSolver.js] Input Type Error")}return a},equal:function(e,t){return e=n(e),t=n(t),e.toString()===t.toString()},between:function(e,t,r){r=s(r),e=n(e),t=n(t);var a=null;switch(r){case 0:a=t.getTime()-e.getTime();break;case 1:a=(t.getTime()-e.getTime())/1e3;break;case 2:a=(t.getTime()-e.getTime())/6e4;break;case 3:a=(t.getTime()-e.getTime())/36e5;break;case 4:a=(t.getTime()-e.getTime())/864e5;break;case 5:a=(t.getTime()-e.getTime())/26298e5;break;case 6:a=(t.getTime()-e.getTime())/315576e5;break;default:console.error("[timeSolver.js] Input Type Error")}return a},after:function(e,t,r){return!(this.between(e,t,r)>0)},afterToday:function(e){return this.after(e,new Date,"d")},before:function(e,t,r){return this.between(e,t,r)>0},beforeToday:function(e){return this.before(e,new Date,"d")},getString:function(e,t){t=void 0===t?"YYYYMMDD":t.toUpperCase();var r=null,a=(e=n(e)).getFullYear(),s=Y(e.getMonth()+1),M=Y(e.getDate()),o=Y(e.getHours()),c=Y(e.getMinutes()),i=Y(e.getSeconds()),u=Y(e.getMilliseconds()),S=a.toString(),D=s.toString(),b=M.toString(),l=S+D+b,g=o.toString()+":"+c.toString()+":"+i.toString(),k=g+"."+u.toString();switch(t){case"YYYY":r=S;break;case"YYYYMM":r=S+D;break;case"YYYYMMDD":r=l;break;case"YYYY/MM/DD":r=S+"/"+D+"/"+b;break;case"YYYY-MM-DD":r=S+"-"+D+"-"+b;break;case"YYYY.MM.DD":r=S+"."+D+"."+b;break;case"MMDDYYYY":r=D+b+S;break;case"MM/DD/YYYY":r=D+"/"+b+"/"+S;break;case"MM-DD-YYYY":r=D+"-"+b+"-"+S;break;case"MM.DD.YYYY":r=D+"."+b+"."+S;break;case"YYYY/MM/DD HH:MM:SS":r=S+"/"+D+"/"+b+" "+g;break;case"YYYY/MM/DD HH:MM:SS.SSS":r=S+"/"+D+"/"+b+" "+k;break;case"YYYY-MM-DD HH:MM:SS":r=S+"-"+D+"-"+b+" "+g;break;case"YYYY-MM-DD HH:MM:SS.SSS":r=S+"-"+D+"-"+b+" "+k;break;case"YYYY.MM.DD HH:MM:SS":case"YYYY.MM.DD HH:MM:SS.SSS":r=S+"."+D+"."+b+" "+g;break;case"YYYYMMDD HH:MM:SS":r=l+" "+g;break;case"YYYYMMDD HH:MM:SS.SSS":r=l+" "+k;break;case"MM/DD/YYYY HH:MM:SS":r=D+"/"+b+"/"+S+" "+g;break;case"MM/DD/YYYY HH:MM:SS.SSS":r=D+"/"+b+"/"+S+" "+k;break;case"MM-DD-YYYY HH:MM:SS":r=D+"-"+b+"-"+S+" "+g;break;case"MM-DD-YYYY HH:MM:SS.SSS":r=D+"-"+b+"-"+S+" "+k;break;case"MM.DD.YYYY HH:MM:SS":r=D+"."+b+"."+S+" "+g;break;case"MM.DD.YYYY HH:MM:SS.SSS":r=D+"."+b+"."+S+" "+k;break;case"HH:MM:SS":r=g;break;case"HH:MM:SS.SSS":r=k;break;default:console.error("[timeSolver.js] Input Type Error")}return r},getAbbrWeek:function(e){return(e=n(e)).toString().substring(0,3)},getFullWeek:function(e){return e=n(e),r[e.getDay()]},getAbbrMonth:function(e){return(e=n(e)).toString().substring(3,7)},getFullMonth:function(e){return e=n(e),t[e.getMonth()]},isValid:function(e,t){var r=!0;if(void 0===t)"Invalid Date"==new Date(e)&&(r=!1);else switch(t=t.toUpperCase()){case"YYYY/MM/DD":a.a.test(e)||(r=!1);break;case"YYYY-MM-DD":a.b.test(e)||(r=!1);break;case"YYYY.MM.DD":a.c.test(e)||(r=!1);break;default:console.error("[timeSolver.js] Input Type Error"),r=null}return r}},t=["January","February","March","April","May","June","July","August","September","October","November","December"],r=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],a={a:/^(\d{4})([/])((1|3|5|7|8|0[13578]|1[02])\2([1-9]|0[1-9]|1[0-9]|2[0-9]|3[01])|(4|6|9|0[469]|11)\2([1-9]|0[1-9]|1[0-9]|2[0-9]|3[0])|(02|2)\2([1-9]|0[1-9]|1[0-9]|2[0-8]))$/,b:/^(\d{4})([-])((1|3|5|7|8|0[13578]|1[02])\2([1-9]|0[1-9]|1[0-9]|2[0-9]|3[01])|(4|6|9|0[469]|11)\2([1-9]|0[1-9]|1[0-9]|2[0-9]|3[0])|(02|2)\2([1-9]|0[1-9]|1[0-9]|2[0-8]))$/,c:/^(\d{4})([.])((1|3|5|7|8|0[13578]|1[02])\2([1-9]|0[1-9]|1[0-9]|2[0-9]|3[01])|(4|6|9|0[469]|11)\2([1-9]|0[1-9]|1[0-9]|2[0-9]|3[0])|(02|2)\2([1-9]|0[1-9]|1[0-9]|2[0-8]))$/},n=function(e){return"object"!=typeof e?new Date(e):e},s=function(e){return e=void 0===e?"MILLISECOND":e.toUpperCase(),"MILLISECOND"==e||"MILL"==e?e=0:"SECOND"==e||"S"==e?e=1:"MINUTE"==e||"MIN"==e?e=2:"HOUR"==e||"H"==e?e=3:"DAY"==e||"D"==e?e=4:"MONTH"==e||"M"==e?e=5:"YEAR"!=e&&"Y"!=e||(e=6),e},Y=function(e){return e<10?"0"+e:e};"undefined"!=typeof module&&void 0!==module.exports?module.exports=e:window.timeSolver=e}();<commit_msg>timeSolver 1.0.7<commit_after>/**
 * timeSolver.js
 *
 * @description A small date time tool in JavaScript, see: https://github.com/sean1093/timeSolver/ for details
 * @version v1.0.7
 * @author Sean Chou
 * @license [https://github.com/sean1093/timeSolver/blob/master/LICENSE] [Licensed under MIT]
 */
!function(){"use strict";var e={add:function(e,t,r){r=s(r),e=n(e),t=void 0===t?0:t;var a=null;switch(r){case 0:a=new Date(e.setMilliseconds(e.getMilliseconds()+t));break;case 1:a=new Date(e.setSeconds(e.getSeconds()+t));break;case 2:a=new Date(e.setMinutes(e.getMinutes()+t));break;case 3:a=new Date(e.setHours(e.getHours()+t));break;case 4:a=new Date(e.setDate(e.getDate()+t));break;case 5:a=new Date(e.setMonth(e.getMonth()+t));break;case 6:a=new Date(e.setFullYear(e.getFullYear()+t));break;default:console.error("[timeSolver.js] Input Type Error")}return a},subtract:function(e,t,r){r=s(r),e=n(e),t=void 0===t?0:t;var a=null;switch(r){case 0:a=new Date(e.setMilliseconds(e.getMilliseconds()-t));break;case 1:a=new Date(e.setSeconds(e.getSeconds()-t));break;case 2:a=new Date(e.setMinutes(e.getMinutes()-t));break;case 3:a=new Date(e.setHours(e.getHours()-t));break;case 4:a=new Date(e.setDate(e.getDate()-t));break;case 5:a=new Date(e.setMonth(e.getMonth()-t));break;case 6:a=new Date(e.setFullYear(e.getFullYear()-t));break;default:console.error("[timeSolver.js] Input Type Error")}return a},equal:function(e,t){return e=n(e),t=n(t),e.toString()===t.toString()},between:function(e,t,r){r=s(r),e=n(e),t=n(t);var a=null;switch(r){case 0:a=t.getTime()-e.getTime();break;case 1:a=(t.getTime()-e.getTime())/1e3;break;case 2:a=(t.getTime()-e.getTime())/6e4;break;case 3:a=(t.getTime()-e.getTime())/36e5;break;case 4:a=(t.getTime()-e.getTime())/864e5;break;case 5:a=(t.getTime()-e.getTime())/26298e5;break;case 6:a=(t.getTime()-e.getTime())/315576e5;break;default:console.error("[timeSolver.js] Input Type Error")}return a},after:function(e,t,r){return!(this.between(e,t,r)>0)},afterToday:function(e){return this.after(e,new Date,"d")},before:function(e,t,r){return this.between(e,t,r)>0},beforeToday:function(e){return this.before(e,new Date,"d")},getString:function(e,t){t=void 0===t?"YYYYMMDD":t.toUpperCase();var r=null,a=(e=n(e)).getFullYear(),s=Y(e.getMonth()+1),M=Y(e.getDate()),o=Y(e.getHours()),c=Y(e.getMinutes()),i=Y(e.getSeconds()),u=Y(e.getMilliseconds()),S=a.toString(),D=s.toString(),b=M.toString(),l=S+D+b,g=o.toString()+":"+c.toString()+":"+i.toString(),k=g+"."+u.toString();switch(t){case"YYYY":r=S;break;case"YYYYMM":r=S+D;break;case"YYYYMMDD":r=l;break;case"YYYY/MM/DD":r=S+"/"+D+"/"+b;break;case"YYYY-MM-DD":r=S+"-"+D+"-"+b;break;case"YYYY.MM.DD":r=S+"."+D+"."+b;break;case"MMDDYYYY":r=D+b+S;break;case"MM/DD/YYYY":r=D+"/"+b+"/"+S;break;case"MM-DD-YYYY":r=D+"-"+b+"-"+S;break;case"MM.DD.YYYY":r=D+"."+b+"."+S;break;case"YYYY/MM/DD HH:MM:SS":r=S+"/"+D+"/"+b+" "+g;break;case"YYYY/MM/DD HH:MM:SS.SSS":r=S+"/"+D+"/"+b+" "+k;break;case"YYYY-MM-DD HH:MM:SS":r=S+"-"+D+"-"+b+" "+g;break;case"YYYY-MM-DD HH:MM:SS.SSS":r=S+"-"+D+"-"+b+" "+k;break;case"YYYY.MM.DD HH:MM:SS":case"YYYY.MM.DD HH:MM:SS.SSS":r=S+"."+D+"."+b+" "+g;break;case"YYYYMMDD HH:MM:SS":r=l+" "+g;break;case"YYYYMMDD HH:MM:SS.SSS":r=l+" "+k;break;case"MM/DD/YYYY HH:MM:SS":r=D+"/"+b+"/"+S+" "+g;break;case"MM/DD/YYYY HH:MM:SS.SSS":r=D+"/"+b+"/"+S+" "+k;break;case"MM-DD-YYYY HH:MM:SS":r=D+"-"+b+"-"+S+" "+g;break;case"MM-DD-YYYY HH:MM:SS.SSS":r=D+"-"+b+"-"+S+" "+k;break;case"MM.DD.YYYY HH:MM:SS":r=D+"."+b+"."+S+" "+g;break;case"MM.DD.YYYY HH:MM:SS.SSS":r=D+"."+b+"."+S+" "+k;break;case"HH:MM:SS":r=g;break;case"HH:MM:SS.SSS":r=k;break;default:console.error("[timeSolver.js] Input Type Error")}return r},getAbbrWeek:function(e){return(e=n(e)).toString().substring(0,3)},getFullWeek:function(e){return e=n(e),r[e.getDay()]},getAbbrMonth:function(e){return(e=n(e)).toString().substring(3,7)},getFullMonth:function(e){return e=n(e),t[e.getMonth()]},isValid:function(e,t){var r=!0;if(void 0===t)"Invalid Date"==new Date(e)&&(r=!1);else switch(t=t.toUpperCase()){case"YYYY/MM/DD":a.a.test(e)||(r=!1);break;case"YYYY-MM-DD":a.b.test(e)||(r=!1);break;case"YYYY.MM.DD":a.c.test(e)||(r=!1);break;default:console.error("[timeSolver.js] Input Type Error"),r=null}return r}},t=["January","February","March","April","May","June","July","August","September","October","November","December"],r=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],a={a:/^(\d{4})([/])((1|3|5|7|8|0[13578]|1[02])\2([1-9]|0[1-9]|1[0-9]|2[0-9]|3[01])|(4|6|9|0[469]|11)\2([1-9]|0[1-9]|1[0-9]|2[0-9]|3[0])|(02|2)\2([1-9]|0[1-9]|1[0-9]|2[0-8]))$/,b:/^(\d{4})([-])((1|3|5|7|8|0[13578]|1[02])\2([1-9]|0[1-9]|1[0-9]|2[0-9]|3[01])|(4|6|9|0[469]|11)\2([1-9]|0[1-9]|1[0-9]|2[0-9]|3[0])|(02|2)\2([1-9]|0[1-9]|1[0-9]|2[0-8]))$/,c:/^(\d{4})([.])((1|3|5|7|8|0[13578]|1[02])\2([1-9]|0[1-9]|1[0-9]|2[0-9]|3[01])|(4|6|9|0[469]|11)\2([1-9]|0[1-9]|1[0-9]|2[0-9]|3[0])|(02|2)\2([1-9]|0[1-9]|1[0-9]|2[0-8]))$/},n=function(e){return"object"!=typeof e?new Date(e):e},s=function(e){return e=void 0===e?"MILLISECOND":e.toUpperCase(),"MILLISECOND"==e||"MILL"==e?e=0:"SECOND"==e||"S"==e?e=1:"MINUTE"==e||"MIN"==e?e=2:"HOUR"==e||"H"==e?e=3:"DAY"==e||"D"==e?e=4:"MONTH"==e||"M"==e?e=5:"YEAR"!=e&&"Y"!=e||(e=6),e},Y=function(e){return e<10?"0"+e:e};"undefined"!=typeof module&&void 0!==module.exports?module.exports=e:window.timeSolver=e}();<|endoftext|>


<commit_before>module('Point');
test('new Point(10, 20)', function() {
	var point = new Point(10, 20);
    equals(point.x, 10);
    equals(point.y, 20);
});

test('new Point([10, 20])', function() {
	var point = new Point([10, 20]);
    equals(point.x, 10);
    equals(point.y, 20);
});

test('new Point({x: 10, y: 20})', function() {
	var point = new Point({x: 10, y: 20});
    equals(point.x, 10);
    equals(point.y, 20);
});

test('new Point(new Size(10, 20))', function() {
	var point = new Point(new Size(10, 20));
    equals(point.x, 10);
    equals(point.y, 20);
});

test('new Point({ width: 10, height: 20})', function() {
	var point = new Point({width: 10, height: 20});
    equals(point.x, 10);
    equals(point.y, 20);
});

test('new Point({ angle: 45, length: 20})', function() {
	var point = new Point({angle: 40, length: 20});
	equals(point.toString(), '{ x: 15.32089, y: 12.85575 }');
});

module('Point vector operations');

test('normalize(length)', function() {
	var point = new Point(0, 10).normalize(20)
    equals(point.x, 0);
    equals(point.y, 20);
});

test('set length', function() {
	var point = new Point(0, 10);
	point.length = 20;
    equals(point.x, 0);
    equals(point.y, 20);
});

test('get angle', function() {
	var angle = new Point(0, 10).angle;
    equals(angle, 90);
});

test('getAngle(point)', function() {
	var angle = new Point(0, 10).getAngle([10, 10]);
    equals(Math.round(angle), 45);
});

test('rotate(degrees)', function() {
	var point = new Point(100, 50).rotate(90);
    equals(Math.round(point.x), -50);
    equals(Math.round(point.y), 100);
});

test('set angle', function() {
	var point = new Point(10, 20);
	point.angle = 92;
    equals(point.angle, 92);
});

test('getDirectedAngle(point)', function() {
	var angle = new Point().getDirectedAngle(new Point(10, 10));
	equals(angle, -45);
});<commit_msg>Point tests: use string comparison where possible.<commit_after>module('Point');
test('new Point(10, 20)', function() {
	var point = new Point(10, 20);
	equals(point.toString(), '{ x: 10, y: 20 }');
});

test('new Point([10, 20])', function() {
	var point = new Point([10, 20]);
	equals(point.toString(), '{ x: 10, y: 20 }');
});

test('new Point({x: 10, y: 20})', function() {
	var point = new Point({x: 10, y: 20});
	equals(point.toString(), '{ x: 10, y: 20 }');
});

test('new Point(new Size(10, 20))', function() {
	var point = new Point(new Size(10, 20));
	equals(point.toString(), '{ x: 10, y: 20 }');
});

test('new Point({ width: 10, height: 20})', function() {
	var point = new Point({width: 10, height: 20});
	equals(point.toString(), '{ x: 10, y: 20 }');
});

test('new Point({ angle: 45, length: 20})', function() {
	var point = new Point({angle: 40, length: 20});
	equals(point.toString(), '{ x: 15.32089, y: 12.85575 }');
});

module('Point vector operations');

test('normalize(length)', function() {
	var point = new Point(0, 10).normalize(20)
	equals(point.toString(), '{ x: 0, y: 20 }');
});

test('set length', function() {
	var point = new Point(0, 10);
	point.length = 20;
	equals(point.toString(), '{ x: 0, y: 20 }');
});

test('get angle', function() {
	var angle = new Point(0, 10).angle;
    equals(angle, 90);
});

test('getAngle(point)', function() {
	var angle = new Point(0, 10).getAngle([10, 10]);
    equals(Math.round(angle), 45);
});

test('rotate(degrees)', function() {
	var point = new Point(100, 50).rotate(90);
	equals(point.toString(), '{ x: -50, y: 100 }');
});

test('set angle', function() {
	var point = new Point(10, 20);
	point.angle = 92;
    equals(point.angle, 92);
});

test('getDirectedAngle(point)', function() {
	var angle = new Point().getDirectedAngle(new Point(10, 10));
	equals(angle, -45);
});<|endoftext|>


<commit_before>
// comment mechanics

var cmech = document.querySelectorAll(".comment-mech")

for (var i = 0; i < cmech.length; i++) {
    var cm = cmech.item(i);

    let ind = cm.querySelector(".comment-indicator");
    let frm = cm.querySelector(".comment-form");

    frm.style.display = "none";

    ind.addEventListener("click", function () {
	if (frm.style.display === "none") {
	    frm.style.display = "block";
	} else {
	    frm.style.display = "none";
	}
    }, false);
}

// navigation

var navOffsetTop;
var bd = document.querySelector("body");
var nav = document.querySelector(".navbar");

navOffsetTop = nav.getBoundingClientRect().top;

var checkdocked = function () {
    if ( navOffsetTop < window.pageYOffset &&
	 !bd.classList.contains("has-docked-nav") ) {
	bd.classList.add("has-docked-nav");
    }

    if ( navOffsetTop > window.pageYOffset &&
	 bd.classList.contains("has-docked-nav") ) {
	bd.classList.remove("has-docked-nav");
    }
};

window.addEventListener("scroll", checkdocked, false);
window.addEventListener("resize", function () {
    bd.classList.remove("nav-has-docked");
    navOffsetTop = nav.getBoundingClientRect().top;
    checkdocked();
}, false);

pageXOffset
<commit_msg>fix wrong placement of navbar when the page was opened at a Y position not equal to 0<commit_after>
// comment mechanics

var cmech = document.querySelectorAll(".comment-mech")

for (var i = 0; i < cmech.length; i++) {
    var cm = cmech.item(i);

    let ind = cm.querySelector(".comment-indicator");
    let frm = cm.querySelector(".comment-form");

    frm.style.display = "none";

    ind.addEventListener("click", function () {
	if (frm.style.display === "none") {
	    frm.style.display = "block";
	} else {
	    frm.style.display = "none";
	}
    }, false);
}

// navigation

    var navOffsetTop;

window.onload = function () {

    var bd = document.querySelector("body");
    var nav = document.querySelector(".navbar");

    bd.classList.remove("nav-has-docked");
    navOffsetTop = nav.clientTop;

    var checkdocked = function () {
	if ( navOffsetTop < window.pageYOffset &&
	     !bd.classList.contains("has-docked-nav") ) {
	    bd.classList.add("has-docked-nav");
	}

	if ( navOffsetTop > window.pageYOffset &&
	     bd.classList.contains("has-docked-nav") ) {
	    bd.classList.remove("has-docked-nav");
	}
    };

    window.addEventListener("scroll", checkdocked, false);
    window.addEventListener("resize", function () {
	bd.classList.remove("nav-has-docked");
	navOffsetTop = nav.getBoundingClientRect().top;
	checkdocked();
    }, false);

};
<|endoftext|>


<commit_before>/**
 * SetupMainv2 Component Stories.
 *
 * Site Kit by Google, Copyright 2022 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Internal dependencies
 */
import SetupMain from './SetupMain';
import WithRegistrySetup from '../../../../../../../tests/js/WithRegistrySetup';
import * as fixtures from '../../../datastore/__fixtures__';
import {
	createTestRegistry,
	WithTestRegistry,
	provideModules,
	provideSiteInfo,
} from '../../../../../../../tests/js/utils';
import { MODULES_ADSENSE } from '../../../datastore/constants';

const defaultSettings = {
	accountID: '',
	clientID: '',
	accountStatus: '',
	siteStatus: '',
	useSnippet: true,
	accountSetupComplete: false,
	siteSetupComplete: false,
};

function Template( { setupRegistry } ) {
	return (
		<WithRegistrySetup func={ setupRegistry }>
			<SetupMain />
		</WithRegistrySetup>
	);
}

function createSetupAccountStory( variation, args = {} ) {
	const {
		accounts = fixtures.accounts,
		clients = fixtures.clients,
		sites = fixtures.sites,
		referenceSiteURL = 'https://example.com',
		existingTag = false,
	} = args;

	const story = Template.bind( {} );
	story.storyName = `Account: ${ variation }`;
	story.args = {
		setupRegistry: ( registry ) => {
			const { _id: accountID } = accounts[ 0 ];
			const {
				receiveGetAccounts,
				receiveGetAlerts,
				receiveGetClients,
				receiveGetSettings,
				receiveGetSites,
				receiveGetURLChannels,
				receiveGetExistingTag,
			} = registry.dispatch( MODULES_ADSENSE );

			provideSiteInfo( registry, {
				referenceSiteURL,
			} );

			receiveGetAccounts( accounts );
			receiveGetClients( clients, { accountID } );
			receiveGetSites( sites, { accountID } );
			receiveGetSettings( { ...defaultSettings, accountID } );
			receiveGetAlerts( fixtures.alerts, { accountID } );

			registry.dispatch( MODULES_ADSENSE ).setAccountID( accountID );

			const clientID = clients.find(
				( { _accountID } ) => _accountID === accountID
			)?._id;

			if ( clientID ) {
				receiveGetURLChannels( fixtures.urlchannels, {
					accountID,
					clientID,
				} );
			}

			if ( existingTag ) {
				receiveGetExistingTag( 'ca-pub-2833782679114991' );
			}
		},
	};

	return story;
}

export const AdBlocker = Template.bind( {} );
AdBlocker.storyName = 'AdBlocker Active';
AdBlocker.args = {
	setupRegistry: ( registry ) => {
		registry.dispatch( MODULES_ADSENSE ).receiveIsAdBlockerActive( true );
		registry.dispatch( MODULES_ADSENSE ).receiveGetAccounts( [] );
	},
};

export const CreateAccount = Template.bind( {} );
CreateAccount.storyName = 'Create Account';
CreateAccount.args = {
	setupRegistry: ( registry ) => {
		registry.dispatch( MODULES_ADSENSE ).receiveGetAccounts( [] );
	},
};

export const SetupAccountSiteNeedsAttention = createSetupAccountStory(
	'Site - Needs Attention',
	{
		referenceSiteURL: 'https://example.com',
	}
);
export const SetupAccountSiteRequiresReview = createSetupAccountStory(
	'Site - Requires Review',
	{
		referenceSiteURL: 'https://www.test-site.com',
	}
);
export const SetupAccountSiteGettingReady = createSetupAccountStory(
	'Site - Getting Ready',
	{
		referenceSiteURL: 'https://bar-baz.ie',
	}
);
export const SetupAccountSiteReady = createSetupAccountStory(
	'Site - Ready w Ads Enabled',
	{
		referenceSiteURL: 'https://some-other-tld.ie',
	}
);
export const SetupAccountSiteReadyWithTag = createSetupAccountStory(
	'Site - Ready w Ads Enabled + Existing Tag',
	{
		referenceSiteURL: 'https://some-other-tld.ie',
		existingTag: true,
	}
);
export const SetupAccountSiteReadyAdsDisabled = createSetupAccountStory(
	'Site - Ready w Ads Disabled',
	{
		referenceSiteURL: 'https://foo-bar.ie',
	}
);
export const SetupAccountSiteReadyAdsDisabledWithTag = createSetupAccountStory(
	'Site - Ready w Ads Disabled + Existing Tag',
	{
		referenceSiteURL: 'https://foo-bar.ie',
		existingTag: true,
	}
);
export const SetupAccountSiteErrorState = createSetupAccountStory(
	'Site - Invalid Site State',
	{
		referenceSiteURL: 'https://invalid-error-site.com',
		sites: [
			{
				domain: 'invalid-error-site.com',
				state: 'NON_EXISTENT_SITE_STATE',
			},
		],
	}
);
export const SetupAccountNoClient = createSetupAccountStory( 'No Client', {
	clients: [ { ...fixtures.clients[ 0 ], productCode: '' } ],
} );
export const SetupAccountCreateSite = createSetupAccountStory( 'Create Site', {
	sites: [],
} );
export const SetupAccountPendingTasks = createSetupAccountStory(
	'Pending Tasks',
	{
		accounts: [
			{
				...fixtures.accountsMultiple[ 3 ],
				pendingTasks: [
					{
						_id: '1234',
					},
				],
			},
		],
	}
);

export const SelectAccount = Template.bind( {} );
SelectAccount.storyName = 'Select Account';
SelectAccount.args = {
	setupRegistry: ( registry ) => {
		registry.dispatch( MODULES_ADSENSE ).receiveGetAccounts( [
			{
				_id: 'pub-2833782679114991',
				name: 'accounts/pub-2833782679114991',
				displayName: 'Test Account',
				timeZone: {
					id: 'Europe/Berlin',
				},
				createTime: '2013-10-17T15:51:03.000Z',
			},
		] );
	},
};

export const ErrorNotice = Template.bind( {} );
ErrorNotice.storyName = 'Error Notice';
ErrorNotice.args = {
	setupRegistry: ( registry ) => {
		registry.dispatch( MODULES_ADSENSE ).receiveGetAccounts( [] );
		registry.dispatch( MODULES_ADSENSE ).receiveError(
			{
				// Typically thrown when fetching accounts.
				message: 'AdSense account is disapproved.',
				data: {
					status: 403,
					reason: 'disapprovedAccount',
				},
			},
			'getAccounts',
			[]
		);
	},
};
ErrorNotice.parameters = {
	features: [ 'adsenseSetupV2' ],
};

export default {
	title: 'Modules/AdSense/Components/Setup/V2/SetupMain',
	component: SetupMain,
	decorators: [
		( Story, { parameters } ) => {
			const registry = createTestRegistry();

			provideModules( registry, [
				{
					slug: 'adsense',
					active: true,
					connected: true,
				},
			] );

			registry
				.dispatch( MODULES_ADSENSE )
				.receiveGetSettings( defaultSettings );
			registry
				.dispatch( MODULES_ADSENSE )
				.receiveIsAdBlockerActive( false );

			return (
				<WithTestRegistry
					registry={ registry }
					features={ parameters.features || [] }
				>
					<Story />
				</WithTestRegistry>
			);
		},
	],
};
<commit_msg>Fix V2 AdSense setup stories.<commit_after>/**
 * SetupMainv2 Component Stories.
 *
 * Site Kit by Google, Copyright 2022 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Internal dependencies
 */
import SetupMain from './SetupMain';
import { Cell, Grid, Row } from '../../../../../material-components';
import WithRegistrySetup from '../../../../../../../tests/js/WithRegistrySetup';
import * as fixtures from '../../../datastore/__fixtures__';
import {
	createTestRegistry,
	WithTestRegistry,
	provideModules,
	provideSiteInfo,
} from '../../../../../../../tests/js/utils';
import { MODULES_ADSENSE } from '../../../datastore/constants';

const defaultSettings = {
	accountID: '',
	clientID: '',
	accountStatus: '',
	siteStatus: '',
	useSnippet: true,
	accountSetupComplete: false,
	siteSetupComplete: false,
};

function Template( { setupRegistry } ) {
	return (
		<WithRegistrySetup func={ setupRegistry }>

					<Grid>
						<Row>
							<Cell size={ 12 }>
								<SetupMain />
							</Cell>
						</Row>
					</Grid>

		</WithRegistrySetup>
	);
}

function createSetupAccountStory( variation, args = {} ) {
	const {
		accounts = fixtures.accounts,
		clients = fixtures.clients,
		sites = fixtures.sites,
		referenceSiteURL = 'https://example.com',
		existingTag = false,
	} = args;

	const story = Template.bind( {} );
	story.storyName = `Account: ${ variation }`;
	story.args = {
		setupRegistry: ( registry ) => {
			const { _id: accountID } = accounts[ 0 ];
			const {
				receiveGetAccounts,
				receiveGetAlerts,
				receiveGetClients,
				receiveGetSettings,
				receiveGetSites,
				receiveGetURLChannels,
				receiveGetExistingTag,
			} = registry.dispatch( MODULES_ADSENSE );

			provideSiteInfo( registry, {
				referenceSiteURL,
			} );

			receiveGetAccounts( accounts );
			receiveGetClients( clients, { accountID } );
			receiveGetSites( sites, { accountID } );
			receiveGetSettings( { ...defaultSettings, accountID } );
			receiveGetAlerts( fixtures.alerts, { accountID } );

			registry.dispatch( MODULES_ADSENSE ).setAccountID( accountID );

			const clientID = clients.find(
				( { _accountID } ) => _accountID === accountID
			)?._id;

			if ( clientID ) {
				receiveGetURLChannels( fixtures.urlchannels, {
					accountID,
					clientID,
				} );
			}

			if ( existingTag ) {
				receiveGetExistingTag( 'ca-pub-2833782679114991' );
			}
		},
	};

	return story;
}

export const AdBlocker = Template.bind( {} );
AdBlocker.storyName = 'AdBlocker Active';
AdBlocker.args = {
	setupRegistry: ( registry ) => {
		registry.dispatch( MODULES_ADSENSE ).receiveIsAdBlockerActive( true );
		registry.dispatch( MODULES_ADSENSE ).receiveGetAccounts( [] );
	},
};

export const CreateAccount = Template.bind( {} );
CreateAccount.storyName = 'Create Account';
CreateAccount.args = {
	setupRegistry: ( registry ) => {
		registry.dispatch( MODULES_ADSENSE ).receiveGetAccounts( [] );
	},
};

export const SetupAccountSiteNeedsAttention = createSetupAccountStory(
	'Site - Needs Attention',
	{
		referenceSiteURL: 'https://example.com',
	}
);
export const SetupAccountSiteRequiresReview = createSetupAccountStory(
	'Site - Requires Review',
	{
		referenceSiteURL: 'https://www.test-site.com',
	}
);
export const SetupAccountSiteGettingReady = createSetupAccountStory(
	'Site - Getting Ready',
	{
		referenceSiteURL: 'https://bar-baz.ie',
	}
);
export const SetupAccountSiteReady = createSetupAccountStory(
	'Site - Ready w Ads Enabled',
	{
		referenceSiteURL: 'https://some-other-tld.ie',
	}
);
export const SetupAccountSiteReadyWithTag = createSetupAccountStory(
	'Site - Ready w Ads Enabled + Existing Tag',
	{
		referenceSiteURL: 'https://some-other-tld.ie',
		existingTag: true,
	}
);
export const SetupAccountSiteReadyAdsDisabled = createSetupAccountStory(
	'Site - Ready w Ads Disabled',
	{
		referenceSiteURL: 'https://foo-bar.ie',
	}
);
export const SetupAccountSiteReadyAdsDisabledWithTag = createSetupAccountStory(
	'Site - Ready w Ads Disabled + Existing Tag',
	{
		referenceSiteURL: 'https://foo-bar.ie',
		existingTag: true,
	}
);
export const SetupAccountSiteErrorState = createSetupAccountStory(
	'Site - Invalid Site State',
	{
		referenceSiteURL: 'https://invalid-error-site.com',
		sites: [
			{
				domain: 'invalid-error-site.com',
				state: 'NON_EXISTENT_SITE_STATE',
			},
		],
	}
);
export const SetupAccountNoClient = createSetupAccountStory( 'No Client', {
	clients: [ { ...fixtures.clients[ 0 ], productCode: '' } ],
} );
export const SetupAccountCreateSite = createSetupAccountStory( 'Create Site', {
	sites: [],
} );
export const SetupAccountPendingTasks = createSetupAccountStory(
	'Pending Tasks',
	{
		accounts: [
			{
				...fixtures.accountsMultiple[ 3 ],
				pendingTasks: [
					{
						_id: '1234',
					},
				],
			},
		],
		existingTag: true,
	}
);

export const SelectAccount = Template.bind( {} );
SelectAccount.storyName = 'Select Account';
SelectAccount.args = {
	setupRegistry: ( registry ) => {
		registry.dispatch( MODULES_ADSENSE ).receiveGetAccounts( [
			{
				_id: 'pub-2833782679114991',
				name: 'accounts/pub-2833782679114991',
				displayName: 'Test Account',
				timeZone: {
					id: 'Europe/Berlin',
				},
				createTime: '2013-10-17T15:51:03.000Z',
			},
		] );
	},
};

export const ErrorNotice = Template.bind( {} );
ErrorNotice.storyName = 'Error Notice';
ErrorNotice.args = {
	setupRegistry: ( registry ) => {
		registry.dispatch( MODULES_ADSENSE ).receiveGetAccounts( [] );
		registry.dispatch( MODULES_ADSENSE ).receiveError(
			{
				// Typically thrown when fetching accounts.
				message: 'AdSense account is disapproved.',
				data: {
					status: 403,
					reason: 'disapprovedAccount',
				},
			},
			'getAccounts',
			[]
		);
	},
};
ErrorNotice.parameters = {
	features: [ 'adsenseSetupV2' ],
};

export default {
	title: 'Modules/AdSense/Components/Setup/V2/SetupMain',
	component: SetupMain,
	decorators: [
		( Story, { parameters } ) => {
			const registry = createTestRegistry();

			provideModules( registry, [
				{
					slug: 'adsense',
					active: true,
					connected: true,
				},
			] );

			registry
				.dispatch( MODULES_ADSENSE )
				.receiveGetSettings( defaultSettings );
			registry
				.dispatch( MODULES_ADSENSE )
				.receiveIsAdBlockerActive( false );

			return (
				<WithTestRegistry
					registry={ registry }
					features={ parameters.features || [] }
				>
					<Story />
				</WithTestRegistry>
			);
		},
	],
	parameters: { padding: 0 },
};
<|endoftext|>


<commit_before>'use strict';

var set_taxon_select = function(selector){
  if ($(selector).length > 0) {
    $(selector).select2({
      placeholder: Spree.translations.taxon_placeholder,
      multiple: true,
      initSelection: function (element, callback) {
        var url = Spree.url(Spree.routes.taxons_search, {
          ids: element.val(),
          token: Spree.api_key
        });
        return $.getJSON(url, null, function (data) {
          return callback(data['taxons']);
        });
      },
      ajax: {
        url: Spree.routes.taxons_search,
        datatype: 'json',
        data: function (term, page) {
          return {
            per_page: 50,
            page: page,
            without_children: true,
            q: {
              name_cont: term
            },
            token: Spree.api_key
          };
        },
        results: function (data, page) {
          var more = page < data.pages;
          return {
            results: data['taxons'],
            more: more
          };
        }
      },
      formatResult: function (taxon) {
        return taxon.pretty_name;
      },
      formatSelection: function (taxon) {
        return taxon.pretty_name;
      }
    });
  }
}

$(document).ready(function () {
  set_taxon_select('#product_taxon_ids')
});
<commit_msg>Increase perfs when loading a product's page<commit_after>'use strict';

var set_taxon_select = function(selector){
  if ($(selector).length > 0) {
    $(selector).select2({
      placeholder: Spree.translations.taxon_placeholder,
      multiple: true,
      initSelection: function (element, callback) {
        var url = Spree.url(Spree.routes.taxons_search, {
          ids: element.val(),
          without_children: true,
          token: Spree.api_key
        });
        return $.getJSON(url, null, function (data) {
          return callback(data['taxons']);
        });
      },
      ajax: {
        url: Spree.routes.taxons_search,
        datatype: 'json',
        data: function (term, page) {
          return {
            per_page: 50,
            page: page,
            without_children: true,
            q: {
              name_cont: term
            },
            token: Spree.api_key
          };
        },
        results: function (data, page) {
          var more = page < data.pages;
          return {
            results: data['taxons'],
            more: more
          };
        }
      },
      formatResult: function (taxon) {
        return taxon.pretty_name;
      },
      formatSelection: function (taxon) {
        return taxon.pretty_name;
      }
    });
  }
}

$(document).ready(function () {
  set_taxon_select('#product_taxon_ids')
});
<|endoftext|>


<commit_before>function sprintf() {
  //  discuss at: http://phpjs.org/functions/sprintf/
  // original by: Ash Searle (http://hexmen.com/blog/)
  // improved by: Michael White (http://getsprink.com)
  // improved by: Jack
  // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
  // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
  // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
  // improved by: Dj
  // improved by: Allidylls
  //    input by: Paulo Freitas
  //    input by: Brett Zamir (http://brett-zamir.me)
  //   example 1: sprintf("%01.2f", 123.1);
  //   returns 1: 123.10
  //   example 2: sprintf("[%10s]", 'monkey');
  //   returns 2: '[    monkey]'
  //   example 3: sprintf("[%'#10s]", 'monkey');
  //   returns 3: '[####monkey]'
  //   example 4: sprintf("%d", 123456789012345);
  //   returns 4: '123456789012345'

  var regex = /%%|%(\d+\$)?([-+\'#0 ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([scboxXuideEfFgG])/g;
  var a = arguments;
  var i = 0;
  var format = a[i++];

  // pad()
  var pad = function(str, len, chr, leftJustify) {
    if (!chr) {
      chr = ' ';
    }
    var padding = (str.length >= len) ? '' : new Array(1 + len - str.length >>> 0)
      .join(chr);
    return leftJustify ? str + padding : padding + str;
  };

  // justify()
  var justify = function(value, prefix, leftJustify, minWidth, zeroPad, customPadChar) {
    var diff = minWidth - value.length;
    if (diff > 0) {
      if (leftJustify || !zeroPad) {
        value = pad(value, minWidth, customPadChar, leftJustify);
      } else {
        value = value.slice(0, prefix.length) + pad('', diff, '0', true) + value.slice(prefix.length);
      }
    }
    return value;
  };

  // formatBaseX()
  var formatBaseX = function(value, base, prefix, leftJustify, minWidth, precision, zeroPad) {
    // Note: casts negative numbers to positive ones
    var number = value >>> 0;
    prefix = prefix && number && {
      '2': '0b',
      '8': '0',
      '16': '0x'
    }[base] || '';
    value = prefix + pad(number.toString(base), precision || 0, '0', false);
    return justify(value, prefix, leftJustify, minWidth, zeroPad);
  };

  // formatString()
  var formatString = function(value, leftJustify, minWidth, precision, zeroPad, customPadChar) {
    if (precision != null) {
      value = value.slice(0, precision);
    }
    return justify(value, '', leftJustify, minWidth, zeroPad, customPadChar);
  };

  // doFormat()
  var doFormat = function(substring, valueIndex, flags, minWidth, _, precision, type) {
    var number, prefix, method, textTransform, value;

    if (substring === '%%') {
      return '%';
    }

    // parse flags
    var leftJustify = false;
    var positivePrefix = '';
    var zeroPad = false;
    var prefixBaseX = false;
    var customPadChar = ' ';
    var flagsl = flags.length;
    for (var j = 0; flags && j < flagsl; j++) {
      switch (flags.charAt(j)) {
        case ' ':
          positivePrefix = ' ';
          break;
        case '+':
          positivePrefix = '+';
          break;
        case '-':
          leftJustify = true;
          break;
        case "'":
          customPadChar = flags.charAt(j + 1);
          break;
        case '0':
          zeroPad = true;
          customPadChar = '0';
          break;
        case '#':
          prefixBaseX = true;
          break;
      }
    }

    // parameters may be null, undefined, empty-string or real valued
    // we want to ignore null, undefined and empty-string values
    if (!minWidth) {
      minWidth = 0;
    } else if (minWidth === '*') {
      minWidth = +a[i++];
    } else if (minWidth.charAt(0) == '*') {
      minWidth = +a[minWidth.slice(1, -1)];
    } else {
      minWidth = +minWidth;
    }

    // Note: undocumented perl feature:
    if (minWidth < 0) {
      minWidth = -minWidth;
      leftJustify = true;
    }

    if (!isFinite(minWidth)) {
      throw new Error('sprintf: (minimum-)width must be finite');
    }

    if (!precision) {
      precision = 'fFeE'.indexOf(type) > -1 ? 6 : (type === 'd') ? 0 : undefined;
    } else if (precision === '*') {
      precision = +a[i++];
    } else if (precision.charAt(0) == '*') {
      precision = +a[precision.slice(1, -1)];
    } else {
      precision = +precision;
    }

    // grab value using valueIndex if required?
    value = valueIndex ? a[valueIndex.slice(0, -1)] : a[i++];

    switch (type) {
      case 's':
        return formatString(String(value), leftJustify, minWidth, precision, zeroPad, customPadChar);
      case 'c':
        return formatString(String.fromCharCode(+value), leftJustify, minWidth, precision, zeroPad);
      case 'b':
        return formatBaseX(value, 2, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
      case 'o':
        return formatBaseX(value, 8, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
      case 'x':
        return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
      case 'X':
        return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad)
          .toUpperCase();
      case 'u':
        return formatBaseX(value, 10, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
      case 'i':
      case 'd':
        number = +value || 0;
        number = Math.round(number - number % 1); // Plain Math.round doesn't just truncate
        prefix = number < 0 ? '-' : positivePrefix;
        value = prefix + pad(String(Math.abs(number)), precision, '0', false);
        return justify(value, prefix, leftJustify, minWidth, zeroPad);
      case 'e':
      case 'E':
      case 'f': // Should handle locales (as per setlocale)
      case 'F':
      case 'g':
      case 'G':
        number = +value;
        prefix = number < 0 ? '-' : positivePrefix;
        method = ['toExponential', 'toFixed', 'toPrecision']['efg'.indexOf(type.toLowerCase())];
        textTransform = ['toString', 'toUpperCase']['eEfFgG'.indexOf(type) % 2];
        value = prefix + Math.abs(number)[method](precision);
        return justify(value, prefix, leftJustify, minWidth, zeroPad)[textTransform]();
      default:
        return substring;
    }
  };

  return format.replace(regex, doFormat);
}
<commit_msg>add test case<commit_after>function sprintf() {
  //  discuss at: http://phpjs.org/functions/sprintf/
  // original by: Ash Searle (http://hexmen.com/blog/)
  // improved by: Michael White (http://getsprink.com)
  // improved by: Jack
  // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
  // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
  // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
  // improved by: Dj
  // improved by: Allidylls
  //    input by: Paulo Freitas
  //    input by: Brett Zamir (http://brett-zamir.me)
  //   example 1: sprintf("%01.2f", 123.1);
  //   returns 1: 123.10
  //   example 2: sprintf("[%10s]", 'monkey');
  //   returns 2: '[    monkey]'
  //   example 3: sprintf("[%'#10s]", 'monkey');
  //   returns 3: '[####monkey]'
  //   example 4: sprintf("%d", 123456789012345);
  //   returns 4: '123456789012345'
  //   example 4: sprintf( '%-03s', 'E' );
  //   returns 5: 'E00'

  var regex = /%%|%(\d+\$)?([-+\'#0 ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([scboxXuideEfFgG])/g;
  var a = arguments;
  var i = 0;
  var format = a[i++];

  // pad()
  var pad = function(str, len, chr, leftJustify) {
    if (!chr) {
      chr = ' ';
    }
    var padding = (str.length >= len) ? '' : new Array(1 + len - str.length >>> 0)
      .join(chr);
    return leftJustify ? str + padding : padding + str;
  };

  // justify()
  var justify = function(value, prefix, leftJustify, minWidth, zeroPad, customPadChar) {
    var diff = minWidth - value.length;
    if (diff > 0) {
      if (leftJustify || !zeroPad) {
        value = pad(value, minWidth, customPadChar, leftJustify);
      } else {
        value = value.slice(0, prefix.length) + pad('', diff, '0', true) + value.slice(prefix.length);
      }
    }
    return value;
  };

  // formatBaseX()
  var formatBaseX = function(value, base, prefix, leftJustify, minWidth, precision, zeroPad) {
    // Note: casts negative numbers to positive ones
    var number = value >>> 0;
    prefix = prefix && number && {
      '2': '0b',
      '8': '0',
      '16': '0x'
    }[base] || '';
    value = prefix + pad(number.toString(base), precision || 0, '0', false);
    return justify(value, prefix, leftJustify, minWidth, zeroPad);
  };

  // formatString()
  var formatString = function(value, leftJustify, minWidth, precision, zeroPad, customPadChar) {
    if (precision != null) {
      value = value.slice(0, precision);
    }
    return justify(value, '', leftJustify, minWidth, zeroPad, customPadChar);
  };

  // doFormat()
  var doFormat = function(substring, valueIndex, flags, minWidth, _, precision, type) {
    var number, prefix, method, textTransform, value;

    if (substring === '%%') {
      return '%';
    }

    // parse flags
    var leftJustify = false;
    var positivePrefix = '';
    var zeroPad = false;
    var prefixBaseX = false;
    var customPadChar = ' ';
    var flagsl = flags.length;
    for (var j = 0; flags && j < flagsl; j++) {
      switch (flags.charAt(j)) {
        case ' ':
          positivePrefix = ' ';
          break;
        case '+':
          positivePrefix = '+';
          break;
        case '-':
          leftJustify = true;
          break;
        case "'":
          customPadChar = flags.charAt(j + 1);
          break;
        case '0':
          zeroPad = true;
          customPadChar = '0';
          break;
        case '#':
          prefixBaseX = true;
          break;
      }
    }

    // parameters may be null, undefined, empty-string or real valued
    // we want to ignore null, undefined and empty-string values
    if (!minWidth) {
      minWidth = 0;
    } else if (minWidth === '*') {
      minWidth = +a[i++];
    } else if (minWidth.charAt(0) == '*') {
      minWidth = +a[minWidth.slice(1, -1)];
    } else {
      minWidth = +minWidth;
    }

    // Note: undocumented perl feature:
    if (minWidth < 0) {
      minWidth = -minWidth;
      leftJustify = true;
    }

    if (!isFinite(minWidth)) {
      throw new Error('sprintf: (minimum-)width must be finite');
    }

    if (!precision) {
      precision = 'fFeE'.indexOf(type) > -1 ? 6 : (type === 'd') ? 0 : undefined;
    } else if (precision === '*') {
      precision = +a[i++];
    } else if (precision.charAt(0) == '*') {
      precision = +a[precision.slice(1, -1)];
    } else {
      precision = +precision;
    }

    // grab value using valueIndex if required?
    value = valueIndex ? a[valueIndex.slice(0, -1)] : a[i++];

    switch (type) {
      case 's':
        return formatString(String(value), leftJustify, minWidth, precision, zeroPad, customPadChar);
      case 'c':
        return formatString(String.fromCharCode(+value), leftJustify, minWidth, precision, zeroPad);
      case 'b':
        return formatBaseX(value, 2, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
      case 'o':
        return formatBaseX(value, 8, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
      case 'x':
        return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
      case 'X':
        return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad)
          .toUpperCase();
      case 'u':
        return formatBaseX(value, 10, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
      case 'i':
      case 'd':
        number = +value || 0;
        number = Math.round(number - number % 1); // Plain Math.round doesn't just truncate
        prefix = number < 0 ? '-' : positivePrefix;
        value = prefix + pad(String(Math.abs(number)), precision, '0', false);
        return justify(value, prefix, leftJustify, minWidth, zeroPad);
      case 'e':
      case 'E':
      case 'f': // Should handle locales (as per setlocale)
      case 'F':
      case 'g':
      case 'G':
        number = +value;
        prefix = number < 0 ? '-' : positivePrefix;
        method = ['toExponential', 'toFixed', 'toPrecision']['efg'.indexOf(type.toLowerCase())];
        textTransform = ['toString', 'toUpperCase']['eEfFgG'.indexOf(type) % 2];
        value = prefix + Math.abs(number)[method](precision);
        return justify(value, prefix, leftJustify, minWidth, zeroPad)[textTransform]();
      default:
        return substring;
    }
  };

  return format.replace(regex, doFormat);
}
<|endoftext|>


<commit_before>class PerfectNumbers {
  classify(num) {
    if (num < 1) throw 'Classification is only possible for natural numbers.';

    const aliquotSum = this.factors(num).reduce((acc, val) => acc + val, 0);
    if (aliquotSum === num) {
      return 'perfect';
    } else if (aliquotSum > num) {
      return 'abundant';
    }
    return 'deficient';
  }

  factors(num) {
    const startNum = Math.floor(num / 2);
    const intRange = [...Array(startNum).keys()].map(i => i+1);
    return intRange.filter(div => this.isDivisor(num, div));
  }

  isDivisor(num, div) {
    return num % div === 0;
  }
}

export default PerfectNumbers;
<commit_msg>Do proper test of int<commit_after>class PerfectNumbers {
  classify(num) {
    if (!Number.isInteger(num) || num < 1) throw 'Classification is only possible for natural numbers.';

    const aliquotSum = this.factors(num).reduce((acc, val) => acc + val, 0);
    if (aliquotSum === num) {
      return 'perfect';
    } else if (aliquotSum > num) {
      return 'abundant';
    }
    return 'deficient';
  }

  factors(num) {
    const startNum = Math.floor(num / 2);
    const intRange = [...Array(startNum).keys()].map(i => i+1);
    return intRange.filter(div => this.isDivisor(num, div));
  }

  isDivisor(num, div) {
    return num % div === 0;
  }
}

export default PerfectNumbers;
<|endoftext|>