<commit_before>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule Slider
 * @flow
 */
'use strict';

var Image = require('Image');
var ColorPropType = require('ColorPropType');
var NativeMethodsMixin = require('NativeMethodsMixin');
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
var Platform = require('Platform');
var React = require('React');
var PropTypes = require('prop-types');
var StyleSheet = require('StyleSheet');
var ViewPropTypes = require('ViewPropTypes');

var createReactClass = require('create-react-class');
var requireNativeComponent = require('requireNativeComponent');

type Event = Object;

/**
 * A component used to select a single value from a range of values.
 */
var Slider = createReactClass({
  displayName: 'Slider',
  mixins: [NativeMethodsMixin],

  propTypes: {
    ...ViewPropTypes,

    /**
     * Used to style and layout the `Slider`.  See `StyleSheet.js` and
     * `ViewStylePropTypes.js` for more info.
     */
    style: ViewPropTypes.style,

    /**
     * Initial value of the slider. The value should be between minimumValue
     * and maximumValue, which default to 0 and 1 respectively.
     * Default value is 0.
     *
     * *This is not a controlled component*, you don't need to update the
     * value during dragging.
     */
    value: PropTypes.number,

    /**
     * Step value of the slider. The value should be
     * between 0 and (maximumValue - minimumValue).
     * Default value is 0.
     */
    step: PropTypes.number,

    /**
     * Initial minimum value of the slider. Default value is 0.
     */
    minimumValue: PropTypes.number,

    /**
     * Initial maximum value of the slider. Default value is 1.
     */
    maximumValue: PropTypes.number,

    /**
     * The color used for the track to the left of the button.
     * Overrides the default blue gradient image on iOS.
     */
    minimumTrackTintColor: ColorPropType,

    /**
     * The color used for the track to the right of the button.
     * Overrides the default blue gradient image on iOS.
     */
    maximumTrackTintColor: ColorPropType,

    /**
     * If true the user won't be able to move the slider.
     * Default value is false.
     */
    disabled: PropTypes.bool,

    /**
     * Assigns a single image for the track. Only static images are supported.
     * The center pixel of the image will be stretched to fill the track.
     * @platform ios
     */
    trackImage: Image.propTypes.source,

    /**
     * Assigns a minimum track image. Only static images are supported. The
     * rightmost pixel of the image will be stretched to fill the track.
     * @platform ios
     */
    minimumTrackImage: Image.propTypes.source,

    /**
     * Assigns a maximum track image. Only static images are supported. The
     * leftmost pixel of the image will be stretched to fill the track.
     * @platform ios
     */
    maximumTrackImage: Image.propTypes.source,

    /**
     * Sets an image for the thumb. Only static images are supported.
     * @platform ios
     */
    thumbImage: Image.propTypes.source,

    /**
     * Color of the foreground switch grip.
     * @platform android
     */
    thumbTintColor: ColorPropType,

    /**
     * Callback continuously called while the user is dragging the slider.
     */
    onValueChange: PropTypes.func,

    /**
     * Callback that is called when the user releases the slider,
     * regardless if the value has changed. The current value is passed
     * as an argument to the callback handler.
     */
    onSlidingComplete: PropTypes.func,

    /**
     * Used to locate this view in UI automation tests.
     */
    testID: PropTypes.string,
  },

  getDefaultProps: function() : any {
    return {
      disabled: false,
      value: 0,
      minimumValue: 0,
      maximumValue: 1,
      step: 0
    };
  },

  viewConfig: {
    uiViewClassName: 'RCTSlider',
    validAttributes: {
      ...ReactNativeViewAttributes.RCTView,
      value: true
    }
  },

  render: function() {
    const {style, onValueChange, onSlidingComplete, ...props} = this.props;
    /* $FlowFixMe(>=0.54.0 site=react_native_fb,react_native_oss) This comment
     * suppresses an error found when Flow v0.54 was deployed. To see the error
     * delete this comment and run Flow. */
    props.style = [styles.slider, style];

    /* $FlowFixMe(>=0.54.0 site=react_native_fb,react_native_oss) This comment
     * suppresses an error found when Flow v0.54 was deployed. To see the error
     * delete this comment and run Flow. */
    props.onValueChange = onValueChange && ((event: Event) => {
      let userEvent = true;
      if (Platform.OS === 'android') {
        // On Android there's a special flag telling us the user is
        // dragging the slider.
        userEvent = event.nativeEvent.fromUser;
      }
      onValueChange && userEvent && onValueChange(event.nativeEvent.value);
    });

    /* $FlowFixMe(>=0.54.0 site=react_native_fb,react_native_oss) This comment
     * suppresses an error found when Flow v0.54 was deployed. To see the error
     * delete this comment and run Flow. */
    props.onChange = props.onValueChange;

    /* $FlowFixMe(>=0.54.0 site=react_native_fb,react_native_oss) This comment
     * suppresses an error found when Flow v0.54 was deployed. To see the error
     * delete this comment and run Flow. */
    props.onSlidingComplete = onSlidingComplete && ((event: Event) => {
      onSlidingComplete && onSlidingComplete(event.nativeEvent.value);
    });

    return <RCTSlider
      {...props}
      enabled={!this.props.disabled}
      onStartShouldSetResponder={() => true}
      onResponderTerminationRequest={() => false}
    />;
  }
});

let styles;
if (Platform.OS === 'ios') {
  styles = StyleSheet.create({
    slider: {
      height: 40,
    },
  });
} else {
  styles = StyleSheet.create({
    slider: {},
  });
}

let options = {};
if (Platform.OS === 'android') {
  options = {
    nativeOnly: {
      enabled: true,
    }
  };
}
const RCTSlider = requireNativeComponent('RCTSlider', Slider, options);

module.exports = Slider;
<commit_msg>Docs: Improve documentation of Slider (add example)<commit_after>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule Slider
 * @flow
 */
'use strict';

var Image = require('Image');
var ColorPropType = require('ColorPropType');
var NativeMethodsMixin = require('NativeMethodsMixin');
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
var Platform = require('Platform');
var React = require('React');
var PropTypes = require('prop-types');
var StyleSheet = require('StyleSheet');
var ViewPropTypes = require('ViewPropTypes');

var createReactClass = require('create-react-class');
var requireNativeComponent = require('requireNativeComponent');

type Event = Object;

/**
 * A component used to select a single value from a range of values.
 *
 * ### Usage
 *
 * The example below shows how to use `Slider` to change
 * a value used by `Text`. The value is stored using
 * the state of the root component (`App`). The same component
 * subscribes to the `onValueChange`  of `Slider` and changes
 * the value using `setState`.
 *
 *```
 * import React from 'react';
 * import { StyleSheet, Text, View, Slider } from 'react-native';
 *
 * export default class App extends React.Component {
 *   constructor(props) {
 *     super(props);
 *     this.state = {
 *       value: 50
 *     }
 *   }
 *
 *   change(value) {
 *     this.setState(() => {
 *       return {
 *         value: parseFloat(value)
 *       };
 *     });
 *   }
 *
 *   render() {
 *     const {value} = this.state;
 *     return (
 *       <View style={styles.container}>
 *         <Text style={styles.text}>{String(value)}</Text>
 *         <Slider
 *           step={1}
 *           maximumValue={100}
 *           onValueChange={this.change.bind(this)}
 *           value={value} />
 *       </View>
 *     );
 *   }
 * }
 *
 * const styles = StyleSheet.create({
 *   container: {
 *     flex: 1,
 *     flexDirection: 'column',
 *     justifyContent: 'center'
 *   },
 *   text: {
 *     fontSize: 50,
 *     textAlign: 'center'
 *   }
 * });
 *```
 *
 */
var Slider = createReactClass({
  displayName: 'Slider',
  mixins: [NativeMethodsMixin],

  propTypes: {
    ...ViewPropTypes,

    /**
     * Used to style and layout the `Slider`.  See `StyleSheet.js` and
     * `ViewStylePropTypes.js` for more info.
     */
    style: ViewPropTypes.style,

    /**
     * Initial value of the slider. The value should be between minimumValue
     * and maximumValue, which default to 0 and 1 respectively.
     * Default value is 0.
     *
     * *This is not a controlled component*, you don't need to update the
     * value during dragging.
     */
    value: PropTypes.number,

    /**
     * Step value of the slider. The value should be
     * between 0 and (maximumValue - minimumValue).
     * Default value is 0.
     */
    step: PropTypes.number,

    /**
     * Initial minimum value of the slider. Default value is 0.
     */
    minimumValue: PropTypes.number,

    /**
     * Initial maximum value of the slider. Default value is 1.
     */
    maximumValue: PropTypes.number,

    /**
     * The color used for the track to the left of the button.
     * Overrides the default blue gradient image on iOS.
     */
    minimumTrackTintColor: ColorPropType,

    /**
     * The color used for the track to the right of the button.
     * Overrides the default blue gradient image on iOS.
     */
    maximumTrackTintColor: ColorPropType,

    /**
     * If true the user won't be able to move the slider.
     * Default value is false.
     */
    disabled: PropTypes.bool,

    /**
     * Assigns a single image for the track. Only static images are supported.
     * The center pixel of the image will be stretched to fill the track.
     * @platform ios
     */
    trackImage: Image.propTypes.source,

    /**
     * Assigns a minimum track image. Only static images are supported. The
     * rightmost pixel of the image will be stretched to fill the track.
     * @platform ios
     */
    minimumTrackImage: Image.propTypes.source,

    /**
     * Assigns a maximum track image. Only static images are supported. The
     * leftmost pixel of the image will be stretched to fill the track.
     * @platform ios
     */
    maximumTrackImage: Image.propTypes.source,

    /**
     * Sets an image for the thumb. Only static images are supported.
     * @platform ios
     */
    thumbImage: Image.propTypes.source,

    /**
     * Color of the foreground switch grip.
     * @platform android
     */
    thumbTintColor: ColorPropType,

    /**
     * Callback continuously called while the user is dragging the slider.
     */
    onValueChange: PropTypes.func,

    /**
     * Callback that is called when the user releases the slider,
     * regardless if the value has changed. The current value is passed
     * as an argument to the callback handler.
     */
    onSlidingComplete: PropTypes.func,

    /**
     * Used to locate this view in UI automation tests.
     */
    testID: PropTypes.string,
  },

  getDefaultProps: function() : any {
    return {
      disabled: false,
      value: 0,
      minimumValue: 0,
      maximumValue: 1,
      step: 0
    };
  },

  viewConfig: {
    uiViewClassName: 'RCTSlider',
    validAttributes: {
      ...ReactNativeViewAttributes.RCTView,
      value: true
    }
  },

  render: function() {
    const {style, onValueChange, onSlidingComplete, ...props} = this.props;
    /* $FlowFixMe(>=0.54.0 site=react_native_fb,react_native_oss) This comment
     * suppresses an error found when Flow v0.54 was deployed. To see the error
     * delete this comment and run Flow. */
    props.style = [styles.slider, style];

    /* $FlowFixMe(>=0.54.0 site=react_native_fb,react_native_oss) This comment
     * suppresses an error found when Flow v0.54 was deployed. To see the error
     * delete this comment and run Flow. */
    props.onValueChange = onValueChange && ((event: Event) => {
      let userEvent = true;
      if (Platform.OS === 'android') {
        // On Android there's a special flag telling us the user is
        // dragging the slider.
        userEvent = event.nativeEvent.fromUser;
      }
      onValueChange && userEvent && onValueChange(event.nativeEvent.value);
    });

    /* $FlowFixMe(>=0.54.0 site=react_native_fb,react_native_oss) This comment
     * suppresses an error found when Flow v0.54 was deployed. To see the error
     * delete this comment and run Flow. */
    props.onChange = props.onValueChange;

    /* $FlowFixMe(>=0.54.0 site=react_native_fb,react_native_oss) This comment
     * suppresses an error found when Flow v0.54 was deployed. To see the error
     * delete this comment and run Flow. */
    props.onSlidingComplete = onSlidingComplete && ((event: Event) => {
      onSlidingComplete && onSlidingComplete(event.nativeEvent.value);
    });

    return <RCTSlider
      {...props}
      enabled={!this.props.disabled}
      onStartShouldSetResponder={() => true}
      onResponderTerminationRequest={() => false}
    />;
  }
});

let styles;
if (Platform.OS === 'ios') {
  styles = StyleSheet.create({
    slider: {
      height: 40,
    },
  });
} else {
  styles = StyleSheet.create({
    slider: {},
  });
}

let options = {};
if (Platform.OS === 'android') {
  options = {
    nativeOnly: {
      enabled: true,
    }
  };
}
const RCTSlider = requireNativeComponent('RCTSlider', Slider, options);

module.exports = Slider;
<|endoftext|>


<commit_before>angular
  .module('app')
  .controller('SearchRailsController', SearchRailsController)

  function SearchRailsController(Artwork) {
    var vm = this

    this.submit = function(location) {
       Artwork.getArtworksLocation(location).success(function(res) {
         vm.artworks = res.artworks
       })
    }
  }
<commit_msg>angular successfully displays filtered artworks<commit_after>angular
  .module('app')
  .controller('SearchRailsController', SearchRailsController)

  function SearchRailsController(Artwork) {
    var vm = this

    this.submit = function(location, movement, title) {
      l = location.toLowerCase()
      m = movement.toLowerCase()
      t = title.toLowerCase().replace(/ /g, '-')

       Artwork.searchRails(l, m, t).success(function(res) {
         vm.artworks = res.artworks
       })
    }
  }
<|endoftext|>


<commit_before>/*
Copyright 2018 New Vector Ltd

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.
*/

import React from 'react';

import sdk from '../../../index';
import MatrixClientPeg from '../../../MatrixClientPeg';
import { _t } from '../../../languageHandler';
import Modal from '../../../Modal';

export default class KeyBackupPanel extends React.PureComponent {
    constructor(props) {
        super(props);

        this._startNewBackup = this._startNewBackup.bind(this);
        this._deleteBackup = this._deleteBackup.bind(this);
        this._onKeyBackupSessionsRemaining =
            this._onKeyBackupSessionsRemaining.bind(this);
        this._onKeyBackupStatus = this._onKeyBackupStatus.bind(this);
        this._restoreBackup = this._restoreBackup.bind(this);

        this._unmounted = false;
        this.state = {
            loading: true,
            error: null,
            backupInfo: null,
            sessionsRemaining: 0,
        };
    }

    componentWillMount() {
        this._checkKeyBackupStatus();

        MatrixClientPeg.get().on('crypto.keyBackupStatus', this._onKeyBackupStatus);
        MatrixClientPeg.get().on(
            'crypto.keyBackupSessionsRemaining',
            this._onKeyBackupSessionsRemaining,
        );
    }

    componentWillUnmount() {
        this._unmounted = true;

        if (MatrixClientPeg.get()) {
            MatrixClientPeg.get().removeListener('crypto.keyBackupStatus', this._onKeyBackupStatus);
            MatrixClientPeg.get().removeListener(
                'crypto.keyBackupSessionsRemaining',
                this._onKeyBackupSessionsRemaining,
            );
        }
    }

    _onKeyBackupSessionsRemaining(sessionsRemaining) {
        this.setState({
            sessionsRemaining,
        });
    }

    _onKeyBackupStatus() {
        // This just loads the current backup status rather than forcing
        // a re-check otherwise we risk causing infinite loops
        this._loadBackupStatus();
    }

    async _checkKeyBackupStatus() {
        try {
            const {backupInfo, trustInfo} = await MatrixClientPeg.get().checkKeyBackup();
            this.setState({
                backupInfo,
                backupSigStatus: trustInfo,
                error: null,
                loading: false,
            });
        } catch (e) {
            console.log("Unable to fetch check backup status", e);
            if (this._unmounted) return;
            this.setState({
                error: e,
                backupInfo: null,
                backupSigStatus: null,
                loading: false,
            });
        }
    }

    async _loadBackupStatus() {
        this.setState({loading: true});
        try {
            const backupInfo = await MatrixClientPeg.get().getKeyBackupVersion();
            const backupSigStatus = await MatrixClientPeg.get().isKeyBackupTrusted(backupInfo);
            if (this._unmounted) return;
            this.setState({
                error: null,
                backupInfo,
                backupSigStatus,
                loading: false,
            });
        } catch (e) {
            console.log("Unable to fetch key backup status", e);
            if (this._unmounted) return;
            this.setState({
                error: e,
                backupInfo: null,
                backupSigStatus: null,
                loading: false,
            });
        }
    }

    _startNewBackup() {
        Modal.createTrackedDialogAsync('Key Backup', 'Key Backup',
            import('../../../async-components/views/dialogs/keybackup/CreateKeyBackupDialog'),
            {
                onFinished: () => {
                    this._loadBackupStatus();
                },
            },
        );
    }

    _deleteBackup() {
        const QuestionDialog = sdk.getComponent('dialogs.QuestionDialog');
        Modal.createTrackedDialog('Delete Backup', '', QuestionDialog, {
            title: _t('Delete Backup'),
            description: _t(
                "Are you sure? You will lose your encrypted messages if your " +
                "keys are not backed up properly.",
            ),
            button: _t('Delete Backup'),
            danger: true,
            onFinished: (proceed) => {
                if (!proceed) return;
                this.setState({loading: true});
                MatrixClientPeg.get().deleteKeyBackupVersion(this.state.backupInfo.version).then(() => {
                    this._loadBackupStatus();
                });
            },
        });
    }

    _restoreBackup() {
        const RestoreKeyBackupDialog = sdk.getComponent('dialogs.keybackup.RestoreKeyBackupDialog');
        Modal.createTrackedDialog('Restore Backup', '', RestoreKeyBackupDialog, {
        });
    }

    render() {
        const Spinner = sdk.getComponent("elements.Spinner");
        const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
        const encryptedMessageAreEncrypted = _t(
            "Encrypted messages are secured with end-to-end encryption. " +
            "Only you and the recipient(s) have the keys to read these messages.",
        );

        if (this.state.error) {
            return (

                    {_t("Unable to load key backup status")}

            );
        } else if (this.state.loading) {
            return <Spinner />;
        } else if (this.state.backupInfo) {
            let clientBackupStatus;
            let restoreButtonCaption = _t("Restore from Backup");

            if (MatrixClientPeg.get().getKeyBackupEnabled()) {
                clientBackupStatus =

{encryptedMessageAreEncrypted}

✅ {_t("This device is backing up your keys. ")}

;
            } else {
                clientBackupStatus =

{encryptedMessageAreEncrypted}

{_t(
                        "This device is not backing up your keys, " +
                        "but you do have an existing backup you can restore from " +
                        "and add to going forward.", {},
                        {b: sub => {sub}},
                    )}

{_t(
                        "Connect this device to key backup before signing out to avoid " +
                        "losing any keys that may only be on this device.",
                    )}

;
                restoreButtonCaption = _t("Connect this device to Key Backup");
            }

            let uploadStatus;
            const { sessionsRemaining } = this.state;
            if (!MatrixClientPeg.get().getKeyBackupEnabled()) {
                // No upload status to show when backup disabled.
                uploadStatus = "";
            } else if (sessionsRemaining > 0) {
                uploadStatus =

                    {_t("Backing up %(sessionsRemaining)s keys...", { sessionsRemaining })}

;
            } else {
                uploadStatus =

                    {_t("All keys backed up")}

;
            }

            let backupSigStatuses = this.state.backupSigStatus.sigs.map((sig, i) => {
                const deviceName = sig.device ? (sig.device.getDisplayName() || sig.device.deviceId) : null;
                const validity = sub =>

                        {sub}
                    ;
                const verify = sub =>

                        {sub}
                    ;
                const device = sub => {deviceName};
                const fromThisDevice = (
                    sig.device &&
                    sig.device.getFingerprint() === MatrixClientPeg.get().getDeviceEd25519Key()
                );
                let sigStatus;
                if (!sig.device) {
                    sigStatus = _t(
                        "Backup has a signature from <verify>unknown</verify> device with ID %(deviceId)s.",
                        { deviceId: sig.deviceId }, { verify },
                    );
                } else if (sig.valid && fromThisDevice) {
                    sigStatus = _t(
                        "Backup has a <validity>valid</validity> signature from this device",
                        {}, { validity },
                    );
                } else if (!sig.valid && fromThisDevice) {
                    // it can happen...
                    sigStatus = _t(
                        "Backup has an <validity>invalid</validity> signature from this device",
                        {}, { validity },
                    );
                } else if (sig.valid && sig.device.isVerified()) {
                    sigStatus = _t(
                        "Backup has a <validity>valid</validity> signature from " +
                        "<verify>verified</verify> device <device></device>",
                        {}, { validity, verify, device },
                    );
                } else if (sig.valid && !sig.device.isVerified()) {
                    sigStatus = _t(
                        "Backup has a <validity>valid</validity> signature from " +
                        "<verify>unverified</verify> device <device></device>",
                        {}, { validity, verify, device },
                    );
                } else if (!sig.valid && sig.device.isVerified()) {
                    sigStatus = _t(
                        "Backup has an <validity>invalid</validity> signature from " +
                        "<verify>verified</verify> device <device></device>",
                        {}, { validity, verify, device },
                    );
                } else if (!sig.valid && !sig.device.isVerified()) {
                    sigStatus = _t(
                        "Backup has an <validity>invalid</validity> signature from " +
                        "<verify>unverified</verify> device <device></device>",
                        {}, { validity, verify, device },
                    );
                }

                return

                    {sigStatus}

;
            });
            if (this.state.backupSigStatus.sigs.length === 0) {
                backupSigStatuses = _t("Backup is not signed by any of your devices");
            }

            let trustedLocally;
            if (this.state.backupSigStatus.trusted_locally) {
                trustedLocally = _t("This backup is trusted because it has been restored on this device");
            }

            return

{clientBackupStatus}

                    {_t("Advanced")}

{_t("Backup version: ")}{this.state.backupInfo.version}

{_t("Algorithm: ")}{this.state.backupInfo.algorithm}

                    {uploadStatus}

{backupSigStatuses}

{trustedLocally}

                    <AccessibleButton kind="primary" onClick={this._restoreBackup}>
                        {restoreButtonCaption}
                    </AccessibleButton>
                    <AccessibleButton kind="danger" onClick={this._deleteBackup}>
                        { _t("Delete Backup") }
                    </AccessibleButton>

;
        } else {
            return

{_t(
                        "Your keys are not being backed up from this device.", {},
                        {b: sub => {sub}},
                    )}

{encryptedMessageAreEncrypted}

{_t("Back up your keys before signing out to avoid losing them.")}

                <AccessibleButton kind="primary" onClick={this._startNewBackup}>
                    { _t("Start using Key Backup") }
                </AccessibleButton>

;
        }
    }
}
<commit_msg>Switch to function properties to avoid manual binding in KeyBackupPanel<commit_after>/*
Copyright 2018 New Vector Ltd

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.
*/

import React from 'react';

import sdk from '../../../index';
import MatrixClientPeg from '../../../MatrixClientPeg';
import { _t } from '../../../languageHandler';
import Modal from '../../../Modal';

export default class KeyBackupPanel extends React.PureComponent {
    constructor(props) {
        super(props);

        this._unmounted = false;
        this.state = {
            loading: true,
            error: null,
            backupInfo: null,
            sessionsRemaining: 0,
        };
    }

    componentWillMount() {
        this._checkKeyBackupStatus();

        MatrixClientPeg.get().on('crypto.keyBackupStatus', this._onKeyBackupStatus);
        MatrixClientPeg.get().on(
            'crypto.keyBackupSessionsRemaining',
            this._onKeyBackupSessionsRemaining,
        );
    }

    componentWillUnmount() {
        this._unmounted = true;

        if (MatrixClientPeg.get()) {
            MatrixClientPeg.get().removeListener('crypto.keyBackupStatus', this._onKeyBackupStatus);
            MatrixClientPeg.get().removeListener(
                'crypto.keyBackupSessionsRemaining',
                this._onKeyBackupSessionsRemaining,
            );
        }
    }

    _onKeyBackupSessionsRemaining = (sessionsRemaining) => {
        this.setState({
            sessionsRemaining,
        });
    }

    _onKeyBackupStatus = () => {
        // This just loads the current backup status rather than forcing
        // a re-check otherwise we risk causing infinite loops
        this._loadBackupStatus();
    }

    async _checkKeyBackupStatus() {
        try {
            const {backupInfo, trustInfo} = await MatrixClientPeg.get().checkKeyBackup();
            this.setState({
                backupInfo,
                backupSigStatus: trustInfo,
                error: null,
                loading: false,
            });
        } catch (e) {
            console.log("Unable to fetch check backup status", e);
            if (this._unmounted) return;
            this.setState({
                error: e,
                backupInfo: null,
                backupSigStatus: null,
                loading: false,
            });
        }
    }

    async _loadBackupStatus() {
        this.setState({loading: true});
        try {
            const backupInfo = await MatrixClientPeg.get().getKeyBackupVersion();
            const backupSigStatus = await MatrixClientPeg.get().isKeyBackupTrusted(backupInfo);
            if (this._unmounted) return;
            this.setState({
                error: null,
                backupInfo,
                backupSigStatus,
                loading: false,
            });
        } catch (e) {
            console.log("Unable to fetch key backup status", e);
            if (this._unmounted) return;
            this.setState({
                error: e,
                backupInfo: null,
                backupSigStatus: null,
                loading: false,
            });
        }
    }

    _startNewBackup = () => {
        Modal.createTrackedDialogAsync('Key Backup', 'Key Backup',
            import('../../../async-components/views/dialogs/keybackup/CreateKeyBackupDialog'),
            {
                onFinished: () => {
                    this._loadBackupStatus();
                },
            },
        );
    }

    _deleteBackup = () => {
        const QuestionDialog = sdk.getComponent('dialogs.QuestionDialog');
        Modal.createTrackedDialog('Delete Backup', '', QuestionDialog, {
            title: _t('Delete Backup'),
            description: _t(
                "Are you sure? You will lose your encrypted messages if your " +
                "keys are not backed up properly.",
            ),
            button: _t('Delete Backup'),
            danger: true,
            onFinished: (proceed) => {
                if (!proceed) return;
                this.setState({loading: true});
                MatrixClientPeg.get().deleteKeyBackupVersion(this.state.backupInfo.version).then(() => {
                    this._loadBackupStatus();
                });
            },
        });
    }

    _restoreBackup = () => {
        const RestoreKeyBackupDialog = sdk.getComponent('dialogs.keybackup.RestoreKeyBackupDialog');
        Modal.createTrackedDialog('Restore Backup', '', RestoreKeyBackupDialog, {
        });
    }

    render() {
        const Spinner = sdk.getComponent("elements.Spinner");
        const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
        const encryptedMessageAreEncrypted = _t(
            "Encrypted messages are secured with end-to-end encryption. " +
            "Only you and the recipient(s) have the keys to read these messages.",
        );

        if (this.state.error) {
            return (

                    {_t("Unable to load key backup status")}

            );
        } else if (this.state.loading) {
            return <Spinner />;
        } else if (this.state.backupInfo) {
            let clientBackupStatus;
            let restoreButtonCaption = _t("Restore from Backup");

            if (MatrixClientPeg.get().getKeyBackupEnabled()) {
                clientBackupStatus =

{encryptedMessageAreEncrypted}

✅ {_t("This device is backing up your keys. ")}

;
            } else {
                clientBackupStatus =

{encryptedMessageAreEncrypted}

{_t(
                        "This device is not backing up your keys, " +
                        "but you do have an existing backup you can restore from " +
                        "and add to going forward.", {},
                        {b: sub => {sub}},
                    )}

{_t(
                        "Connect this device to key backup before signing out to avoid " +
                        "losing any keys that may only be on this device.",
                    )}

;
                restoreButtonCaption = _t("Connect this device to Key Backup");
            }

            let uploadStatus;
            const { sessionsRemaining } = this.state;
            if (!MatrixClientPeg.get().getKeyBackupEnabled()) {
                // No upload status to show when backup disabled.
                uploadStatus = "";
            } else if (sessionsRemaining > 0) {
                uploadStatus =

                    {_t("Backing up %(sessionsRemaining)s keys...", { sessionsRemaining })}

;
            } else {
                uploadStatus =

                    {_t("All keys backed up")}

;
            }

            let backupSigStatuses = this.state.backupSigStatus.sigs.map((sig, i) => {
                const deviceName = sig.device ? (sig.device.getDisplayName() || sig.device.deviceId) : null;
                const validity = sub =>

                        {sub}
                    ;
                const verify = sub =>

                        {sub}
                    ;
                const device = sub => {deviceName};
                const fromThisDevice = (
                    sig.device &&
                    sig.device.getFingerprint() === MatrixClientPeg.get().getDeviceEd25519Key()
                );
                let sigStatus;
                if (!sig.device) {
                    sigStatus = _t(
                        "Backup has a signature from <verify>unknown</verify> device with ID %(deviceId)s.",
                        { deviceId: sig.deviceId }, { verify },
                    );
                } else if (sig.valid && fromThisDevice) {
                    sigStatus = _t(
                        "Backup has a <validity>valid</validity> signature from this device",
                        {}, { validity },
                    );
                } else if (!sig.valid && fromThisDevice) {
                    // it can happen...
                    sigStatus = _t(
                        "Backup has an <validity>invalid</validity> signature from this device",
                        {}, { validity },
                    );
                } else if (sig.valid && sig.device.isVerified()) {
                    sigStatus = _t(
                        "Backup has a <validity>valid</validity> signature from " +
                        "<verify>verified</verify> device <device></device>",
                        {}, { validity, verify, device },
                    );
                } else if (sig.valid && !sig.device.isVerified()) {
                    sigStatus = _t(
                        "Backup has a <validity>valid</validity> signature from " +
                        "<verify>unverified</verify> device <device></device>",
                        {}, { validity, verify, device },
                    );
                } else if (!sig.valid && sig.device.isVerified()) {
                    sigStatus = _t(
                        "Backup has an <validity>invalid</validity> signature from " +
                        "<verify>verified</verify> device <device></device>",
                        {}, { validity, verify, device },
                    );
                } else if (!sig.valid && !sig.device.isVerified()) {
                    sigStatus = _t(
                        "Backup has an <validity>invalid</validity> signature from " +
                        "<verify>unverified</verify> device <device></device>",
                        {}, { validity, verify, device },
                    );
                }

                return

                    {sigStatus}

;
            });
            if (this.state.backupSigStatus.sigs.length === 0) {
                backupSigStatuses = _t("Backup is not signed by any of your devices");
            }

            let trustedLocally;
            if (this.state.backupSigStatus.trusted_locally) {
                trustedLocally = _t("This backup is trusted because it has been restored on this device");
            }

            return

{clientBackupStatus}

                    {_t("Advanced")}

{_t("Backup version: ")}{this.state.backupInfo.version}

{_t("Algorithm: ")}{this.state.backupInfo.algorithm}

                    {uploadStatus}

{backupSigStatuses}

{trustedLocally}

                    <AccessibleButton kind="primary" onClick={this._restoreBackup}>
                        {restoreButtonCaption}
                    </AccessibleButton>
                    <AccessibleButton kind="danger" onClick={this._deleteBackup}>
                        { _t("Delete Backup") }
                    </AccessibleButton>

;
        } else {
            return

{_t(
                        "Your keys are not being backed up from this device.", {},
                        {b: sub => {sub}},
                    )}

{encryptedMessageAreEncrypted}

{_t("Back up your keys before signing out to avoid losing them.")}

                <AccessibleButton kind="primary" onClick={this._startNewBackup}>
                    { _t("Start using Key Backup") }
                </AccessibleButton>

;
        }
    }
}
<|endoftext|>


<commit_before>function runTest()
{
    FBTest.sysout("issue4889.START");

    FBTest.openNewTab(basePath + "script/breakpoints/4889/issue4889.html", function(win)
    {
        FBTest.openFirebug();
        FBTest.enableScriptPanel();
        FBTest.enableConsolePanel();

        FBTest.selectPanel("console");

        var config = {tagName: "div", classes: "logRow logRow-errorMessage", count: 2};
        FBTest.waitForDisplayedElement("console", config, function(row)
        {
            var panelNode = FW.FBL.getAncestorByClass(row, "panelNode");
            var errorMessages = panelNode.getElementsByClassName("logRow-errorMessage");

            for (var i = 0; i < errorMessages.length; ++i)
            {
                var breakpoint = errorMessages[i].getElementsByClassName("errorBreak").item(0);
                var errorMessage = errorMessages[i].getElementsByClassName("errorMessage").item(0);
                if (FBTest.ok(breakpoint, "There must be an breakpoint available for the error " +
                    "log '" + errorMessage.textContent +"'."))
                {
                    FBTest.click(breakpoint);
                }
            }

            FBTest.selectPanel("script");
            panelNode = FBTest.selectPanel("breakpoints").panelNode;
            var breakpointHeader = panelNode.getElementsByClassName("breakpointHeader").item(0);

            if (FBTest.compare("Error Breakpoints",
                breakpointHeader && breakpointHeader.textContent,
                "There must be a breakpoint category 'Error Breakpoints'"))
            {
                var breakpointBlock = panelNode.getElementsByClassName("breakpointBlock").item(0);

                FBTest.click(breakpointHeader);

                FBTest.ok(!FW.FBL.hasClass(breakpointBlock, "opened"),
                    "The breakpoint category should be collapsed.");

                FBTest.click(breakpointHeader);
                FBTest.ok(FW.FBL.hasClass(breakpointBlock, "opened"),
                    "The breakpoint category should be expanded.");
            }

            // Finish test
            FBTest.testDone("issue4889.DONE");
        });

        FBTest.click(win.document.getElementById("callFirstFunction"));
        FBTest.click(win.document.getElementById("callSecondFunction"));
    });
}
<commit_msg>FBTest: fix script/breakpoints/4889<commit_after>function runTest()
{
    FBTest.sysout("issue4889.START");

    FBTest.openNewTab(basePath + "script/breakpoints/4889/issue4889.html", function(win)
    {
        FBTest.openFirebug();
        FBTest.enableScriptPanel();
        FBTest.enableConsolePanel();

        FBTest.selectPanel("console");

        var config = {tagName: "div", classes: "logRow logRow-errorMessage", counter: 2};
        FBTest.waitForDisplayedElement("console", config, function(row)
        {
            var panelNode = FW.FBL.getAncestorByClass(row, "panelNode");
            var errorMessages = panelNode.getElementsByClassName("logRow-errorMessage");

            for (var i=0; i<errorMessages.length; ++i)
            {
                var breakpoint = errorMessages[i].getElementsByClassName("errorBreak").item(0);
                var errorMessage = errorMessages[i].getElementsByClassName("errorMessage").item(0);

                if (FBTest.ok(breakpoint, "There must be an breakpoint available for the error " +
                    "log '" + errorMessage.textContent +"'."))
                {
                    FBTest.click(breakpoint);
                }
            }

            FBTest.selectPanel("script");
            panelNode = FBTest.selectPanel("breakpoints").panelNode;

            var breakpointHeader = panelNode.getElementsByClassName("breakpointHeader").item(0);

            if (FBTest.compare("Error Breakpoints",
                breakpointHeader && breakpointHeader.textContent,
                "There must be a breakpoint category 'Error Breakpoints'"))
            {
                var breakpointBlock = panelNode.getElementsByClassName("breakpointBlock").item(0);

                FBTest.click(breakpointHeader);

                FBTest.ok(!FW.FBL.hasClass(breakpointBlock, "opened"),
                    "The breakpoint category should be collapsed.");

                FBTest.click(breakpointHeader);
                FBTest.ok(FW.FBL.hasClass(breakpointBlock, "opened"),
                    "The breakpoint category should be expanded.");
            }

            // Finish test
            FBTest.testDone("issue4889.DONE");
        });

        FBTest.click(win.document.getElementById("callFirstFunction"));
        FBTest.click(win.document.getElementById("callSecondFunction"));
    });
}
<|endoftext|>


<commit_before>import React from 'react';
import {sortBy, get} from 'lodash';
import {range} from 'ramda';

import SECT_VALUES from './../../constants/sectValues';
import CATEGORY_VALUES from './../../constants/categoryValues';
import EXPLANATION_CATEGORY_VALUES from './../../constants/explanationCategoryValues';
import hasValue from './../../helpers/hasValue';

const fieldsInOrder = ['page-num', 'target-entry', 'explanation', 'category', 'sect'];

const hasData = (prop, data) => (prop in data) && hasValue(data[prop]);

function hasTagetEntry({contentFields, targetLanguages}) {
  return contentFields.some((field) => {
    const lang = (field.match(/^target-entry-lang-(.+)$/) || [])[1];
    return targetLanguages.includes(lang);
  });
}

function hasExplanation({contentFields, targetLanguages}) {
  return contentFields.some((field) => {
    const lang = (field.match(/^explanation-lang-(.+)$/) || [])[1];
    return targetLanguages.includes(lang);
  });
}

function toFieldData({f, data, contentFields, targetLanguages}) {

  const fieldData = {};

  if (hasTagetEntry({contentFields, targetLanguages})) {

    const genTargetEntryKey = (lang) => `target-entry-${lang}`;

    fieldData['target-entry'] = targetLanguages.filter((lang) => hasData(genTargetEntryKey(lang), data))
      .map((lang) => {
        const key = genTargetEntryKey(lang);
        return (
          <tr key={`tr-${key}`}>
            {f('target-entry-lang', {lang: f(lang)})}
            {data[key]}

        );
      });
  }

  if (hasData('page-num', data)) {
    fieldData['page-num'] = (

        {f('page-num')}
        {data['page-num']}

    );
  }

  if (hasExplanation({contentFields, targetLanguages})) {

    const getExplanationKey = (lang) => `explanation-${lang}`;

    const highestIndex = targetLanguages.reduce((index, lang) => {
      const key = getExplanationKey(lang);
      const arr = data[key] || [];
      const length = arr.length;
      return (length > index) ? length : index;
    }, 0);

    const sourceData = data['explanation-source'];
    const noteData = data['explanation-note'];
    const categoryData = data['explanation-category'];

    fieldData.explanation = range(0, highestIndex)
      .map((index) => {

        const rows = targetLanguages.map((lang) => {
          const key = getExplanationKey(lang);
          const arr = data[key] || [];
          const value = arr[index];
          return {lang, value};
        })
        .filter(({value}) => hasValue(value))
        .map(({lang, value}) => {
          return (
            <tr key={`explanation-${lang}`}>
              {f('explanation-num-lang', {num: `${index + 1}`, lang: f(lang)})}
              {value}

          );
        });

        const source = get(sourceData, index);

        if (hasValue(source)) {
          rows.push((

              {f('explanation-source-num', {num: `${index + 1}`})}
              {source}

          ));
        }

        const note = get(noteData, index);

        if (hasValue(note)) {
          rows.push((

              {f('explanation-note-num', {num: `${index + 1}`})}
              {note}

          ));
        }

        const category = get(categoryData, index);

        if (hasValue(category)) {

          const value = category.map((value) => {
            const categoryId = EXPLANATION_CATEGORY_VALUES.find((row) => row.value === value).id;
            return f(categoryId);
          })
          .join(' ');

          rows.push((

              {f('explanation-category-num', {num: `${index + 1}`})}
              {value}

          ));
        }

        return rows;
      });
  }

  if (hasData('category', data)) {
    const value = data.category;
    const categoryId = CATEGORY_VALUES.find((row) => row.value === value).id;

    fieldData.category = (

        {f('category')}
        {f(categoryId)}

    );
  }

  if (hasData('sect', data)) {

    const value = data.sect;
    const sectId = SECT_VALUES.find((row) => row.value === value).id;

    fieldData.sect = (

        {f('sect')}
        {f(sectId)}

    );
  }

  return fieldData;
}

function render(fieldData) {
  const fields = sortBy(Object.keys(fieldData), (field) => fieldsInOrder.indexOf(field));
  return fields.map((field) => fieldData[field]);
}

export default function renderContentFields({f, data, contentFields, targetLanguages}) {
  const fieldData = toFieldData({f, data, contentFields, targetLanguages});
  return render(fieldData);
}
<commit_msg>remove page-num in renderContentFields<commit_after>import React from 'react';
import {sortBy, get} from 'lodash';
import {range} from 'ramda';

import SECT_VALUES from './../../constants/sectValues';
import CATEGORY_VALUES from './../../constants/categoryValues';
import EXPLANATION_CATEGORY_VALUES from './../../constants/explanationCategoryValues';
import hasValue from './../../helpers/hasValue';

const fieldsInOrder = ['target-entry', 'explanation', 'category', 'sect'];

const hasData = (prop, data) => (prop in data) && hasValue(data[prop]);

function hasTagetEntry({contentFields, targetLanguages}) {
  return contentFields.some((field) => {
    const lang = (field.match(/^target-entry-lang-(.+)$/) || [])[1];
    return targetLanguages.includes(lang);
  });
}

function hasExplanation({contentFields, targetLanguages}) {
  return contentFields.some((field) => {
    const lang = (field.match(/^explanation-lang-(.+)$/) || [])[1];
    return targetLanguages.includes(lang);
  });
}

function toFieldData({f, data, contentFields, targetLanguages}) {

  const fieldData = {};

  if (hasTagetEntry({contentFields, targetLanguages})) {

    const genTargetEntryKey = (lang) => `target-entry-${lang}`;

    fieldData['target-entry'] = targetLanguages.filter((lang) => hasData(genTargetEntryKey(lang), data))
      .map((lang) => {
        const key = genTargetEntryKey(lang);
        return (
          <tr key={`tr-${key}`}>
            {f('target-entry-lang', {lang: f(lang)})}
            {data[key]}

        );
      });
  }

  if (hasExplanation({contentFields, targetLanguages})) {

    const getExplanationKey = (lang) => `explanation-${lang}`;

    const highestIndex = targetLanguages.reduce((index, lang) => {
      const key = getExplanationKey(lang);
      const arr = data[key] || [];
      const length = arr.length;
      return (length > index) ? length : index;
    }, 0);

    const sourceData = data['explanation-source'];
    const noteData = data['explanation-note'];
    const categoryData = data['explanation-category'];

    fieldData.explanation = range(0, highestIndex)
      .map((index) => {

        const rows = targetLanguages.map((lang) => {
          const key = getExplanationKey(lang);
          const arr = data[key] || [];
          const value = arr[index];
          return {lang, value};
        })
        .filter(({value}) => hasValue(value))
        .map(({lang, value}) => {
          return (
            <tr key={`explanation-${lang}`}>
              {f('explanation-num-lang', {num: `${index + 1}`, lang: f(lang)})}
              {value}

          );
        });

        const source = get(sourceData, index);

        if (hasValue(source)) {
          rows.push((

              {f('explanation-source-num', {num: `${index + 1}`})}
              {source}

          ));
        }

        const note = get(noteData, index);

        if (hasValue(note)) {
          rows.push((

              {f('explanation-note-num', {num: `${index + 1}`})}
              {note}

          ));
        }

        const category = get(categoryData, index);

        if (hasValue(category)) {

          const value = category.map((value) => {
            const categoryId = EXPLANATION_CATEGORY_VALUES.find((row) => row.value === value).id;
            return f(categoryId);
          })
          .join(' ');

          rows.push((

              {f('explanation-category-num', {num: `${index + 1}`})}
              {value}

          ));
        }

        return rows;
      });
  }

  if (hasData('category', data)) {
    const value = data.category;
    const categoryId = CATEGORY_VALUES.find((row) => row.value === value).id;

    fieldData.category = (

        {f('category')}
        {f(categoryId)}

    );
  }

  if (hasData('sect', data)) {

    const value = data.sect;
    const sectId = SECT_VALUES.find((row) => row.value === value).id;

    fieldData.sect = (

        {f('sect')}
        {f(sectId)}

    );
  }

  return fieldData;
}

function render(fieldData) {
  const fields = sortBy(Object.keys(fieldData), (field) => fieldsInOrder.indexOf(field));
  return fields.map((field) => fieldData[field]);
}

export default function renderContentFields({f, data, contentFields, targetLanguages}) {
  const fieldData = toFieldData({f, data, contentFields, targetLanguages});
  return render(fieldData);
}
<|endoftext|>


<commit_before>/**
	@namespace enyo
*/
(function (enyo, scope) {

	var kind = enyo.kind;

	var ModelList = enyo.ModelList,
		EventEmitter = enyo.EventEmitter,

		// because Object is already taken by something...blarg
		_Object = enyo.Object;

	var BaseStore = enyo.kind({
		kind: _Object,
		mixins: [EventEmitter]
	});

	/**
		An anonymous kind used internally for the singleton {@link enyo.store}.

		@protected
		@class Store
		@extends enyo.Object
	*/
	var Store = kind(
		/** @lends Store.prototype */ {

		/**
			@private
		*/
		kind: BaseStore,

		/**
			@public
			@method
		*/
		find: function () {

			return this;
		},

		/**
			@public
			@method
		*/
		findLocal: function (ctor, fn, opts) {
			var kindName = ctor.prototype.kindName,
				list = this.models[kindName],
				options = {all: true, context: this};

			// allows the method to be called with a constructor only and will return an
			// immutable copy of the array of all models of that type or an empty array
			if (arguments.length == 1 || typeof fn != 'function') {
				return list ? list.slice() : [];
			}

			// ensure we use defaults with any provided options
			opts = opts ? enyo.mixin({}, [options, opts]) : options;

			if (list) return opts.all ? list.filter(fn, opts.context) : list.find(fn, opts.context);
			else return [];
		},

		/**
			@public
			@method
		*/
		add: function (models, opts) {
			var ctor = models && models instanceof Array ? models[0].ctor : models.ctor,
				kindName = ctor && ctor.prototype.kindName,
				list = this.models[kindName],
				added,
				i;

			// if we were able to find the list then we go ahead and attempt to add the models
			if (list) added = list.add(models);
			// if we successfully added models and this was a default operation (not being
			// batched by a collection or other feature) we emit the event needed primarily
			// by relational models but could be useful other places
			if (added.length && (!opts || !opts.silent)) {
				for (i = 0; i < added.length; ++i) {
					this.emit(ctor, 'add', {model: added[i]});
				}
			}

			return this;
		},

		/**
			@public
			@method
		*/
		remove: function (models, opts) {
			var ctor = models && models instanceof Array ? models[0].ctor : models.ctor,
				kindName = ctor && ctor.prototype.kindName,
				list = this.models[kindName],
				removed,
				i;

			// if we were able to find the list then we go ahead and attempt to remove the models
			if (list) removed = list.remove(models);
			// if we successfully removed models and this was a default opreation (not being
			// batched by a collection or other feature) we emit the event needed primarily
			// by relational models but could be useful other places
			if (removed.length && (!opts || !opts.silent)) {
				for (i = 0; i < removed.length; ++i) {
					this.emit(ctor, 'remove', {model: removed[i]});
				}
			}

			return this;
		},

		/**
			@public
			@method
		*/
		has: function (ctor, model) {
			var list = this.models[ctor.prototype.kindName];
			return list? list.has(model): false;
		},

		/**
			@public
			@method
		*/
		resolve: function (ctor, model) {
			var list = this.models[ctor && ctor.prototype.kindName];
			return list? list.resolve(model): undefined;
		},

		/**
			@private
		*/
		constructor: enyo.inherit(function (sup) {
			return function () {
				sup.apply(this, arguments);

				this._scopeListeners = [];

				// all future sub-kinds of enyo.Model that are processed will automatically
				// create/add their entries to this object in their concat method
				this.models = {
					'enyo.Model': new ModelList()
				};
			};
		}),

		/**
			@private
		*/
		scopeListeners: function (scope, e) {
			return !scope ? this._scopeListeners : this._scopeListeners.filter(function (ln) {
				return ln.scope === scope ? !e ? true : ln.event == e : false;
			});
		},

		/**
			@private
		*/
		on: enyo.inherit(function (sup) {
			return function (ctor, e, fn, ctx) {
				if (typeof ctor == 'function') {
					this.scopeListeners().push({
						scope: ctor,
						event: e,
						method: fn,
						ctx: ctx || this
					});

					return this;
				}

				return sup.apply(this, arguments);
			};
		}),

		/**
			@private
		*/
		off: enyo.inherit(function (sup) {
			return function (ctor, e, fn) {
				var listeners,
					idx;

				if (typeof ctor == 'function') {
					listeners = this.scopeListeners(ctor);
					if (listeners.length) {
						idx = listeners.findIndex(function (ln) {
							return ln.event == e && ln.method === fn;
						});

						// if it found the entry we remove it
						if (idx >= 0) listeners.splice(idx, 1);
					}
					return this;
				}
			};
		}),

		/**
			@private
		*/
		emit: enyo.inherit(function (sup) {
			return function (ctor, e) {
				var listeners,
					args;

				if (typeof ctor == 'function') {
					listeners = this.scopeListeners(ctor, e);

					if (listeners.length) {
						args = enyo.toArray(arguments).slice(1);
						args.unshift(this);
						listeners.forEach(function (ln) {
							ln.method.apply(ln.ctx, args);
						});
						return true;
					}
					return false;
				}

				return sup.apply(this, arguments);
			};
		})
	});

	/**
		A runtime database for working with {@link enyo.Model} instances.

		@public
		@type Store
		@memberof enyo
	*/
	enyo.store = new Store();

})(enyo, this);<commit_msg>allow Store to call has without the constructor<commit_after>/**
	@namespace enyo
*/
(function (enyo, scope) {

	var kind = enyo.kind;

	var ModelList = enyo.ModelList,
		EventEmitter = enyo.EventEmitter,

		// because Object is already taken by something...blarg
		_Object = enyo.Object;

	var BaseStore = enyo.kind({
		kind: _Object,
		mixins: [EventEmitter]
	});

	/**
		An anonymous kind used internally for the singleton {@link enyo.store}.

		@protected
		@class Store
		@extends enyo.Object
	*/
	var Store = kind(
		/** @lends Store.prototype */ {

		/**
			@private
		*/
		kind: BaseStore,

		/**
			@public
			@method
		*/
		find: function () {

			return this;
		},

		/**
			@public
			@method
		*/
		findLocal: function (ctor, fn, opts) {
			var kindName = ctor.prototype.kindName,
				list = this.models[kindName],
				options = {all: true, context: this};

			// allows the method to be called with a constructor only and will return an
			// immutable copy of the array of all models of that type or an empty array
			if (arguments.length == 1 || typeof fn != 'function') {
				return list ? list.slice() : [];
			}

			// ensure we use defaults with any provided options
			opts = opts ? enyo.mixin({}, [options, opts]) : options;

			if (list) return opts.all ? list.filter(fn, opts.context) : list.find(fn, opts.context);
			else return [];
		},

		/**
			@public
			@method
		*/
		add: function (models, opts) {
			var ctor = models && models instanceof Array ? models[0].ctor : models.ctor,
				kindName = ctor && ctor.prototype.kindName,
				list = this.models[kindName],
				added,
				i;

			// if we were able to find the list then we go ahead and attempt to add the models
			if (list) added = list.add(models);
			// if we successfully added models and this was a default operation (not being
			// batched by a collection or other feature) we emit the event needed primarily
			// by relational models but could be useful other places
			if (added.length && (!opts || !opts.silent)) {
				for (i = 0; i < added.length; ++i) {
					this.emit(ctor, 'add', {model: added[i]});
				}
			}

			return this;
		},

		/**
			@public
			@method
		*/
		remove: function (models, opts) {
			var ctor = models && models instanceof Array ? models[0].ctor : models.ctor,
				kindName = ctor && ctor.prototype.kindName,
				list = this.models[kindName],
				removed,
				i;

			// if we were able to find the list then we go ahead and attempt to remove the models
			if (list) removed = list.remove(models);
			// if we successfully removed models and this was a default opreation (not being
			// batched by a collection or other feature) we emit the event needed primarily
			// by relational models but could be useful other places
			if (removed.length && (!opts || !opts.silent)) {
				for (i = 0; i < removed.length; ++i) {
					this.emit(ctor, 'remove', {model: removed[i]});
				}
			}

			return this;
		},

		/**
			@public
			@method
		*/
		has: function (ctor, model) {
			var list;

			if (!model) {
				model = ctor;
				ctor = model.ctor;
			}

			list = this.models[ctor.prototype.kindName];
			return list ? list.has(model) : false;
		},

		/**
			@public
			@method
		*/
		resolve: function (ctor, model) {
			var list = this.models[ctor && ctor.prototype.kindName];
			return list? list.resolve(model): undefined;
		},

		/**
			@private
		*/
		constructor: enyo.inherit(function (sup) {
			return function () {
				sup.apply(this, arguments);

				this._scopeListeners = [];

				// all future sub-kinds of enyo.Model that are processed will automatically
				// create/add their entries to this object in their concat method
				this.models = {
					'enyo.Model': new ModelList()
				};
			};
		}),

		/**
			@private
		*/
		scopeListeners: function (scope, e) {
			return !scope ? this._scopeListeners : this._scopeListeners.filter(function (ln) {
				return ln.scope === scope ? !e ? true : ln.event == e : false;
			});
		},

		/**
			@private
		*/
		on: enyo.inherit(function (sup) {
			return function (ctor, e, fn, ctx) {
				if (typeof ctor == 'function') {
					this.scopeListeners().push({
						scope: ctor,
						event: e,
						method: fn,
						ctx: ctx || this
					});

					return this;
				}

				return sup.apply(this, arguments);
			};
		}),

		/**
			@private
		*/
		off: enyo.inherit(function (sup) {
			return function (ctor, e, fn) {
				var listeners,
					idx;

				if (typeof ctor == 'function') {
					listeners = this.scopeListeners(ctor);
					if (listeners.length) {
						idx = listeners.findIndex(function (ln) {
							return ln.event == e && ln.method === fn;
						});

						// if it found the entry we remove it
						if (idx >= 0) listeners.splice(idx, 1);
					}
					return this;
				}
			};
		}),

		/**
			@private
		*/
		emit: enyo.inherit(function (sup) {
			return function (ctor, e) {
				var listeners,
					args;

				if (typeof ctor == 'function') {
					listeners = this.scopeListeners(ctor, e);

					if (listeners.length) {
						args = enyo.toArray(arguments).slice(1);
						args.unshift(this);
						listeners.forEach(function (ln) {
							ln.method.apply(ln.ctx, args);
						});
						return true;
					}
					return false;
				}

				return sup.apply(this, arguments);
			};
		})
	});

	/**
		A runtime database for working with {@link enyo.Model} instances.

		@public
		@type Store
		@memberof enyo
	*/
	enyo.store = new Store();

})(enyo, this);<|endoftext|>


<commit_before>/* global _, Vue, superagent */

Vue.component('collections-overlay', {
  data: {
    isVisible: false,
    isLoading: false,
    isCollectionsLoaded: false,
    isHidingDeferred: false,
    activeWallpaper: null,

    collections: []
  },

  ready: function () {
    var self = this;

    self.$on('wallpaperDragStart', function (wallpaper) {
      self.setActiveWallpaper(wallpaper);
      self.show();
    });
    self.$on('wallpaperDragEnd', self.hide);

    self.$watch('activeWallpaper', this.refreshActiveWallpaperCollectStatus);
    // this.$emit('collectionOverlayShow');
  },

  methods: {
    setActiveWallpaper: function (wallpaper) {
      this.activeWallpaper = wallpaper;
      this.$broadcast('setActiveWallpaper', wallpaper);
    },

    show: function () {
      this.isVisible = true;

      if ( ! this.isCollectionsLoaded) {
        this.fetchCollections();
      }
    },

    hide: function () {
      var self = this;
      if (self.isHidingDeferred) {
        self.$watch('isHidingDeferred', function (value) {
          if (value) {
            return;
          }
          self.$unwatch('isHidingDeferred');
          self.hideNow();
        });
      } else {
        self.hideNow();
      }
    },

    hideNow: function () {
      this.isVisible = false;
      this.setActiveWallpaper(null);
    },

    fetchCollections: function () {
      var self = this;
      self.isLoading = true;
      self.isCollectionsLoaded = false;

      superagent
        .get('/api/v1/users/me/collections.json')
        .end(function (res) {
          if (res.ok) {
            self.collections = res.body.collections;
          }
          self.isLoading = false;
          self.isCollectionsLoaded = true;

          Vue.nextTick(function () {
            self.$broadcast('setActiveWallpaper', self.activeWallpaper);
          });
        });
    },

    refreshActiveWallpaperCollectStatus: function () {
      var self = this;

      if ( ! self.activeWallpaper) {
        return;
      }

      var wallpaper = self.activeWallpaper;

      var actuallyFetch = function () {
        superagent
          .get('/api/v1/users/me/collections.json')
          .query({ wallpaper_id: wallpaper.id })
          .end(function (res) {
            if (res.ok) {
              self.$broadcast('wallpaperInCollections', {
                wallpaperId: wallpaper.id,
                collectionIds: _.pluck(res.body.collections, 'id')
              });
            }
          });
      };

      if (self.isCollectionsLoaded) {
        actuallyFetch();
      } else {
        self.$watch('isCollectionsLoaded', function (value) {
          if ( ! value) {
            return;
          }
          self.$unwatch('isCollectionsLoaded');
          actuallyFetch();
        });
      }
    },

    addWallpaperToCollection: function (wallpaper, collection) {
      var self = this;

      if ( ! wallpaper || ! collection) {
        return;
      }

      self.isHidingDeferred = true; // Defer hiding

      superagent
        .post('/api/v1/collections/' + collection.id + '/wallpapers.json')
        .send({ wallpaper_id: wallpaper.id })
        .end(function (res) {
          if (res.ok) {
            _.assign(collection, res.body.collection); // Refresh collection
            self.didAddWallpaperToCollection(wallpaper, collection);
          }
        });
    },

    didAddWallpaperToCollection: function (wallpaper, collection) {
      var self = this;

      // Handle deferred hiding
      if (self.isHidingDeferred) {
        setTimeout(function () {
          self.isHidingDeferred = false;
        }, 1000);
      }

      self.$root.$broadcast('didAddWallpaperToCollection', {
        wallpaper: wallpaper,
        collection: collection
      });
    },

    onDragOver: function (e) {
      if ( ! e.targetVM.isInCollection) {
        e.preventDefault(); // prevent default to allow dropping
        e.targetVM.isDraggedOver = true;
      }
    },

    onDrop: function (e) {
      var wallpaperId = parseInt(e.dataTransfer.getData('text/x-wallpaper-id'));

      if (this.activeWallpaper.id === wallpaperId &&
           ! e.targetVM.isInCollection) {
        this.addWallpaperToCollection(this.activeWallpaper, e.targetVM);
      }

      e.targetVM.isDraggedOver = false;
    },

    onDropNewCollection: function (e) {
      e.preventDefault();

      var name = window.prompt('New collection name?', 'Untitled');
      if ( ! name) {
        return;
      }

      var wallpaper = this.activeWallpaper;
      this.isHidingDeferred = true;

      superagent
        .post('/api/v1/users/me/collections.json')
        .send({ name: name, public: true })
        .end(_.bind(function (res) {
          if (res.ok) {
            this.collections.unshift(res.body.collection);
            this.addWallpaperToCollection(wallpaper, res.body.collection);
          } else {
            this.isHidingDeferred = false;
            this.$dispatch('apiError', res);
          }
        }, this));
    }
  }
});
<commit_msg>Update collections when loading<commit_after>/* global _, Vue, superagent */

Vue.component('collections-overlay', {
  data: {
    isVisible: false,
    isLoading: false,
    isCollectionsLoaded: false,
    isHidingDeferred: false,
    activeWallpaper: null,

    collections: []
  },

  ready: function () {
    var self = this;

    self.$on('wallpaperDragStart', function (wallpaper) {
      self.setActiveWallpaper(wallpaper);
      self.show();
    });
    self.$on('wallpaperDragEnd', self.hide);

    self.$watch('activeWallpaper', this.refreshActiveWallpaperCollectStatus);
    // this.$emit('collectionOverlayShow');
  },

  methods: {
    setActiveWallpaper: function (wallpaper) {
      this.activeWallpaper = wallpaper;
      this.$broadcast('setActiveWallpaper', wallpaper);
    },

    show: function () {
      this.isVisible = true;

      if ( ! this.isCollectionsLoaded) {
        this.fetchCollections();
      }
    },

    hide: function () {
      var self = this;
      if (self.isHidingDeferred) {
        self.$watch('isHidingDeferred', function (value) {
          if (value) {
            return;
          }
          self.$unwatch('isHidingDeferred');
          self.hideNow();
        });
      } else {
        self.hideNow();
      }
    },

    hideNow: function () {
      this.isVisible = false;
      this.setActiveWallpaper(null);
    },

    fetchCollections: function () {
      var self = this;
      self.isLoading = true;
      self.isCollectionsLoaded = false;

      superagent
        .get('/api/v1/users/me/collections.json')
        .end(function (res) {
          if (res.ok) {
            self.collections = res.body.collections;
          }
          self.isLoading = false;
          self.isCollectionsLoaded = true;

          Vue.nextTick(function () {
            self.$broadcast('setActiveWallpaper', self.activeWallpaper);
          });
        });
    },

    refreshActiveWallpaperCollectStatus: function () {
      var self = this;

      if ( ! self.activeWallpaper) {
        return;
      }

      var wallpaper = self.activeWallpaper;

      var actuallyFetch = function () {
        superagent
          .get('/api/v1/users/me/collections.json')
          .query({ wallpaper_id: wallpaper.id })
          .end(function (res) {
            if (res.ok) {
              _(res.body.collections).forEach(function (latestCollection) {
                _.chain(self.collections).
                  find({ id: latestCollection.id }).
                  assign(latestCollection);
              });
              self.$broadcast('wallpaperInCollections', {
                wallpaperId: wallpaper.id,
                collectionIds: _.pluck(res.body.collections, 'id')
              });
            }
          });
      };

      if (self.isCollectionsLoaded) {
        actuallyFetch();
      } else {
        self.$watch('isCollectionsLoaded', function (value) {
          if ( ! value) {
            return;
          }
          self.$unwatch('isCollectionsLoaded');
          actuallyFetch();
        });
      }
    },

    addWallpaperToCollection: function (wallpaper, collection) {
      var self = this;

      if ( ! wallpaper || ! collection) {
        return;
      }

      self.isHidingDeferred = true; // Defer hiding

      superagent
        .post('/api/v1/collections/' + collection.id + '/wallpapers.json')
        .send({ wallpaper_id: wallpaper.id })
        .end(function (res) {
          if (res.ok) {
            _.assign(collection, res.body.collection); // Refresh collection
            self.didAddWallpaperToCollection(wallpaper, collection);
          }
        });
    },

    didAddWallpaperToCollection: function (wallpaper, collection) {
      var self = this;

      // Handle deferred hiding
      if (self.isHidingDeferred) {
        setTimeout(function () {
          self.isHidingDeferred = false;
        }, 1000);
      }

      self.$root.$broadcast('didAddWallpaperToCollection', {
        wallpaper: wallpaper,
        collection: collection
      });
    },

    onDragOver: function (e) {
      if ( ! e.targetVM.isInCollection) {
        e.preventDefault(); // prevent default to allow dropping
        e.targetVM.isDraggedOver = true;
      }
    },

    onDrop: function (e) {
      var wallpaperId = parseInt(e.dataTransfer.getData('text/x-wallpaper-id'));

      if (this.activeWallpaper.id === wallpaperId &&
           ! e.targetVM.isInCollection) {
        this.addWallpaperToCollection(this.activeWallpaper, e.targetVM);
      }

      e.targetVM.isDraggedOver = false;
    },

    onDropNewCollection: function (e) {
      e.preventDefault();

      var name = window.prompt('New collection name?', 'Untitled');
      if ( ! name) {
        return;
      }

      var wallpaper = this.activeWallpaper;
      this.isHidingDeferred = true;

      superagent
        .post('/api/v1/users/me/collections.json')
        .send({ name: name, public: true })
        .end(_.bind(function (res) {
          if (res.ok) {
            this.collections.unshift(res.body.collection);
            this.addWallpaperToCollection(wallpaper, res.body.collection);
          } else {
            this.isHidingDeferred = false;
            this.$dispatch('apiError', res);
          }
        }, this));
    }
  }
});
<|endoftext|>


<commit_before>//* @public
/**
	Creates a JavaScript constructor function with a prototype defined by _inProps_.

	_enyo.kind_ makes it easy to build a constructor-with-prototype (like a class) that has advanced
	features like prototype-chaining (inheritance).

	A plug-in system is included for extending the abilities of the kind generator, and constructors
	are allowed to perform custom operations when subclassed.

	Special Property Names
	----------------------

	Generally the properties defined in inProps are copied directly to the generated prototype, but certain
	property names trigger special processing.

	Examples of special properties are:

	* _name_: the _name_ property defines the name of the created constructor in the global namespace
	(intermediate objects are created automatically). _name_ is not copied directly to the prototype,
	but is instead stored as _kindName_.

			// Creates a function MyNamespace.MyKind with a prototype.
			// MyNamespace.MyKind.prototype.kindName is set to "MyNamespace.MyKind".
			// MyNamespace.MyKind.prototype.plainProperty is set to "foo".
			enyo.kind({
				name: "MyNamespace.MyKind"
				plainProperty: "foo"
			});
			// Make an instance of the new kind
			var myk = new MyNamespace.MyKind();

	* _kind_: the name of or reference to a kind to derive from, like a super-class. The new constructor's prototype is
	chained to the prototype specified by _kind_, and the _base_ property in the new prototype is set to reference the
	_kind_ constructor.

			// Create a function MyKind with a prototype, derived from enyo.Object.
			// MyKind.prototype.kindName is set to "MyKind".
			// MyKind.prototype.base is set to enyo.Object.
			enyo.kind({
				name: "MyKind",
				kind: enyo.Object
			});

	* _constructor_: a function to call when a new instance is created. Actually stored on the prototype as __constructor_.

			// Create a function MyKind with a prototype, derived from enyo.Object.
			// _constructor_ is called when an instance is created.
			enyo.kind({
				name: "MyKind",
				kind: enyo.Object,
				constructor: function() {
					this.instanceArray = [];
					// call the constructor inherited from Object
					this.inherited(arguments);
				}
			});

	* _statics_: properties from any _statics_ object are copied onto the constructor directly, instead of the prototype.

			// Create a kind with a static method.
			enyo.kind({
				name: "MyKind",
				statics: {
					info: function() {
						return "MyKind is a kind with statics.";
					}
				}
			});
			// invoke the static info() method of MyKind
			console.log(MyKind.info());

	Certain kinds in the framework define their own special properties.
	For example, see the _published_ property supported by enyo.Object.

	inherited
	---------

	The _inherited_ feature allows you to easily call the super-kind method for any method that has been overridden.

		enyo.kind({
			name: "MyKind",
			doWork: function() {
				this.work++;
			}
		});

		enyo.kind({
			name: "MyDerivedKind",
			kind: "MyKind",
			doWork: function() {
				if (this.shouldDoWork) {
					this.inherited(arguments);
				}
			}
		});

	The first argument to _inherited_ is required to be the literal _arguments_, which is a special JavaScript variable that contains
	information about the executing function.
*/
enyo.kind = function(inProps) {
	// if we have an explicit kind property with value undefined, we probably tried
	// to reference a kind that is not yet in scope
	if ((inProps.kind === undefined) && ("kind" in inProps)) {
		throw "enyo.kind: Attempt to subclass an 'undefined' kind. Check dependencies for [" + name + "].";
	}
	// kind-name to constructor map could be faulty now that a new kind exists, so we simply destroy the memoizations
	enyo._kindCtors = {};
	// extract 'name' property
	var name = inProps.name || "";
	delete inProps.name;
	// extract 'kind' property
	var kind = inProps.kind;
	delete inProps.kind;
	// establish base class reference
	var base = enyo.constructorForKind(kind);
	var isa = base && base.prototype || null;
	// make a boilerplate constructor
	var ctor = enyo.kind.makeCtor();
	// semi-reserved word 'constructor' causes problems with Prototype and IE, so we rename it here
	if (inProps.hasOwnProperty("constructor")) {
		inProps._constructor = inProps.constructor;
		delete inProps.constructor;
	}
	// create our prototype
	//ctor.prototype = isa ? enyo.delegate(isa) : {};
	enyo.setPrototype(ctor, isa ? enyo.delegate(isa) : {});
	// put in our props
	enyo.mixin(ctor.prototype, inProps);
	// alias class name as 'kind' in the prototype
	ctor.prototype.kindName = name;
	// cache super-class constructor
	ctor.prototype.base = base;
	// reference our real constructor
	ctor.prototype.ctor = ctor;
	// support pluggable 'features'
	enyo.forEach(enyo.kind.features, function(fn){ fn(ctor, inProps); });
	// put reference into namespace
	enyo.setObject(name, ctor);
	return ctor;
};

//* @protected
enyo.kind.makeCtor = function() {
	return function() {
		// two-pass instantiation
		if (this._constructor) {
			// pure construction
			this._constructor.apply(this, arguments);
		}
		// defer initialization until entire constructor chain has finished
		if (this.constructed) {
			// post-constructor initialization
			this.constructed.apply(this, arguments);
		}
	};
};

// classes referenced by name can omit this namespace (e.g. "Button" instead of "enyo.Button")
enyo.kind.defaultNamespace = "enyo";

//
// feature hooks for the oop system
//
enyo.kind.features = [];

//
// 'inherited' feature
//
enyo.kind.features.push(function(ctor, props) {
	var proto = ctor.prototype;
	if (!proto.inherited) {
		proto.inherited = enyo.kind.inherited;
	}
	if (proto.base) {
		// decorate function properties to support inherited (do this ex post facto so that ctor.prototype is known, relies on elements in props being copied by reference)
		for (var n in props) {
			var p = props[n];
			if (enyo.isFunction(p)) {
				p._inherited = proto.base.prototype[n];
				// FIXME: we used to need some extra values for inherited, then inherited got cleaner
				// but in the meantime we used these values to support logging in Object.
				// For now we support this legacy situation, by suppling logging information here.
				p.nom = proto.kindName + '.' + n + '()';
			}
		}
	}
});

enyo.kind.inherited = function(args, newArgs) {
	return args.callee._inherited.apply(this, newArgs || args);
};

//
// 'statics' feature
//
enyo.kind.features.push(function(ctor, props) {
	// install common statics
	enyo.mixin(ctor, enyo.kind.statics);
	// move props statics to constructor
	if (props.statics) {
		enyo.mixin(ctor, props.statics);
		delete ctor.prototype.statics;
	}
	// allow superclass customization
	var base = ctor.prototype.base;
	while (base) {
		base.subclass(ctor, props);
		base = base.prototype.base;
	}
});

enyo.kind.statics = {
	subclass: function(ctor, props) {
		//console.log("subclassing [" + ctor.prototype.kind + "] from [", this.prototype.kind + "]");
	},
	extend: function(props) {
		enyo.mixin(this.prototype, props);
	}
};

//
// factory for kinds identified by strings
//
enyo._kindCtors = {};

enyo.constructorForKind = function(inKind) {
	if (inKind === null || enyo.isFunction(inKind)) {
		// in inKind is a function or explicitly null, then that's ctor, full stop.
		return inKind;
	}
	if (inKind) {
		// use memoized constructor if available...
		var ctor = enyo._kindCtors[inKind];
		if (ctor) {
			return ctor;
		}
		// otherwise look it up and memoize what we find
		//
		// if inKind is an object in enyo, say "Control", then ctor = enyo["Control"]
		// if inKind is a path under enyo, say "Heritage.Button", then ctor = enyo["Heritage.Button"] || enyo.Heritage.Button
		// if inKind is a fully qualified path, say "enyo.Heritage.Button", then ctor = enyo["enyo.Heritage.Button"] || enyo.enyo.Heritage.Button || enyo.Heritage.Button
		//
		// Note that kind "Foo" will resolve to enyo.Foo before resolving to global "Foo".
		// This is important so "Image" will map to built-in Image object, instead of enyo.Image control.
		return enyo._kindCtors[inKind] = enyo.Theme[inKind] || enyo[inKind] || enyo.getObject(inKind, false, enyo) || window[inKind] || enyo.getObject(inKind);
	}
	return enyo.defaultCtor;
};

//
// namespace for current theme ("enyo.Theme.Button" references the Button specialization for the current theme)
//
enyo.Theme = {};

enyo.registerTheme = function(inNamespace) {
	enyo.mixin(enyo.Theme, inNamespace);
};<commit_msg>improved error checking for base kinds in enyo.kind<commit_after>//* @public
/**
	Creates a JavaScript constructor function with a prototype defined by _inProps_.

	_enyo.kind_ makes it easy to build a constructor-with-prototype (like a class) that has advanced
	features like prototype-chaining (inheritance).

	A plug-in system is included for extending the abilities of the kind generator, and constructors
	are allowed to perform custom operations when subclassed.

	Special Property Names
	----------------------

	Generally the properties defined in inProps are copied directly to the generated prototype, but certain
	property names trigger special processing.

	Examples of special properties are:

	* _name_: the _name_ property defines the name of the created constructor in the global namespace
	(intermediate objects are created automatically). _name_ is not copied directly to the prototype,
	but is instead stored as _kindName_.

			// Creates a function MyNamespace.MyKind with a prototype.
			// MyNamespace.MyKind.prototype.kindName is set to "MyNamespace.MyKind".
			// MyNamespace.MyKind.prototype.plainProperty is set to "foo".
			enyo.kind({
				name: "MyNamespace.MyKind"
				plainProperty: "foo"
			});
			// Make an instance of the new kind
			var myk = new MyNamespace.MyKind();

	* _kind_: the name of or reference to a kind to derive from, like a super-class. The new constructor's prototype is
	chained to the prototype specified by _kind_, and the _base_ property in the new prototype is set to reference the
	_kind_ constructor.

			// Create a function MyKind with a prototype, derived from enyo.Object.
			// MyKind.prototype.kindName is set to "MyKind".
			// MyKind.prototype.base is set to enyo.Object.
			enyo.kind({
				name: "MyKind",
				kind: enyo.Object
			});

	* _constructor_: a function to call when a new instance is created. Actually stored on the prototype as __constructor_.

			// Create a function MyKind with a prototype, derived from enyo.Object.
			// _constructor_ is called when an instance is created.
			enyo.kind({
				name: "MyKind",
				kind: enyo.Object,
				constructor: function() {
					this.instanceArray = [];
					// call the constructor inherited from Object
					this.inherited(arguments);
				}
			});

	* _statics_: properties from any _statics_ object are copied onto the constructor directly, instead of the prototype.

			// Create a kind with a static method.
			enyo.kind({
				name: "MyKind",
				statics: {
					info: function() {
						return "MyKind is a kind with statics.";
					}
				}
			});
			// invoke the static info() method of MyKind
			console.log(MyKind.info());

	Certain kinds in the framework define their own special properties.
	For example, see the _published_ property supported by enyo.Object.

	inherited
	---------

	The _inherited_ feature allows you to easily call the super-kind method for any method that has been overridden.

		enyo.kind({
			name: "MyKind",
			doWork: function() {
				this.work++;
			}
		});

		enyo.kind({
			name: "MyDerivedKind",
			kind: "MyKind",
			doWork: function() {
				if (this.shouldDoWork) {
					this.inherited(arguments);
				}
			}
		});

	The first argument to _inherited_ is required to be the literal _arguments_, which is a special JavaScript variable that contains
	information about the executing function.
*/
enyo.kind = function(inProps) {
	// kind-name to constructor map could be faulty now that a new kind exists, so we simply destroy the memoizations
	enyo._kindCtors = {};
	// extract 'name' property
	var name = inProps.name || "";
	delete inProps.name;
	// extract 'kind' property
	var hasKind = ("kind" in inProps);
	var kind = inProps.kind;
	delete inProps.kind;
	// establish base class reference
	var base = enyo.constructorForKind(kind);
	var isa = base && base.prototype || null;
	// if we have an explicit kind property with value undefined, we probably tried to reference a kind that is not yet in scope
	if (hasKind && (kind !== null) && (base == null)) {
		throw "enyo.kind: Attempt to subclass an undefined kind. Check dependencies for [" + name + "].";
	}
	// make a boilerplate constructor
	var ctor = enyo.kind.makeCtor();
	// semi-reserved word 'constructor' causes problems with Prototype and IE, so we rename it here
	if (inProps.hasOwnProperty("constructor")) {
		inProps._constructor = inProps.constructor;
		delete inProps.constructor;
	}
	// create our prototype
	//ctor.prototype = isa ? enyo.delegate(isa) : {};
	enyo.setPrototype(ctor, isa ? enyo.delegate(isa) : {});
	// put in our props
	enyo.mixin(ctor.prototype, inProps);
	// alias class name as 'kind' in the prototype
	ctor.prototype.kindName = name;
	// cache super-class constructor
	ctor.prototype.base = base;
	// reference our real constructor
	ctor.prototype.ctor = ctor;
	// support pluggable 'features'
	enyo.forEach(enyo.kind.features, function(fn){ fn(ctor, inProps); });
	// put reference into namespace
	enyo.setObject(name, ctor);
	return ctor;
};

//* @protected
enyo.kind.makeCtor = function() {
	return function() {
		// two-pass instantiation
		if (this._constructor) {
			// pure construction
			this._constructor.apply(this, arguments);
		}
		// defer initialization until entire constructor chain has finished
		if (this.constructed) {
			// post-constructor initialization
			this.constructed.apply(this, arguments);
		}
	};
};

// classes referenced by name can omit this namespace (e.g. "Button" instead of "enyo.Button")
enyo.kind.defaultNamespace = "enyo";

//
// feature hooks for the oop system
//
enyo.kind.features = [];

//
// 'inherited' feature
//
enyo.kind.features.push(function(ctor, props) {
	var proto = ctor.prototype;
	if (!proto.inherited) {
		proto.inherited = enyo.kind.inherited;
	}
	if (proto.base) {
		// decorate function properties to support inherited (do this ex post facto so that ctor.prototype is known, relies on elements in props being copied by reference)
		for (var n in props) {
			var p = props[n];
			if (enyo.isFunction(p)) {
				p._inherited = proto.base.prototype[n];
				// FIXME: we used to need some extra values for inherited, then inherited got cleaner
				// but in the meantime we used these values to support logging in Object.
				// For now we support this legacy situation, by suppling logging information here.
				p.nom = proto.kindName + '.' + n + '()';
			}
		}
	}
});

enyo.kind.inherited = function(args, newArgs) {
	return args.callee._inherited.apply(this, newArgs || args);
};

//
// 'statics' feature
//
enyo.kind.features.push(function(ctor, props) {
	// install common statics
	enyo.mixin(ctor, enyo.kind.statics);
	// move props statics to constructor
	if (props.statics) {
		enyo.mixin(ctor, props.statics);
		delete ctor.prototype.statics;
	}
	// allow superclass customization
	var base = ctor.prototype.base;
	while (base) {
		base.subclass(ctor, props);
		base = base.prototype.base;
	}
});

enyo.kind.statics = {
	subclass: function(ctor, props) {
		//console.log("subclassing [" + ctor.prototype.kind + "] from [", this.prototype.kind + "]");
	},
	extend: function(props) {
		enyo.mixin(this.prototype, props);
	}
};

//
// factory for kinds identified by strings
//
enyo._kindCtors = {};

enyo.constructorForKind = function(inKind) {
	if (inKind === null || enyo.isFunction(inKind)) {
		// in inKind is a function or explicitly null, then that's ctor, full stop.
		return inKind;
	}
	if (inKind) {
		// use memoized constructor if available...
		var ctor = enyo._kindCtors[inKind];
		if (ctor) {
			return ctor;
		}
		// otherwise look it up and memoize what we find
		//
		// if inKind is an object in enyo, say "Control", then ctor = enyo["Control"]
		// if inKind is a path under enyo, say "Heritage.Button", then ctor = enyo["Heritage.Button"] || enyo.Heritage.Button
		// if inKind is a fully qualified path, say "enyo.Heritage.Button", then ctor = enyo["enyo.Heritage.Button"] || enyo.enyo.Heritage.Button || enyo.Heritage.Button
		//
		// Note that kind "Foo" will resolve to enyo.Foo before resolving to global "Foo".
		// This is important so "Image" will map to built-in Image object, instead of enyo.Image control.
		return enyo._kindCtors[inKind] = enyo.Theme[inKind] || enyo[inKind] || enyo.getObject(inKind, false, enyo) || window[inKind] || enyo.getObject(inKind);
	}
	return enyo.defaultCtor;
};

//
// namespace for current theme ("enyo.Theme.Button" references the Button specialization for the current theme)
//
enyo.Theme = {};

enyo.registerTheme = function(inNamespace) {
	enyo.mixin(enyo.Theme, inNamespace);
};<|endoftext|>


<commit_before>/**
 * Copyright 2017 Google Inc., PhantomJS Authors All rights reserved.
 *
 * 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.
 */

const puppeteer = require('puppeteer');

(async() => {

const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setRequestInterceptionEnabled(true);
page.on('request', request => {
  if (/\.(png|jpg|jpeg|gif|webp)$/.test(request.url))
    request.abort();
  else
    request.continue();
});
await page.goto('https://bbc.com');
await page.screenshot({path: 'news.png', fullPage: true});

browser.close();

})();

<commit_msg>example 'block images' - make extension check case insensitive (#401)<commit_after>/**
 * Copyright 2017 Google Inc., PhantomJS Authors All rights reserved.
 *
 * 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.
 */

const puppeteer = require('puppeteer');

(async() => {

const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setRequestInterceptionEnabled(true);
page.on('request', request => {
  if (/\.(png|jpg|jpeg|gif|webp)$/i.test(request.url))
    request.abort();
  else
    request.continue();
});
await page.goto('https://bbc.com');
await page.screenshot({path: 'news.png', fullPage: true});

browser.close();

})();

<|endoftext|>


<commit_before>const { info, warning } = require('../src/logger');

const { connect, close } = require('../src/utils/database');
const { yearModel: Year } = require('../src/services/school/model');
const yearLogic = require('../src/services/school/logic/year');

const YEARS_TO_ADD = ['2021/22', '2022/23', '2023/24', '2024/25', '2025/26'];

const createYear = (year) => new Year({
	name: year,
	startDate: yearLogic.getDefaultStartDate(year),
	endDate: yearLogic.getDefaultEndDate(year),
});

module.exports = {
	up: async function up() {
		await connect();
		const chain = [];
		const existingYears = await Year.find().where('name').in(YEARS_TO_ADD).exec();
		if (existingYears.length > 0) {
			warning(`some year already has been created: ${existingYears}`);
		} else {
			for (const year of YEARS_TO_ADD) {
				info(`processing ${year}`);
				const createdYear = createYear(year);
				await createdYear.save();
				chain.push(createdYear);
				info(`the year ${year} was created successfully`);
			}
		}

		await Promise.all(chain);
		info('Done.');
		await close();
	},

	down: async function down() {
		await connect();
		await Year.deleteMany({
			name: {
				$in: YEARS_TO_ADD,
			},
		});
		await close();
	},

};
<commit_msg>SC-4352 migration add test year model<commit_after>const mongoose = require('mongoose');
const { info, warning } = require('../src/logger');

const { connect, close } = require('../src/utils/database');
const yearLogic = require('../src/services/school/logic/year');

const YEARS_TO_ADD = ['2021/22', '2022/23', '2023/24', '2024/25', '2025/26'];

const yearSchema = new mongoose.Schema({
	name: { type: String, required: true },
	startDate: { type: Date, required: true },
	endDate: { type: Date, required: true },
});

const YearModel = mongoose.model('year3244382362348795', yearSchema, 'years');

const createYear = (year) => new YearModel({
	name: year,
	startDate: yearLogic.getDefaultStartDate(year),
	endDate: yearLogic.getDefaultEndDate(year),
});

module.exports = {
	up: async function up() {
		await connect();
		const chain = [];
		const existingYears = await YearModel.find().where('name').in(YEARS_TO_ADD).exec();
		if (existingYears.length > 0) {
			warning(`some year already has been created: ${existingYears}`);
		} else {
			for (const year of YEARS_TO_ADD) {
				info(`processing ${year}`);
				const createdYear = createYear(year);
				await createdYear.save();
				chain.push(createdYear);
				info(`the year ${year} was created successfully`);
			}
		}

		await Promise.all(chain);
		info('Done.');
		await close();
	},

	down: async function down() {
		await connect();
		await YearModel.deleteMany({
			name: {
				$in: YEARS_TO_ADD,
			},
		});
		await close();
	},

};
<|endoftext|>