<commit_before>/**
 * @fileOverview Requirejs module containing device modifier to launch native external media players
 *
 * @preserve Copyright (c) 2014 British Broadcasting Corporation
 * (http://www.bbc.co.uk) and TAL Contributors (1)
 *
 * (1) TAL Contributors are listed in the AUTHORS file and at
 *     https://github.com/fmtvp/TAL/AUTHORS - please extend this file,
 *     not this notice.
 *
 * @license 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.
 *
 * All rights reserved
 * Please contact us for an alternative licence
 */

require.def(
    "antie/devices/mediaplayer/samsung_maple",
    [
        "antie/devices/device",
        "antie/devices/mediaplayer/mediaplayer",
        "antie/runtimecontext"
    ],
    function(Device, MediaPlayer, RuntimeContext) {
        "use strict";

        var Player = MediaPlayer.extend({

            init: function() {
                this._super();
                this._state = MediaPlayer.STATE.EMPTY;
                this._playerPlugin = document.getElementById('playerPlugin');
            },

            /**
            * @inheritDoc
            */
            setSource: function (mediaType, url, mimeType) {
                if (this.getState() === MediaPlayer.STATE.EMPTY) {
                    this._type = mediaType;
                    this._source = url;
                    this._mimeType = mimeType;
                    this._registerEventHandlers();
                    this._toStopped();
                    this._currentTimeKnown = false;
                } else {
                    this._toError("Cannot set source unless in the '" + MediaPlayer.STATE.EMPTY + "' state");
                }
            },

            /**
            * @inheritDoc
            */
            resume : function () {
                this._postBufferingState = MediaPlayer.STATE.PLAYING;
                switch (this.getState()) {
                    case MediaPlayer.STATE.PLAYING:
                        break;

                    case MediaPlayer.STATE.BUFFERING:
                        if (this._tryingToPause) {
                            this._tryingToPause = false;
                            this._toPlaying();
                        }
                        break;

                    case MediaPlayer.STATE.PAUSED:
                        this._playerPlugin.Resume();
                        this._toPlaying();
                        break;

                    default:
                        this._toError("Cannot resume while in the '" + this.getState() + "' state");
                        break;
                }
            },

            /**
            * @inheritDoc
            */
            playFrom: function (seconds) {
                this._postBufferingState = MediaPlayer.STATE.PLAYING;
                var seekingTo = this._range ? this._getClampedTime(seconds) : seconds;
                var offset = seekingTo - this.getCurrentTime();
                switch (this.getState()) {
                    case MediaPlayer.STATE.BUFFERING:
                        if (!this._currentTimeKnown) {
                            this._deferSeekingTo = seekingTo;
                        } else {
                            this._jump(offset);
                        }
                        break;

                    case MediaPlayer.STATE.PLAYING:
                        this._toBuffering();
                        if (!this._currentTimeKnown) {
                            this._deferSeekingTo = seekingTo;
                        } else if (this._isNearToCurrentTime(seekingTo)) {
                            this._toPlaying();
                        } else {
                            this._jump(offset);
                        }
                        break;

                    case MediaPlayer.STATE.PAUSED:
                        this._toBuffering();
                        if (!this._currentTimeKnown) {
                            this._deferSeekingTo = seekingTo;
                        } else if (this._isNearToCurrentTime(seekingTo)) {
                            this._playerPlugin.Resume();
                            this._toPlaying();
                        } else {
                            this._jump(offset);
                        }
                        break;

                    case MediaPlayer.STATE.STOPPED:
                    case MediaPlayer.STATE.COMPLETE:
                        this._playerPlugin.ResumePlay(this._source, seekingTo);
                        this._toBuffering();
                        break;

                    default:
                        this._toError("Cannot playFrom while in the '" + this.getState() + "' state");
                        break;
                }
            },

            /**
            * @inheritDoc
            */
            pause: function () {
                this._postBufferingState = MediaPlayer.STATE.PAUSED;
                switch (this.getState()) {
                    case MediaPlayer.STATE.BUFFERING:
                    case MediaPlayer.STATE.PAUSED:
                        break;

                    case MediaPlayer.STATE.PLAYING:
                        this._pauseWithStateTransition();
                        break;

                    default:
                        this._toError("Cannot pause while in the '" + this.getState() + "' state");
                        break;
                }
            },

            /**
            * @inheritDoc
            */
            stop: function () {
                switch (this.getState()) {
                    case MediaPlayer.STATE.BUFFERING:
                    case MediaPlayer.STATE.PLAYING:
                    case MediaPlayer.STATE.PAUSED:
                    case MediaPlayer.STATE.COMPLETE:
                        this._stopPlayer();
                        this._toStopped();
                        break;

                    default:
                        this._toError("Cannot stop while in the '" + this.getState() + "' state");
                        break;
                }
            },

            /**
            * @inheritDoc
            */
            reset: function () {
                switch (this.getState()) {
                    case MediaPlayer.STATE.STOPPED:
                    case MediaPlayer.STATE.ERROR:
                        this._toEmpty();
                        break;

                    default:
                        this._toError("Cannot reset while in the '" + this.getState() + "' state");
                        break;
                }
            },

            /**
            * @inheritDoc
            */
            getSource: function () {
                return this._source;
            },

            /**
            * @inheritDoc
            */
            getMimeType: function () {
                return this._mimeType;
            },

            /**
            * @inheritDoc
            */
            getCurrentTime: function () {
                var result = undefined;
                switch (this.getState()) {
                    case MediaPlayer.STATE.STOPPED:
                        break;
                    default:
                        result = this._currentTime;
                        break;
                }
                return result;
            },

            /**
            * @inheritDoc
            */
            getRange: function () {
                return this._range;
            },

            /**
            * @inheritDoc
            */
            getState: function () {
                return this._state;
            },

            _onFinishedBuffering: function() {
                if (this.getState() !== MediaPlayer.STATE.BUFFERING) {
                    return;
                } else if (this._postBufferingState === MediaPlayer.STATE.PAUSED) {
                    this._pauseWithStateTransition();
                } else {
                    this._toPlaying();
                }
            },

            _onDeviceError: function(message) {
                this._toError(message);
            },

            _onDeviceBuffering: function() {
                this._toBuffering();
            },

            _onEndOfMedia: function() {
                this._stopPlayer();
                this._toComplete();
            },

            _stopPlayer: function() {
                this._playerPlugin.Stop();
                this._currentTimeKnown = false;
            },

            _pauseWithStateTransition: function() {
                var result = this._playerPlugin.Pause();
                if (result) {
                    this._toPaused();
                }

                this._tryingToPause = !result;
            },

            _onStatus: function() {
                var state = this.getState();
                if (state === MediaPlayer.STATE.PLAYING) {
                    this._emitEvent(MediaPlayer.EVENT.STATUS);
                }

                if (this._tryingToPause) {
                    this._pauseWithStateTransition();
                }
            },

            _onMetadata: function() {
                this._range = {
                    start: 0,
                    end: this._playerPlugin.GetDuration() / 1000
                };
            },

            _onCurrentTime: function(timeInMillis) {
                this._currentTime = timeInMillis / 1000;
                this._onStatus();
                this._currentTimeKnown = true;
                this._deferredSeek();
            },

            _deferredSeek: function() {
                if (this._deferSeekingTo) {
                    this.playFrom(this._deferSeekingTo);
                    this._deferSeekingTo = null;
                }
            },

            _registerEventHandlers: function() {
                var self = this;

                window.SamsungMapleOnRenderError = function () {
                    self._onDeviceError("Media element emitted OnRenderError");
                };
                this._playerPlugin.OnRenderError = 'SamsungMapleOnRenderError';

                window.SamsungMapleOnConnectionFailed = function () {
                    self._onDeviceError("Media element emitted OnConnectionFailed");
                };
                this._playerPlugin.OnConnectionFailed = 'SamsungMapleOnConnectionFailed';

                window.SamsungMapleOnNetworkDisconnected = function () {
                    self._onDeviceError("Media element emitted OnNetworkDisconnected");
                };
                this._playerPlugin.OnNetworkDisconnected = 'SamsungMapleOnNetworkDisconnected';

                window.SamsungMapleOnStreamNotFound = function () {
                    self._onDeviceError("Media element emitted OnStreamNotFound");
                };
                this._playerPlugin.OnStreamNotFound = 'SamsungMapleOnStreamNotFound';

                window.SamsungMapleOnAuthenticationFailed = function () {
                    self._onDeviceError("Media element emitted OnAuthenticationFailed");
                };
                this._playerPlugin.OnAuthenticationFailed = 'SamsungMapleOnAuthenticationFailed';

                window.SamsungMapleOnRenderingComplete = function () {
                    self._onEndOfMedia();
                };
                this._playerPlugin.OnRenderingComplete = 'SamsungMapleOnRenderingComplete';

                window.SamsungMapleOnBufferingStart = function () {
                    self._onDeviceBuffering();
                };
                this._playerPlugin.OnBufferingStart = 'SamsungMapleOnBufferingStart';

                window.SamsungMapleOnBufferingComplete = function () {
                    self._onFinishedBuffering();
                };
                this._playerPlugin.OnBufferingComplete = 'SamsungMapleOnBufferingComplete';

                window.SamsungMapleOnStreamInfoReady = function () {
                    self._onMetadata();
                };
                this._playerPlugin.OnStreamInfoReady = 'SamsungMapleOnStreamInfoReady';

                window.SamsungMapleOnCurrentPlayTime = function (timeInMillis) {
                    self._onCurrentTime(timeInMillis);
                };
                this._playerPlugin.OnCurrentPlayTime = 'SamsungMapleOnCurrentPlayTime';

                this._onWindowHide = function () {
                    self.stop();
                };

                window.addEventListener('hide', this._onWindowHide, false);
                window.addEventListener('unload', this._onWindowHide, false);
            },

            _unregisterEventHandlers: function() {
                var eventHandlers = [
                    'SamsungMapleOnRenderError',
                    'SamsungMapleOnRenderingComplete',
                    'SamsungMapleOnBufferingStart',
                    'SamsungMapleOnBufferingComplete',
                    'SamsungMapleOnStreamInfoReady',
                    'SamsungMapleOnCurrentPlayTime',
                    'SamsungMapleOnConnectionFailed',
                    'SamsungMapleOnNetworkDisconnected',
                    'SamsungMapleOnStreamNotFound',
                    'SamsungMapleOnAuthenticationFailed'
                ];

                for (var i = 0; i < eventHandlers.length; i++){
                    var handler = eventHandlers[i];
                    var hook = handler.substring("SamsungMaple".length);
                    this._playerPlugin[hook] = undefined;

                    delete window[handler];
                }

                window.removeEventListener('hide', this._onWindowHide, false);
                window.removeEventListener('unload', this._onWindowHide, false);
            },

            _wipe: function () {
                this._stopPlayer();
                this._type = undefined;
                this._source = undefined;
                this._mimeType = undefined;
                this._currentTime = undefined;
                this._range = undefined;
                this._unregisterEventHandlers();
            },

            _jump: function (offsetSeconds) {
                if (offsetSeconds > 0) {
                    this._playerPlugin.JumpForward(offsetSeconds);
                } else {
                    this._playerPlugin.JumpBackward(Math.abs(offsetSeconds));
                }
            },

            _toStopped: function () {
                this._currentTime = 0;
                this._range = undefined;
                this._state = MediaPlayer.STATE.STOPPED;
                this._emitEvent(MediaPlayer.EVENT.STOPPED);
            },

            _toBuffering: function () {
                if (this._state !== MediaPlayer.STATE.BUFFERING) {
                    this._state = MediaPlayer.STATE.BUFFERING;
                    this._emitEvent(MediaPlayer.EVENT.BUFFERING);
                }
            },

            _toPlaying: function () {
                this._state = MediaPlayer.STATE.PLAYING;
                this._emitEvent(MediaPlayer.EVENT.PLAYING);
            },

            _toPaused: function () {
                this._state = MediaPlayer.STATE.PAUSED;
                this._emitEvent(MediaPlayer.EVENT.PAUSED);
            },

            _toComplete: function () {
                this._currentTime = undefined;
                this._state = MediaPlayer.STATE.COMPLETE;
                this._emitEvent(MediaPlayer.EVENT.COMPLETE);
            },

            _toEmpty: function () {
                this._wipe();
                this._state = MediaPlayer.STATE.EMPTY;
            },

            _toError: function(errorMessage) {
                RuntimeContext.getDevice().getLogger().error(errorMessage);
                this._wipe();
                this._state = MediaPlayer.STATE.ERROR;
                this._emitEvent(MediaPlayer.EVENT.ERROR);
            },

            /**
             * @constant {Number} Time (in seconds) compared to current time within which seeking has no effect.
             * On a sample device (Samsung FoxP 2013), seeking by two seconds worked 90% of the time, but seeking
             * by 2.5 seconds was always seen to work.
             */
            CURRENT_TIME_TOLERANCE: 2.5
        });

        var instance = new Player();

        // Mixin this MediaPlayer implementation, so that device.getMediaPlayer() returns the correct implementation for the device
        Device.prototype.getMediaPlayer = function() {
            return instance;
        };

        return Player;
    }

);
<commit_msg>Rename helper method to make its intent more clear<commit_after>/**
 * @fileOverview Requirejs module containing device modifier to launch native external media players
 *
 * @preserve Copyright (c) 2014 British Broadcasting Corporation
 * (http://www.bbc.co.uk) and TAL Contributors (1)
 *
 * (1) TAL Contributors are listed in the AUTHORS file and at
 *     https://github.com/fmtvp/TAL/AUTHORS - please extend this file,
 *     not this notice.
 *
 * @license 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.
 *
 * All rights reserved
 * Please contact us for an alternative licence
 */

require.def(
    "antie/devices/mediaplayer/samsung_maple",
    [
        "antie/devices/device",
        "antie/devices/mediaplayer/mediaplayer",
        "antie/runtimecontext"
    ],
    function(Device, MediaPlayer, RuntimeContext) {
        "use strict";

        var Player = MediaPlayer.extend({

            init: function() {
                this._super();
                this._state = MediaPlayer.STATE.EMPTY;
                this._playerPlugin = document.getElementById('playerPlugin');
            },

            /**
            * @inheritDoc
            */
            setSource: function (mediaType, url, mimeType) {
                if (this.getState() === MediaPlayer.STATE.EMPTY) {
                    this._type = mediaType;
                    this._source = url;
                    this._mimeType = mimeType;
                    this._registerEventHandlers();
                    this._toStopped();
                    this._currentTimeKnown = false;
                } else {
                    this._toError("Cannot set source unless in the '" + MediaPlayer.STATE.EMPTY + "' state");
                }
            },

            /**
            * @inheritDoc
            */
            resume : function () {
                this._postBufferingState = MediaPlayer.STATE.PLAYING;
                switch (this.getState()) {
                    case MediaPlayer.STATE.PLAYING:
                        break;

                    case MediaPlayer.STATE.BUFFERING:
                        if (this._tryingToPause) {
                            this._tryingToPause = false;
                            this._toPlaying();
                        }
                        break;

                    case MediaPlayer.STATE.PAUSED:
                        this._playerPlugin.Resume();
                        this._toPlaying();
                        break;

                    default:
                        this._toError("Cannot resume while in the '" + this.getState() + "' state");
                        break;
                }
            },

            /**
            * @inheritDoc
            */
            playFrom: function (seconds) {
                this._postBufferingState = MediaPlayer.STATE.PLAYING;
                var seekingTo = this._range ? this._getClampedTime(seconds) : seconds;
                var offset = seekingTo - this.getCurrentTime();
                switch (this.getState()) {
                    case MediaPlayer.STATE.BUFFERING:
                        if (!this._currentTimeKnown) {
                            this._deferSeekingTo = seekingTo;
                        } else {
                            this._jump(offset);
                        }
                        break;

                    case MediaPlayer.STATE.PLAYING:
                        this._toBuffering();
                        if (!this._currentTimeKnown) {
                            this._deferSeekingTo = seekingTo;
                        } else if (this._isNearToCurrentTime(seekingTo)) {
                            this._toPlaying();
                        } else {
                            this._jump(offset);
                        }
                        break;

                    case MediaPlayer.STATE.PAUSED:
                        this._toBuffering();
                        if (!this._currentTimeKnown) {
                            this._deferSeekingTo = seekingTo;
                        } else if (this._isNearToCurrentTime(seekingTo)) {
                            this._playerPlugin.Resume();
                            this._toPlaying();
                        } else {
                            this._jump(offset);
                        }
                        break;

                    case MediaPlayer.STATE.STOPPED:
                    case MediaPlayer.STATE.COMPLETE:
                        this._playerPlugin.ResumePlay(this._source, seekingTo);
                        this._toBuffering();
                        break;

                    default:
                        this._toError("Cannot playFrom while in the '" + this.getState() + "' state");
                        break;
                }
            },

            /**
            * @inheritDoc
            */
            pause: function () {
                this._postBufferingState = MediaPlayer.STATE.PAUSED;
                switch (this.getState()) {
                    case MediaPlayer.STATE.BUFFERING:
                    case MediaPlayer.STATE.PAUSED:
                        break;

                    case MediaPlayer.STATE.PLAYING:
                        this._tryPauseWithStateTransition();
                        break;

                    default:
                        this._toError("Cannot pause while in the '" + this.getState() + "' state");
                        break;
                }
            },

            /**
            * @inheritDoc
            */
            stop: function () {
                switch (this.getState()) {
                    case MediaPlayer.STATE.BUFFERING:
                    case MediaPlayer.STATE.PLAYING:
                    case MediaPlayer.STATE.PAUSED:
                    case MediaPlayer.STATE.COMPLETE:
                        this._stopPlayer();
                        this._toStopped();
                        break;

                    default:
                        this._toError("Cannot stop while in the '" + this.getState() + "' state");
                        break;
                }
            },

            /**
            * @inheritDoc
            */
            reset: function () {
                switch (this.getState()) {
                    case MediaPlayer.STATE.STOPPED:
                    case MediaPlayer.STATE.ERROR:
                        this._toEmpty();
                        break;

                    default:
                        this._toError("Cannot reset while in the '" + this.getState() + "' state");
                        break;
                }
            },

            /**
            * @inheritDoc
            */
            getSource: function () {
                return this._source;
            },

            /**
            * @inheritDoc
            */
            getMimeType: function () {
                return this._mimeType;
            },

            /**
            * @inheritDoc
            */
            getCurrentTime: function () {
                var result = undefined;
                switch (this.getState()) {
                    case MediaPlayer.STATE.STOPPED:
                        break;
                    default:
                        result = this._currentTime;
                        break;
                }
                return result;
            },

            /**
            * @inheritDoc
            */
            getRange: function () {
                return this._range;
            },

            /**
            * @inheritDoc
            */
            getState: function () {
                return this._state;
            },

            _onFinishedBuffering: function() {
                if (this.getState() !== MediaPlayer.STATE.BUFFERING) {
                    return;
                } else if (this._postBufferingState === MediaPlayer.STATE.PAUSED) {
                    this._tryPauseWithStateTransition();
                } else {
                    this._toPlaying();
                }
            },

            _onDeviceError: function(message) {
                this._toError(message);
            },

            _onDeviceBuffering: function() {
                this._toBuffering();
            },

            _onEndOfMedia: function() {
                this._stopPlayer();
                this._toComplete();
            },

            _stopPlayer: function() {
                this._playerPlugin.Stop();
                this._currentTimeKnown = false;
            },

            _tryPauseWithStateTransition: function() {
                var result = this._playerPlugin.Pause();
                if (result) {
                    this._toPaused();
                }

                this._tryingToPause = !result;
            },

            _onStatus: function() {
                var state = this.getState();
                if (state === MediaPlayer.STATE.PLAYING) {
                    this._emitEvent(MediaPlayer.EVENT.STATUS);
                }

                if (this._tryingToPause) {
                    this._tryPauseWithStateTransition();
                }
            },

            _onMetadata: function() {
                this._range = {
                    start: 0,
                    end: this._playerPlugin.GetDuration() / 1000
                };
            },

            _onCurrentTime: function(timeInMillis) {
                this._currentTime = timeInMillis / 1000;
                this._onStatus();
                this._currentTimeKnown = true;
                this._deferredSeek();
            },

            _deferredSeek: function() {
                if (this._deferSeekingTo) {
                    this.playFrom(this._deferSeekingTo);
                    this._deferSeekingTo = null;
                }
            },

            _registerEventHandlers: function() {
                var self = this;

                window.SamsungMapleOnRenderError = function () {
                    self._onDeviceError("Media element emitted OnRenderError");
                };
                this._playerPlugin.OnRenderError = 'SamsungMapleOnRenderError';

                window.SamsungMapleOnConnectionFailed = function () {
                    self._onDeviceError("Media element emitted OnConnectionFailed");
                };
                this._playerPlugin.OnConnectionFailed = 'SamsungMapleOnConnectionFailed';

                window.SamsungMapleOnNetworkDisconnected = function () {
                    self._onDeviceError("Media element emitted OnNetworkDisconnected");
                };
                this._playerPlugin.OnNetworkDisconnected = 'SamsungMapleOnNetworkDisconnected';

                window.SamsungMapleOnStreamNotFound = function () {
                    self._onDeviceError("Media element emitted OnStreamNotFound");
                };
                this._playerPlugin.OnStreamNotFound = 'SamsungMapleOnStreamNotFound';

                window.SamsungMapleOnAuthenticationFailed = function () {
                    self._onDeviceError("Media element emitted OnAuthenticationFailed");
                };
                this._playerPlugin.OnAuthenticationFailed = 'SamsungMapleOnAuthenticationFailed';

                window.SamsungMapleOnRenderingComplete = function () {
                    self._onEndOfMedia();
                };
                this._playerPlugin.OnRenderingComplete = 'SamsungMapleOnRenderingComplete';

                window.SamsungMapleOnBufferingStart = function () {
                    self._onDeviceBuffering();
                };
                this._playerPlugin.OnBufferingStart = 'SamsungMapleOnBufferingStart';

                window.SamsungMapleOnBufferingComplete = function () {
                    self._onFinishedBuffering();
                };
                this._playerPlugin.OnBufferingComplete = 'SamsungMapleOnBufferingComplete';

                window.SamsungMapleOnStreamInfoReady = function () {
                    self._onMetadata();
                };
                this._playerPlugin.OnStreamInfoReady = 'SamsungMapleOnStreamInfoReady';

                window.SamsungMapleOnCurrentPlayTime = function (timeInMillis) {
                    self._onCurrentTime(timeInMillis);
                };
                this._playerPlugin.OnCurrentPlayTime = 'SamsungMapleOnCurrentPlayTime';

                this._onWindowHide = function () {
                    self.stop();
                };

                window.addEventListener('hide', this._onWindowHide, false);
                window.addEventListener('unload', this._onWindowHide, false);
            },

            _unregisterEventHandlers: function() {
                var eventHandlers = [
                    'SamsungMapleOnRenderError',
                    'SamsungMapleOnRenderingComplete',
                    'SamsungMapleOnBufferingStart',
                    'SamsungMapleOnBufferingComplete',
                    'SamsungMapleOnStreamInfoReady',
                    'SamsungMapleOnCurrentPlayTime',
                    'SamsungMapleOnConnectionFailed',
                    'SamsungMapleOnNetworkDisconnected',
                    'SamsungMapleOnStreamNotFound',
                    'SamsungMapleOnAuthenticationFailed'
                ];

                for (var i = 0; i < eventHandlers.length; i++){
                    var handler = eventHandlers[i];
                    var hook = handler.substring("SamsungMaple".length);
                    this._playerPlugin[hook] = undefined;

                    delete window[handler];
                }

                window.removeEventListener('hide', this._onWindowHide, false);
                window.removeEventListener('unload', this._onWindowHide, false);
            },

            _wipe: function () {
                this._stopPlayer();
                this._type = undefined;
                this._source = undefined;
                this._mimeType = undefined;
                this._currentTime = undefined;
                this._range = undefined;
                this._unregisterEventHandlers();
            },

            _jump: function (offsetSeconds) {
                if (offsetSeconds > 0) {
                    this._playerPlugin.JumpForward(offsetSeconds);
                } else {
                    this._playerPlugin.JumpBackward(Math.abs(offsetSeconds));
                }
            },

            _toStopped: function () {
                this._currentTime = 0;
                this._range = undefined;
                this._state = MediaPlayer.STATE.STOPPED;
                this._emitEvent(MediaPlayer.EVENT.STOPPED);
            },

            _toBuffering: function () {
                if (this._state !== MediaPlayer.STATE.BUFFERING) {
                    this._state = MediaPlayer.STATE.BUFFERING;
                    this._emitEvent(MediaPlayer.EVENT.BUFFERING);
                }
            },

            _toPlaying: function () {
                this._state = MediaPlayer.STATE.PLAYING;
                this._emitEvent(MediaPlayer.EVENT.PLAYING);
            },

            _toPaused: function () {
                this._state = MediaPlayer.STATE.PAUSED;
                this._emitEvent(MediaPlayer.EVENT.PAUSED);
            },

            _toComplete: function () {
                this._currentTime = undefined;
                this._state = MediaPlayer.STATE.COMPLETE;
                this._emitEvent(MediaPlayer.EVENT.COMPLETE);
            },

            _toEmpty: function () {
                this._wipe();
                this._state = MediaPlayer.STATE.EMPTY;
            },

            _toError: function(errorMessage) {
                RuntimeContext.getDevice().getLogger().error(errorMessage);
                this._wipe();
                this._state = MediaPlayer.STATE.ERROR;
                this._emitEvent(MediaPlayer.EVENT.ERROR);
            },

            /**
             * @constant {Number} Time (in seconds) compared to current time within which seeking has no effect.
             * On a sample device (Samsung FoxP 2013), seeking by two seconds worked 90% of the time, but seeking
             * by 2.5 seconds was always seen to work.
             */
            CURRENT_TIME_TOLERANCE: 2.5
        });

        var instance = new Player();

        // Mixin this MediaPlayer implementation, so that device.getMediaPlayer() returns the correct implementation for the device
        Device.prototype.getMediaPlayer = function() {
            return instance;
        };

        return Player;
    }

);
<|endoftext|>


<commit_before>/* eslint-disable react/destructuring-assignment */
/* eslint-disable react/forbid-prop-types */
/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

import React from 'react';
import PropTypes from 'prop-types';

import { StyleSheet, View } from 'react-native';

import { PageContentModal } from './PageContentModal';

import globalStyles, { DARK_GREY, WARM_GREY, SUSSOL_ORANGE } from '../../globalStyles';
import { AutocompleteSelector, ToggleBar, PageButton, TextEditor } from '..';

import { SETTINGS_KEYS } from '../../settings';
import { getAllPrograms, getAllPeriodsForProgram } from '../../utilities';
import SequentialSteps from '../SequentialSteps';

const localization = {
  program: 'program',
  supplier: 'supplier',
  orderType: 'order type',
  period: 'period',
  programTitle: 'Select a Program to use',
  supplierTitle: 'Select a Supplier to use',
  orderTypeTitle: 'Select a Order Type to use',
  periodTitle: 'Select a Period to use',
  nameTitle: 'Give your stocktake a name',
  programError: 'No programs available',
  supplierError: 'No suppliers available',
  orderTypeError: 'No order types available',
  periodError: 'No periods available',
};

const newState = {
  RESET_ALL: {
    program: null,
    supplier: null,
    period: null,
    periods: null,
    orderType: null,
    orderTypes: null,
    name: null,
    currentStepKey: null,
    isProgramBased: true,
  },
  SELECT_PROGRAM: {
    period: {},
    periods: null,
    supplier: {},
    orderType: {},
    orderTypes: null,
    modalIsOpen: false,
  },
  SELECT_ORDER_TYPE: { period: {}, periods: null, modalIsOpen: false },
  SELECT_NAME: { modalIsOpen: false },
  SELECT_PERIOD: { modalIsOpen: false },
  SELECT_SUPPLIER: { modalIsOpen: false },
};

export class ByProgramModal extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      // Values used for deriving current UI state
      steps: null,
      modalIsOpen: false,
      isProgramBased: true,
      currentStepKey: null,
      // New requisition or stocktake values
      program: null,
      supplier: null,
      orderType: null,
      period: null,
      name: null,
      // Data stored for performance
      storeTag: null,
      programs: null,
      suppliers: null,
      orderTypes: null,
      periods: null,
    };
  }

  // Store unchanging select modal options and set the default
  // steps array.
  componentDidMount = () => {
    const { settings, database } = this.props;
    const programs = getAllPrograms(settings, database);
    const suppliers = database.objects('Name').filtered('isSupplier = $0', true);
    const steps = this.setCurrentSteps();
    this.setState({ programs, suppliers, currentStepKey: steps[0].key });
  };

  onConfirmRequisition = () => {
    const { onConfirm } = this.props;
    const { supplier: otherStoreName, orderType } = this.state;
    onConfirm({ ...this.state, otherStoreName, orderType: orderType && orderType.name });
    this.setState({ ...newState.RESET_ALL }, () => this.setCurrentSteps());
  };

  onToggleChange = () => {
    const { isProgramBased } = this.state;
    this.setState({ ...newState.RESET_ALL, isProgramBased: !isProgramBased }, () =>
      this.setCurrentSteps(true)
    );
  };

  // Open a modal - in case it is an earlier step in the process,
  // set the current step to the step number corresponding with
  // the onPress event.
  onModalTransition = ({ key: currentStepKey }) => {
    if (currentStepKey) this.setState({ modalIsOpen: true, currentStepKey });
    else this.setState({ modalIsOpen: false });
  };

  getSequentialStepsProps = () => {
    const { name } = this.state;

    const getBaseProps = key => ({
      name: this.state[key] && this.state[key].name,
      placeholder: localization[`${key}Title`],
      key,
      error: this.state[`${key}s`] ? this.state[`${key}s`].length === 0 : false,
      errorText: localization[`${key}Error`],
    });

    return {
      program: getBaseProps('program'),
      supplier: getBaseProps('supplier'),
      name: { name, placeholder: localization.nameTitle, key: name, type: 'input' },
      orderType: getBaseProps('orderType'),
      period: getBaseProps('period'),
    };
  };

  // Initial set up or update the current steps property to reflect the current state
  setCurrentSteps = setNewCurrentKey => {
    const { isProgramBased } = this.state;
    const { type } = this.props;

    const sequentialSteps = this.getSequentialStepsProps();
    const stepKeys = {
      requisition: isProgramBased ? ['program', 'supplier', 'orderType', 'period'] : ['supplier'],
      stocktake: isProgramBased ? ['program', 'name'] : ['name'],
    };
    const steps = stepKeys[type].map(step => sequentialSteps[step]);
    if (setNewCurrentKey) this.setState({ steps, currentStepKey: steps[0].key });
    else this.setState({ steps });

    return steps;
  };

  setNewValue = ({ key, selectedItem }) => {
    const { settings, database, type } = this.props;
    const { program, storeTag, isProgramBased } = this.state;
    const periodScheduleName = storeTag && storeTag.periodScheduleName;

    let nextState;
    switch (key) {
      case 'program':
        nextState = {
          ...newState.SELECT_PROGRAM,
          storeTag: selectedItem.getStoreTagObject(settings.get(SETTINGS_KEYS.THIS_STORE_TAGS)),
          program: selectedItem,
          currentStepKey: type === 'requisition' ? 'supplier' : 'name',
        };
        break;
      case 'supplier':
        nextState = {
          ...newState.SELECT_SUPPLIER,
          supplier: selectedItem,
          orderTypes:
            program &&
            program.getStoreTagObject(settings.get(SETTINGS_KEYS.THIS_STORE_TAGS)).orderTypes,

          currentStepKey: isProgramBased ? 'orderType' : 'complete',
        };
        break;
      case 'orderType':
        nextState = {
          ...newState.SELECT_ORDER_TYPE,
          periods: getAllPeriodsForProgram(database, program, periodScheduleName, selectedItem),
          orderType: selectedItem,
          currentStepKey: 'period',
        };
        break;
      case 'period':
        nextState = {
          ...newState.SELECT_PERIOD,
          period: selectedItem,
          currentStepKey: 'complete',
        };
        break;
      case 'name':
        nextState = {
          ...newState.SELECT_NAME,
          name: selectedItem,
          currentStepKey: 'complete',
        };
        break;
      default:
        break;
    }

    this.setState(nextState, () => this.setCurrentSteps());
  };

  getSearchModalProps = () => {
    const { programs, suppliers, orderTypes, periods, program, orderType } = this.state;

    const getBaseProps = key => ({
      queryString: 'code BEGINSWITH[c] $0',
      sortByString: 'name',
      primaryFilterProperty: 'name',
      renderLeftText: item => `${item.name}`,
      onSelect: selectedItem => this.setNewValue({ key, selectedItem }),
    });

    return {
      program: {
        ...getBaseProps('program'),
        options: programs,
        queryStringSecondary: 'name BEGINSWITH[c] $0',
        renderRightText: item =>
          item.parsedProgramSettings ? item.parsedProgramSettings.elmisCode : '',
      },
      supplier: {
        ...getBaseProps('supplier'),
        options: suppliers,
        secondaryFilterProperty: 'code',
        renderRightText: item => `(${item.code})`,
      },
      orderType: {
        ...getBaseProps('orderType'),
        options: orderTypes,
        renderRightText: item =>
          `Max MOS: ${item.maxMOS} - Threshold MOS: ${item.thresholdMOS} - Max orders per period: ${
            item.maxOrdersPerPeriod
          }`,
      },
      period: {
        ...getBaseProps('period'),
        options: periods,
        renderRightText: item =>
          `${item.toString()} - ${item.requisitionsForOrderType(program, orderType)}/${
            orderType.maxOrdersPerPeriod
          } Requisition(s)`,
      },
    };
  };

  renderTextEditor = () => {
    const { name } = this.state;
    return (
      <TextEditor
        text={name}
        onEndEditing={selectedItem => this.setNewValue({ key: 'name', selectedItem })}
      />
    );
  };

  renderModal = () => {
    const { currentStepKey } = this.state;
    if (currentStepKey === 'name') return this.renderTextEditor();
    return <AutocompleteSelector {...this.getSearchModalProps()[currentStepKey]} />;
  };

  renderToggleBar = () => {
    const { type } = this.props;
    const { isProgramBased } = this.state;
    const buttonText = type === 'requisition' ? 'order' : 'stocktake';
    return (
      <ToggleBar
        toggles={[
          { text: `Program ${buttonText}`, onPress: this.onToggleChange, isOn: isProgramBased },
          { text: `General ${buttonText}`, onPress: this.onToggleChange, isOn: !isProgramBased },
        ]}
      />
    );
  };

  render() {
    const { onCancel, isOpen, type, database } = this.props;
    const { modalIsOpen, steps, currentStepKey } = this.state;
    if (!(steps || currentStepKey)) return null;

    return (
      <PageContentModal
        isOpen={isOpen}
        style={{ ...globalStyles.modal, backgroundColor: DARK_GREY }}
        swipeToClose={false}
        onClose={() => {
          this.setState({ ...newState.RESET_ALL }, () => {
            this.setCurrentSteps(true);
            onCancel();
          });
        }}
        title={`${type[0].toUpperCase()}${type.slice(1, type.length)} Details`}
      >
        <View style={localStyles.toggleContainer}>{this.renderToggleBar()}</View>

        <SequentialSteps
          database={database}
          steps={steps}
          onPress={this.onModalTransition}
          currentStepKey={currentStepKey}
        />

        <PageButton
          text="OK"
          onPress={this.onConfirmRequisition}
          isDisabled={!(currentStepKey === 'complete')}
          disabledColor={WARM_GREY}
          style={localStyles.okButton}
          textStyle={{ ...globalStyles.buttonText, color: 'white' }}
        />

        {modalIsOpen && (
          <PageContentModal
            isOpen={modalIsOpen}
            onClose={this.onModalTransition}
            title={localization[`${currentStepKey}Title`]}
            coverScreen
          >
            {this.renderModal()}
          </PageContentModal>
        )}
      </PageContentModal>
    );
  }
}

export default ByProgramModal;

const localStyles = StyleSheet.create({
  toggleContainer: {
    width: 292,
    alignSelf: 'center',
    marginVertical: 20,
  },
  okButton: {
    ...globalStyles.button,
    backgroundColor: SUSSOL_ORANGE,
    alignSelf: 'center',
    marginTop: 60,
  },
});

ByProgramModal.propTypes = {
  database: PropTypes.object.isRequired,
  onConfirm: PropTypes.func.isRequired,
  onCancel: PropTypes.func.isRequired,
  isOpen: PropTypes.bool.isRequired,
  type: PropTypes.string.isRequired,
  settings: PropTypes.object.isRequired,
};
<commit_msg>Add TODO<commit_after>/* eslint-disable react/destructuring-assignment */
/* eslint-disable react/forbid-prop-types */
/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

import React from 'react';
import PropTypes from 'prop-types';

import { StyleSheet, View } from 'react-native';

import { PageContentModal } from './PageContentModal';

import globalStyles, { DARK_GREY, WARM_GREY, SUSSOL_ORANGE } from '../../globalStyles';
import { AutocompleteSelector, ToggleBar, PageButton, TextEditor } from '..';

import { SETTINGS_KEYS } from '../../settings';
import { getAllPrograms, getAllPeriodsForProgram } from '../../utilities';
import SequentialSteps from '../SequentialSteps';

// TODO: Proper localization
const localization = {
  program: 'program',
  supplier: 'supplier',
  orderType: 'order type',
  period: 'period',
  programTitle: 'Select a Program to use',
  supplierTitle: 'Select a Supplier to use',
  orderTypeTitle: 'Select a Order Type to use',
  periodTitle: 'Select a Period to use',
  nameTitle: 'Give your stocktake a name',
  programError: 'No programs available',
  supplierError: 'No suppliers available',
  orderTypeError: 'No order types available',
  periodError: 'No periods available',
};

const newState = {
  RESET_ALL: {
    program: null,
    supplier: null,
    period: null,
    periods: null,
    orderType: null,
    orderTypes: null,
    name: null,
    currentStepKey: null,
    isProgramBased: true,
  },
  SELECT_PROGRAM: {
    period: {},
    periods: null,
    supplier: {},
    orderType: {},
    orderTypes: null,
    modalIsOpen: false,
  },
  SELECT_ORDER_TYPE: { period: {}, periods: null, modalIsOpen: false },
  SELECT_NAME: { modalIsOpen: false },
  SELECT_PERIOD: { modalIsOpen: false },
  SELECT_SUPPLIER: { modalIsOpen: false },
};

export class ByProgramModal extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      // Values used for deriving current UI state
      steps: null,
      modalIsOpen: false,
      isProgramBased: true,
      currentStepKey: null,
      // New requisition or stocktake values
      program: null,
      supplier: null,
      orderType: null,
      period: null,
      name: null,
      // Data stored for performance
      storeTag: null,
      programs: null,
      suppliers: null,
      orderTypes: null,
      periods: null,
    };
  }

  // Store unchanging select modal options and set the default
  // steps array.
  componentDidMount = () => {
    const { settings, database } = this.props;
    const programs = getAllPrograms(settings, database);
    const suppliers = database.objects('Name').filtered('isSupplier = $0', true);
    const steps = this.setCurrentSteps();
    this.setState({ programs, suppliers, currentStepKey: steps[0].key });
  };

  onConfirmRequisition = () => {
    const { onConfirm } = this.props;
    const { supplier: otherStoreName, orderType } = this.state;
    onConfirm({ ...this.state, otherStoreName, orderType: orderType && orderType.name });
    this.setState({ ...newState.RESET_ALL }, () => this.setCurrentSteps());
  };

  onToggleChange = () => {
    const { isProgramBased } = this.state;
    this.setState({ ...newState.RESET_ALL, isProgramBased: !isProgramBased }, () =>
      this.setCurrentSteps(true)
    );
  };

  // Open a modal - in case it is an earlier step in the process,
  // set the current step to the step number corresponding with
  // the onPress event.
  onModalTransition = ({ key: currentStepKey }) => {
    if (currentStepKey) this.setState({ modalIsOpen: true, currentStepKey });
    else this.setState({ modalIsOpen: false });
  };

  getSequentialStepsProps = () => {
    const { name } = this.state;

    const getBaseProps = key => ({
      name: this.state[key] && this.state[key].name,
      placeholder: localization[`${key}Title`],
      key,
      error: this.state[`${key}s`] ? this.state[`${key}s`].length === 0 : false,
      errorText: localization[`${key}Error`],
    });

    return {
      program: getBaseProps('program'),
      supplier: getBaseProps('supplier'),
      name: { name, placeholder: localization.nameTitle, key: name, type: 'input' },
      orderType: getBaseProps('orderType'),
      period: getBaseProps('period'),
    };
  };

  // Initial set up or update the current steps property to reflect the current state
  setCurrentSteps = setNewCurrentKey => {
    const { isProgramBased } = this.state;
    const { type } = this.props;

    const sequentialSteps = this.getSequentialStepsProps();
    const stepKeys = {
      requisition: isProgramBased ? ['program', 'supplier', 'orderType', 'period'] : ['supplier'],
      stocktake: isProgramBased ? ['program', 'name'] : ['name'],
    };
    const steps = stepKeys[type].map(step => sequentialSteps[step]);
    if (setNewCurrentKey) this.setState({ steps, currentStepKey: steps[0].key });
    else this.setState({ steps });

    return steps;
  };

  setNewValue = ({ key, selectedItem }) => {
    const { settings, database, type } = this.props;
    const { program, storeTag, isProgramBased } = this.state;
    const periodScheduleName = storeTag && storeTag.periodScheduleName;

    let nextState;
    switch (key) {
      case 'program':
        nextState = {
          ...newState.SELECT_PROGRAM,
          storeTag: selectedItem.getStoreTagObject(settings.get(SETTINGS_KEYS.THIS_STORE_TAGS)),
          program: selectedItem,
          currentStepKey: type === 'requisition' ? 'supplier' : 'name',
        };
        break;
      case 'supplier':
        nextState = {
          ...newState.SELECT_SUPPLIER,
          supplier: selectedItem,
          orderTypes:
            program &&
            program.getStoreTagObject(settings.get(SETTINGS_KEYS.THIS_STORE_TAGS)).orderTypes,

          currentStepKey: isProgramBased ? 'orderType' : 'complete',
        };
        break;
      case 'orderType':
        nextState = {
          ...newState.SELECT_ORDER_TYPE,
          periods: getAllPeriodsForProgram(database, program, periodScheduleName, selectedItem),
          orderType: selectedItem,
          currentStepKey: 'period',
        };
        break;
      case 'period':
        nextState = {
          ...newState.SELECT_PERIOD,
          period: selectedItem,
          currentStepKey: 'complete',
        };
        break;
      case 'name':
        nextState = {
          ...newState.SELECT_NAME,
          name: selectedItem,
          currentStepKey: 'complete',
        };
        break;
      default:
        break;
    }

    this.setState(nextState, () => this.setCurrentSteps());
  };

  getSearchModalProps = () => {
    const { programs, suppliers, orderTypes, periods, program, orderType } = this.state;

    const getBaseProps = key => ({
      queryString: 'code BEGINSWITH[c] $0',
      sortByString: 'name',
      primaryFilterProperty: 'name',
      renderLeftText: item => `${item.name}`,
      onSelect: selectedItem => this.setNewValue({ key, selectedItem }),
    });

    return {
      program: {
        ...getBaseProps('program'),
        options: programs,
        queryStringSecondary: 'name BEGINSWITH[c] $0',
        renderRightText: item =>
          item.parsedProgramSettings ? item.parsedProgramSettings.elmisCode : '',
      },
      supplier: {
        ...getBaseProps('supplier'),
        options: suppliers,
        secondaryFilterProperty: 'code',
        renderRightText: item => `(${item.code})`,
      },
      orderType: {
        ...getBaseProps('orderType'),
        options: orderTypes,
        renderRightText: item =>
          `Max MOS: ${item.maxMOS} - Threshold MOS: ${item.thresholdMOS} - Max orders per period: ${
            item.maxOrdersPerPeriod
          }`,
      },
      period: {
        ...getBaseProps('period'),
        options: periods,
        renderRightText: item =>
          `${item.toString()} - ${item.requisitionsForOrderType(program, orderType)}/${
            orderType.maxOrdersPerPeriod
          } Requisition(s)`,
      },
    };
  };

  renderTextEditor = () => {
    const { name } = this.state;
    return (
      <TextEditor
        text={name}
        onEndEditing={selectedItem => this.setNewValue({ key: 'name', selectedItem })}
      />
    );
  };

  renderModal = () => {
    const { currentStepKey } = this.state;
    if (currentStepKey === 'name') return this.renderTextEditor();
    return <AutocompleteSelector {...this.getSearchModalProps()[currentStepKey]} />;
  };

  renderToggleBar = () => {
    const { type } = this.props;
    const { isProgramBased } = this.state;
    const buttonText = type === 'requisition' ? 'order' : 'stocktake';
    return (
      <ToggleBar
        toggles={[
          { text: `Program ${buttonText}`, onPress: this.onToggleChange, isOn: isProgramBased },
          { text: `General ${buttonText}`, onPress: this.onToggleChange, isOn: !isProgramBased },
        ]}
      />
    );
  };

  render() {
    const { onCancel, isOpen, type, database } = this.props;
    const { modalIsOpen, steps, currentStepKey } = this.state;
    if (!(steps || currentStepKey)) return null;

    return (
      <PageContentModal
        isOpen={isOpen}
        style={{ ...globalStyles.modal, backgroundColor: DARK_GREY }}
        swipeToClose={false}
        onClose={() => {
          this.setState({ ...newState.RESET_ALL }, () => {
            this.setCurrentSteps(true);
            onCancel();
          });
        }}
        title={`${type[0].toUpperCase()}${type.slice(1, type.length)} Details`}
      >
        <View style={localStyles.toggleContainer}>{this.renderToggleBar()}</View>

        <SequentialSteps
          database={database}
          steps={steps}
          onPress={this.onModalTransition}
          currentStepKey={currentStepKey}
        />

        <PageButton
          text="OK"
          onPress={this.onConfirmRequisition}
          isDisabled={!(currentStepKey === 'complete')}
          disabledColor={WARM_GREY}
          style={localStyles.okButton}
          textStyle={{ ...globalStyles.buttonText, color: 'white' }}
        />

        {modalIsOpen && (
          <PageContentModal
            isOpen={modalIsOpen}
            onClose={this.onModalTransition}
            title={localization[`${currentStepKey}Title`]}
            coverScreen
          >
            {this.renderModal()}
          </PageContentModal>
        )}
      </PageContentModal>
    );
  }
}

export default ByProgramModal;

const localStyles = StyleSheet.create({
  toggleContainer: {
    width: 292,
    alignSelf: 'center',
    marginVertical: 20,
  },
  okButton: {
    ...globalStyles.button,
    backgroundColor: SUSSOL_ORANGE,
    alignSelf: 'center',
    marginTop: 60,
  },
});

ByProgramModal.propTypes = {
  database: PropTypes.object.isRequired,
  onConfirm: PropTypes.func.isRequired,
  onCancel: PropTypes.func.isRequired,
  isOpen: PropTypes.bool.isRequired,
  type: PropTypes.string.isRequired,
  settings: PropTypes.object.isRequired,
};
<|endoftext|>


<commit_before>/**
 * for define and check implementation of interface javascript
 *
 * @author jittagorn pitakmetagoon
 * create 10/02/2014
 *
 * License Apache License Version 2.0, January 2004
 *
 * =============================================================================
 * example to use
 *
 * var UserService = Interface.define('UserService', {
 *
 *     save : function(user){
 *
 *     }
 * });
 *
 * //define class
 * var UserServiceImpl = function(){
 *
 * };
 *
 * //define method
 * UserServiceImpl.prototype.save = function(){
 *
 * };
 *
 * Interface.ensureImplements(UserServiceImpl, UserService);
 * //will throw Error, it's not implements arguments user on save method
 *
 * modify new
 * -----------------------------------------------------------------------------
 * UserServiceImpl.prototype.save = function(user){
 *
 * };
 *
 * Interface.ensureImplements(UserServiceImpl, UserService); //not throw Error
 */
window.Interface = window.Interface || (function(Array, Object, String, Function, Error, undefined) {

    //define class ImplementsException
    var ImplementsException = function() {
        //
    };

    ImplementsException.prototype = new Error();

    // protect old browser not support method trim
    if (!String.prototype.trim) {
        String.prototype.trim = function() {
            return this.replace(/^\s+|\s+$/g, '');
        };
    }

    //code from http://stackoverflow.com/questions/5767325/remove-specific-element-from-an-array
    Array.prototype.remove = function(item) {
        for (var i = this.length; i--; ) {
            if (this[i] === item) {
                this.splice(i, 1);
            }
        }
    };

    var FuntionUtils = (function() {

        //This regex is from require.js
        var FUNCTION_ARGUMENT_REGEX_PATTERN = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;

        return {
            /**
             * regular expression pattern for get arguments name in the function
             */
            FUNCTION_ARGUMENT_REGEX_PATTERN: FUNCTION_ARGUMENT_REGEX_PATTERN,
            /**
             * for get arguments name of input function parameter
             * code from http://stackoverflow.com/questions/20058391/javascript-dependency-injection
             *
             * @param {Function} func
             * @throws Error
             * @returns {Array<String>} - array of arguments name
             */
            getArgumentsFromFunction: function(func) {
                if (typeof func !== 'function') {
                    throw new Error('Invalid input type parameters, FuntionUtils.getArgumentsFromFunction(Function func) - func is not function.');
                }

                var args = func.toString().match(FUNCTION_ARGUMENT_REGEX_PATTERN)[1].split(',');
                var length = args.length;
                for (var i = 0; i < length; i++) {
                    args[i] = args[i].trim().replace('\n/**/', '');
                }

                args.remove('');

                return args;
            }
        };
    }).call(this);

    function is(data, type) {
        return Object.prototype.toString.call(data) === '[object ' + type + ']';
    }

    function isFunction(data) {
        return is(data, 'Function');
    }

    function isBoolean(data) {
        return is(data, 'Boolean');
    }

    function isString(data) {
        return is(data, 'String');
    }

    function isObject(data) {
        return is(data, 'Object');
    }

    function forEachProperty(object, callback, context) {
        for (var property in object) {
            if (object.hasOwnProperty(property)) {
                var bool = callback.call(context || null, object[property], property, object);
                if (isBoolean(bool) && !bool) {
                    return;
                }
            }
        }
    }

    /**
     * define global Interface
     */
    var Interface = function() {
        //define interface
    };

    var __slice = Array.prototype.slice;

    /**
     * public static method for define Interface by interface name an interface prototype
     *
     * @param {String} name
     * @param {Object} prototype
     *
     * @returns {Bridge} interface
     */
    Interface.define = function(name, prototype) {
        if (!isString(name) || !isObject(prototype)) {
            throw new Error('Invalid input type parameters, Interface.define(String name, Object prototype).');
        }

        var Bridge = function() {
            //define bridge
        };

        Bridge.prototype = new Interface();
        Bridge.interfaceName = name;

        forEachProperty(prototype, function(behavior, property) {
            if (isFunction(behavior)) {
                var args = FuntionUtils.getArgumentsFromFunction(behavior);
                Bridge.prototype[property] = new Function(args, functionBody(property, args));
            }
        });

        function functionBody(property, args) {
            return "throw new Error('Abstract method \\'" + property + "(" + args.join(', ') + ")\\' of interface \\'" + name + "\\' it\\'s not implements.')";
        }

        /**
         * for extends from SuperInterface to this interface
         * @param {Bridge} SuperInterface
         * @returns {Bridge} interface
         */
        Bridge.extends = function() {
            forEachProperty(__slice.call(arguments), function(interfc, index) {
                if (!isFunction(interfc) || !(interfc.prototype instanceof Interface)) {
                    throw new Error('Invalid input type parameters, Interface.extends(Interface interfaces...) - interfaces[' + index + '] is not "Interface".');
                }

                forEachProperty(interfc.prototype, function(method, property) {
                    Bridge.prototype[property] = method;
                });
            });

            return Bridge;
        };

        return Bridge;
    };

    /**
     * for ensure Class or class instance implements an interfaces
     *
     * @param {Function | Object} class
     * @param {Interface} interfaces..
     *
     * @throws {Error}
     */
    Interface.ensureImplements = function() {
        if (arguments.length < 2 || !(isFunction(arguments[0]) || isObject(arguments[0]))) {
            throw new Error('Invalid input type parameters, Interface.ensureImplements(<Function | Object> class, Interface interfaces...).');
        }

        var classInstance = isFunction(arguments[0]) ? arguments[0].prototype : arguments[0];
        var interfaces = __slice.call(arguments, 1);

        //implements multiple interfaces
        forEachProperty(interfaces, function(interfc, index) {
            if (!isFunction(interfc) || !(interfc.prototype instanceof Interface)) {
                throw new Error('Invalid input type parameters, Interface.ensureImplements(<Function | Object> class, Interface interfaces...) - interfaces[' + index + '] is not "Interface".');
            }

            forEachProperty(interfc.prototype, function(behavior, property) {
                if (isFunction(behavior)) {
                    if (!isFunction(classInstance[property])) {
                        throw new ImplementsException('it\'s not implements method ' + property + '() of interface "' + interfc.interfaceName + '".');
                    }

                    var interfaceArgs = FuntionUtils.getArgumentsFromFunction(behavior);
                    var classArgs = FuntionUtils.getArgumentsFromFunction(classInstance[property]);

                    if (interfaceArgs.length !== classArgs.length) {
                        throw new ImplementsException('it\'s not implements arguments on method ' + property + '(' + interfaceArgs.join(', ') + ') of interface "' + interfc.interfaceName + '".');
                    }
                }
            });
        });
    };

    /**
     * for check Class or class instance implements an interfaces
     *
     * @param {Function | Object} class
     * @param {Interface} interfaces..
     *
     * @return {Boolean}
     */
    Interface.isImplements = function() {
        try {
            Interface.ensureImplements.apply(this, arguments);
        } catch (ex) {
            if (ex instanceof ImplementsException) {
                return false;
            }

            throw ex;
        }

        return true;
    };

    /**
     * return Interface
     */
    return Interface;

}).call(this, Array, Object, String, Function, Error);
<commit_msg>modify js document<commit_after>/**
 * for define and check implementation of interface javascript
 *
 * @author jittagorn pitakmetagoon
 * create 10/02/2014
 *
 * License Apache License Version 2.0, January 2004
 *
 * =============================================================================
 * example to use
 *
 * var UserService = Interface.define('UserService', {
 *
 *     save : function(user){
 *
 *     }
 * });
 *
 * //define class
 * var UserServiceImpl = function(){
 *
 * };
 *
 * //define method
 * UserServiceImpl.prototype.save = function(){
 *
 * };
 *
 * Interface.ensureImplements(UserServiceImpl, UserService);
 * //will throw Error, it's not implements arguments user on save method
 *
 * modify new
 * -----------------------------------------------------------------------------
 * UserServiceImpl.prototype.save = function(user){
 *
 * };
 *
 * Interface.ensureImplements(UserServiceImpl, UserService); //not throw Error
 */
window.Interface = window.Interface || (function(Array, Object, String, Function, Error, undefined) {

    //define class ImplementsException
    var ImplementsException = function() {
        //
    };

    //extends an Error
    ImplementsException.prototype = new Error();

    // protect old browser not support method trim
    if (!String.prototype.trim) {
        String.prototype.trim = function() {
            return this.replace(/^\s+|\s+$/g, '');
        };
    }

    //code from http://stackoverflow.com/questions/5767325/remove-specific-element-from-an-array
    Array.prototype.remove = function(item) {
        for (var i = this.length; i--; ) {
            if (this[i] === item) {
                this.splice(i, 1);
            }
        }
    };

    function is(data, type) {
        return Object.prototype.toString.call(data) === '[object ' + type + ']';
    }

    function isFunction(data) {
        return is(data, 'Function');
    }

    function isBoolean(data) {
        return is(data, 'Boolean');
    }

    function isString(data) {
        return is(data, 'String');
    }

    function isObject(data) {
        return is(data, 'Object');
    }

    var FuntionUtils = (function() {

        //This regex is from require.js
        var FUNCTION_ARGUMENT_REGEX_PATTERN = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;

        return {
            /**
             * regular expression pattern for get arguments name in the function
             */
            FUNCTION_ARGUMENT_REGEX_PATTERN: FUNCTION_ARGUMENT_REGEX_PATTERN,
            /**
             * for get arguments name of input function parameter
             * code from http://stackoverflow.com/questions/20058391/javascript-dependency-injection
             *
             * @param {Function} func
             * @throws Error
             * @returns {Array<String>} - array of arguments name
             */
            getArgumentsFromFunction: function(func) {
                if (!isFunction(func)) {
                    throw new Error('Invalid input type parameters, FuntionUtils.getArgumentsFromFunction(Function func) - func is not function.');
                }

                var args = func.toString().match(FUNCTION_ARGUMENT_REGEX_PATTERN)[1].split(',');
                var length = args.length;
                for (var i = 0; i < length; i++) {
                    args[i] = args[i].trim().replace('\n/**/', '');
                }

                args.remove('');

                return args;
            }
        };
    }).call(this);

    function forEachProperty(object, callback, context) {
        for (var property in object) {
            if (object.hasOwnProperty(property)) {
                var bool = callback.call(context || null, object[property], property, object);
                if (isBoolean(bool) && !bool) {
                    return;
                }
            }
        }
    }

    /**
     * define global Interface
     */
    var Interface = function() {
        //define interface
    };

    var __slice = Array.prototype.slice;

    /**
     * public static method for define Interface by interface name an interface prototype
     *
     * @param {String} name
     * @param {Object} prototype
     *
     * @throws {Error} - invalid input type parameters
     * @returns {Bridge} interface
     */
    Interface.define = function(name, prototype) {
        if (!isString(name) || !isObject(prototype)) {
            throw new Error('Invalid input type parameters, Interface.define(String name, Object prototype).');
        }

        var Bridge = function() {
            //define bridge
        };

        //extends an Interface
        Bridge.prototype = new Interface();
        Bridge.__interfaceName = name;

        forEachProperty(prototype, function(behavior, property) {
            if (isFunction(behavior)) {
                var args = FuntionUtils.getArgumentsFromFunction(behavior);
                Bridge.prototype[property] = new Function(args, functionBody(property, args));
            }
        });

        function functionBody(property, args) {
            return "throw new Error('Abstract method \\'" + property + "(" + args.join(', ') + ")\\' of interface \\'" + name + "\\' it\\'s not implements.')";
        }

        /**
         * for extends from SuperInterface to this interface
         * @param {Bridge} SuperInterface
         * @returns {Bridge} interface
         */
        Bridge.extends = function() {
            forEachProperty(__slice.call(arguments), function(interfc, index) {
                if (!isFunction(interfc) || !(interfc.prototype instanceof Interface)) {
                    throw new Error('Invalid input type parameters, Interface.extends(Interface interfaces...) - interfaces[' + index + '] is not "Interface".');
                }

                forEachProperty(interfc.prototype, function(method, property) {
                    Bridge.prototype[property] = method;
                });
            });

            return Bridge;
        };

        return Bridge;
    };

    /**
     * for ensure Class or class instance implements an interfaces
     *
     * @param {Function | Object} class
     * @param {Interface} interfaces..
     *
     * @throws {Error} - invalid input type parameters
     * @throws {ImplementsException}
     */
    Interface.ensureImplements = function() {
        if (arguments.length < 2 || !(isFunction(arguments[0]) || isObject(arguments[0]))) {
            throw new Error('Invalid input type parameters, Interface.ensureImplements(<Function | Object> class, Interface interfaces...).');
        }

        var classInstance = isFunction(arguments[0]) ? arguments[0].prototype : arguments[0];
        var interfaces = __slice.call(arguments, 1);

        //implements multiple interfaces
        forEachProperty(interfaces, function(interfc, index) {
            if (!isFunction(interfc) || !(interfc.prototype instanceof Interface)) {
                throw new Error('Invalid input type parameters, Interface.ensureImplements(<Function | Object> class, Interface interfaces...) - interfaces[' + index + '] is not "Interface".');
            }

            forEachProperty(interfc.prototype, function(behavior, property) {
                if (isFunction(behavior)) {
                    if (!isFunction(classInstance[property])) {
                        throw new ImplementsException('it\'s not implements method ' + property + '() of interface "' + interfc.__interfaceName + '".');
                    }

                    var interfaceArgs = FuntionUtils.getArgumentsFromFunction(behavior);
                    var classArgs = FuntionUtils.getArgumentsFromFunction(classInstance[property]);

                    if (interfaceArgs.length !== classArgs.length) {
                        throw new ImplementsException('it\'s not implements arguments on method ' + property + '(' + interfaceArgs.join(', ') + ') of interface "' + interfc.__interfaceName + '".');
                    }
                }
            });
        });
    };

    /**
     * for check Class or class instance implements an interfaces
     *
     * @param {Function | Object} class
     * @param {Interface} interfaces..
     *
     * @throws {Error} - invalid input type parameters
     * @return {Boolean}
     */
    Interface.isImplements = function() {
        try {
            Interface.ensureImplements.apply(this, arguments);
        } catch (ex) {
            if (ex instanceof ImplementsException) {
                return false;
            }

            throw ex;
        }

        return true;
    };

    /**
     * return Interface
     */
    return Interface;

}).call(this, Array, Object, String, Function, Error);
<|endoftext|>


<commit_before>module.exports = {
  "env": {
    "browser": true,
    "es6": true,
    "node": true
  },
  "extends": "eslint:recommended",
  "parserOptions": {
    "ecmaVersion": 2018,
    "sourceType": "module"
  },
  "rules": {
    "accessor-pairs": "error",
    "array-bracket-newline": "error",
    "array-bracket-spacing": "error",
    "array-callback-return": "error",
    "array-element-newline": "error",
    "arrow-body-style": "error",
    "arrow-parens": "error",
    "arrow-spacing": [
      "error",
      {
        "after": true,
        "before": true
      }
    ],
    "block-scoped-var": "error",
    "block-spacing": "error",
    "brace-style": "error",
    "callback-return": "error",
    "camelcase": "error",
    "capitalized-comments": "error",
    "class-methods-use-this": "error",
    "comma-dangle": "error",
    "comma-spacing": [
      "error",
      {
        "after": true,
        "before": false
      }
    ],
    "comma-style": "error",
    "complexity": [
      "error",
      {
        "max": 2
      }
    ],
    "computed-property-spacing": "error",
    "consistent-return": "error",
    "consistent-this": "error",
    "curly": "error",
    "default-case": "error",
    "dot-location": "error",
    "dot-notation": [
      "error",
      {
        "allowKeywords": true
      }
    ],
    "eol-last": "error",
    "eqeqeq": [
      "warn",
      "allow-null"
    ],
    "func-call-spacing": "error",
    "func-name-matching": "error",
    "func-names": "error",
    "func-style": "error",
    "function-paren-newline": "error",
    "generator-star-spacing": "error",
    "global-require": "error",
    "guard-for-in": "error",
    "handle-callback-err": "error",
    "id-blacklist": "error",
    "id-length": "error",
    "id-match": "error",
    "implicit-arrow-linebreak": [
      "error",
      "beside"
    ],
    "indent": [
      "error",
      2
    ],
    "indent-legacy": "off",
    "init-declarations": "error",
    "jsx-quotes": "error",
    "key-spacing": "error",
    "keyword-spacing": "error",
    "line-comment-position": "error",
    "linebreak-style": [
      "error",
      "unix"
    ],
    "lines-around-comment": "error",
    "lines-around-directive": "error",
    "lines-between-class-members": "error",
    "max-classes-per-file": "error",
    "max-depth": [
      "error",
      {
        "max": 3
      }
    ],
    "max-len": "error",
    "max-lines": "error",
    "max-lines-per-function": [
      "error",
      {
        "max": 20
      }
    ],
    "max-nested-callbacks": [
      "error",
      {
        "max": 3
      }
    ],
    "max-params": "error",
    "max-statements": "error",
    "max-statements-per-line": "error",
    "multiline-comment-style": "error",
    "multiline-ternary": "error",
    "new-cap": "error",
    "new-parens": "error",
    "newline-after-var": "off",
    "newline-before-return": "error",
    "newline-per-chained-call": "error",
    "no-alert": "error",
    "no-array-constructor": "error",
    "no-async-promise-executor": "error",
    "no-await-in-loop": "error",
    // eslint-disable-next-line no-bitwise
    "no-bitwise": "error",
    "no-buffer-constructor": "error",
    "no-caller": "error",
    "no-catch-shadow": "error",
    "no-confusing-arrow": "error",
    "no-continue": "error",
    "no-div-regex": "error",
    "no-duplicate-imports": "error",
    "no-else-return": "error",
    "no-empty-function": "error",
    "no-eq-null": "error",
    "no-eval": "error",
    "no-extend-native": "error",
    "no-extra-bind": "error",
    "no-extra-label": "error",
    "no-extra-parens": "error",
    "no-floating-decimal": "error",
    "no-implicit-coercion": "error",
    "no-implicit-globals": "error",
    "no-implied-eval": "error",
    "no-inline-comments": "error",
    "no-invalid-this": "error",
    "no-iterator": "error",
    "no-label-var": "error",
    "no-labels": "error",
    "no-lone-blocks": "error",
    "no-lonely-if": "error",
    "no-loop-func": "error",
    "no-magic-numbers": "error",
    "no-misleading-character-class": "error",
    "no-mixed-operators": "error",
    "no-mixed-requires": "error",
    "no-multi-assign": "error",
    "no-multi-spaces": "error",
    "no-multi-str": "error",
    "no-multiple-empty-lines": [
      "error",
      {
        "max": 1,
        "maxEOF": 0,
        "maxBOF": 0,
      }
    ],
    "no-native-reassign": "error",
    "no-negated-condition": "error",
    "no-negated-in-lhs": "error",
    "no-nested-ternary": "error",
    "no-new": "error",
    "no-new-func": "error",
    "no-new-object": "error",
    "no-new-require": "error",
    "no-new-wrappers": "error",
    "no-octal-escape": "error",
    "no-param-reassign": "error",
    "no-path-concat": "error",
    "no-plusplus": "error",
    "no-process-env": "error",
    "no-process-exit": "error",
    "no-proto": "error",
    "no-prototype-builtins": "error",
    "no-restricted-globals": "error",
    "no-restricted-imports": "error",
    "no-restricted-modules": "error",
    "no-restricted-properties": "error",
    "no-restricted-syntax": "error",
    "no-return-assign": "error",
    "no-return-await": "error",
    "no-script-url": "error",
    "no-self-compare": "error",
    "no-sequences": "error",
    "no-shadow": "error",
    "no-shadow-restricted-names": "error",
    "no-spaced-func": "error",
    "no-sync": "error",
    "no-tabs": "error",
    "no-template-curly-in-string": "error",
    "no-ternary": "error",
    "no-throw-literal": "error",
    "no-trailing-spaces": "error",
    "no-undef-init": "error",
    "no-undefined": "error",
    "no-underscore-dangle": "error",
    "no-unmodified-loop-condition": "error",
    "no-unneeded-ternary": "error",
    "no-unused-expressions": "error",
    "no-use-before-define": "error",
    "no-useless-call": "error",
    "no-useless-catch": "error",
    "no-useless-computed-key": "error",
    "no-useless-concat": "error",
    "no-useless-constructor": "error",
    "no-useless-rename": "error",
    "no-useless-return": "error",
    "no-var": "error",
    "no-void": "error",
    "no-warning-comments": "error",
    "no-whitespace-before-property": "error",
    "no-with": "error",
    "nonblock-statement-body-position": "error",
    "object-curly-newline": [
      "error",
      {
        "multiline": true
      }
    ],
    "object-curly-spacing": "error",
    "object-property-newline": "error",
    "object-shorthand": "error",
    "one-var": "off",
    "one-var-declaration-per-line": "error",
    "operator-assignment": "error",
    "operator-linebreak": "error",
    "padded-blocks": "off",
    "padding-line-between-statements": "error",
    "prefer-arrow-callback": "error",
    "prefer-const": "off",
    "prefer-destructuring": "error",
    "prefer-numeric-literals": "error",
    "prefer-object-spread": "error",
    "prefer-promise-reject-errors": "error",
    "prefer-reflect": "error",
    "prefer-rest-params": "error",
    "prefer-spread": "error",
    "prefer-template": "error",
    "quote-props": "error",
    "quotes": [
      "error",
      "single"
    ],
    "radix": "error",
    "require-atomic-updates": "error",
    "require-await": "error",
    "require-jsdoc": "error",
    "require-unicode-regexp": "error",
    "rest-spread-spacing": "error",
    "semi": [
      "error",
      "always"
    ],
    "semi-spacing": "error",
    "semi-style": [
      "error",
      "last"
    ],
    "sort-imports": "error",
    "sort-keys": "error",
    "sort-vars": "error",
    "space-after-keywords": "off",
    "space-before-blocks": [
      "error",
      "never"
    ],
    "space-before-function-paren": [
      "error",
      "never"
    ],
    "space-in-parens": [
      "error",
      "never"
    ],
    "space-infix-ops": [
      "error",
      {
        "int32Hint": false
      }
    ],
    "space-return-throw-case": "off",
    "space-unary-ops": "error",
    "spaced-comment": "error",
    "strict": "error",
    "switch-colon-spacing": "error",
    "symbol-description": "error",
    "template-curly-spacing": "error",
    "template-tag-spacing": "error",
    "unicode-bom": [
      "error",
      "never"
    ],
    "valid-jsdoc": "error",
    "vars-on-top": "error",
    "wrap-iife": [
      "error",
      "inside"
    ],
    "wrap-regex": "error",
    "yield-star-spacing": "error",
    "yoda": "error"
  }
};
<commit_msg>update rules<commit_after>module.exports = {
  "env": {
    "browser": true,
    "es6": true,
    "node": true
  },
  "extends": "eslint:recommended",
  "parserOptions": {
    "ecmaVersion": 2018,
    "sourceType": "module"
  },
  "rules": {
    "accessor-pairs": "error",
    "array-bracket-newline": "error",
    "array-bracket-spacing": "error",
    "array-callback-return": "error",
    "array-element-newline": "error",
    "arrow-body-style": "error",
    "arrow-parens": "error",
    "arrow-spacing": [
      "error",
      {
        "after": true,
        "before": true
      }
    ],
    "block-scoped-var": "error",
    "block-spacing": "error",
    "brace-style": "error",
    "callback-return": "error",
    "camelcase": "error",
    "capitalized-comments": "error",
    "class-methods-use-this": "error",
    "comma-dangle": "error",
    "comma-spacing": [
      "error",
      {
        "after": true,
        "before": false
      }
    ],
    "comma-style": "error",
    "complexity": [
      "error",
      {
        "max": 10
      }
    ],
    "computed-property-spacing": "error",
    "consistent-return": "error",
    "consistent-this": "error",
    "curly": "error",
    "default-case": "error",
    "dot-location": "error",
    "dot-notation": [
      "error",
      {
        "allowKeywords": true
      }
    ],
    "eol-last": "error",
    "eqeqeq": [
      "warn",
      "allow-null"
    ],
    "func-call-spacing": "error",
    "func-name-matching": "error",
    "func-names": ["error", "never"],
    "func-style": ["error", "expression"],
    "function-paren-newline": "error",
    "generator-star-spacing": "error",
    "global-require": "error",
    "guard-for-in": "error",
    "handle-callback-err": "error",
    "id-blacklist": "error",
    "id-length": "off",
    "id-match": "error",
    "implicit-arrow-linebreak": [
      "error",
      "beside"
    ],
    "indent": [
      "error",
      2
    ],
    "indent-legacy": "off",
    "init-declarations": "error",
    "jsx-quotes": "error",
    "key-spacing": "error",
    "keyword-spacing": "error",
    "line-comment-position": "error",
    "linebreak-style": [
      "error",
      "unix"
    ],
    "lines-around-comment": "error",
    "lines-around-directive": "error",
    "lines-between-class-members": "error",
    "max-classes-per-file": "error",
    "max-depth": [
      "error",
      {
        "max": 3
      }
    ],
    "max-len": "error",
    "max-lines": "error",
    "max-lines-per-function": [
      "error",
      {
        "max": 20
      }
    ],
    "max-nested-callbacks": [
      "error",
      {
        "max": 3
      }
    ],
    "max-params": "error",
    "max-statements": "error",
    "max-statements-per-line": "error",
    "multiline-comment-style": ["error", "starred-block"],
    "multiline-ternary": "error",
    "new-cap": "error",
    "new-parens": "error",
    "newline-after-var": "off",
    "newline-before-return": "off",
    "newline-per-chained-call": "error",
    "no-alert": "error",
    "no-array-constructor": "error",
    "no-async-promise-executor": "error",
    "no-await-in-loop": "error",
    // eslint-disable-next-line no-bitwise
    "no-bitwise": "error",
    "no-buffer-constructor": "error",
    "no-caller": "error",
    "no-catch-shadow": "error",
    "no-confusing-arrow": "error",
    "no-continue": "error",
    "no-div-regex": "error",
    "no-duplicate-imports": "error",
    "no-else-return": "error",
    "no-empty-function": "error",
    "no-eq-null": "error",
    "no-eval": "error",
    "no-extend-native": "error",
    "no-extra-bind": "error",
    "no-extra-label": "error",
    "no-extra-parens": "error",
    "no-floating-decimal": "error",
    "no-implicit-coercion": "error",
    "no-implicit-globals": "error",
    "no-implied-eval": "error",
    "no-inline-comments": "error",
    "no-invalid-this": "error",
    "no-iterator": "error",
    "no-label-var": "error",
    "no-labels": "error",
    "no-lone-blocks": "error",
    "no-lonely-if": "error",
    "no-loop-func": "error",
    "no-magic-numbers": [
      "error", {
        "ignore": [1],
        "ignoreArrayIndexes": true
      }],
    "no-misleading-character-class": "error",
    "no-mixed-operators": "error",
    "no-mixed-requires": "error",
    "no-multi-assign": "error",
    "no-multi-spaces": "error",
    "no-multi-str": "error",
    "no-multiple-empty-lines": [
      "error",
      {
        "max": 1,
        "maxEOF": 0,
        "maxBOF": 0,
      }
    ],
    "no-native-reassign": "error",
    "no-negated-condition": "error",
    "no-negated-in-lhs": "error",
    "no-nested-ternary": "error",
    "no-new": "error",
    "no-new-func": "error",
    "no-new-object": "error",
    "no-new-require": "error",
    "no-new-wrappers": "error",
    "no-octal-escape": "error",
    "no-param-reassign": "error",
    "no-path-concat": "error",
    "no-plusplus": "error",
    "no-process-env": "error",
    "no-process-exit": "error",
    "no-proto": "error",
    "no-prototype-builtins": "error",
    "no-restricted-globals": "error",
    "no-restricted-imports": "error",
    "no-restricted-modules": "error",
    "no-restricted-properties": "error",
    "no-restricted-syntax": "error",
    "no-return-assign": "error",
    "no-return-await": "error",
    "no-script-url": "error",
    "no-self-compare": "error",
    "no-sequences": "error",
    "no-shadow": "error",
    "no-shadow-restricted-names": "error",
    "no-spaced-func": "error",
    "no-sync": "error",
    "no-tabs": "error",
    "no-template-curly-in-string": "error",
    "no-ternary": "error",
    "no-throw-literal": "error",
    "no-trailing-spaces": "error",
    "no-undef-init": "error",
    "no-undefined": "error",
    "no-underscore-dangle": ["error", { "allowAfterThis": true }],
    "no-unmodified-loop-condition": "error",
    "no-unneeded-ternary": "error",
    "no-unused-expressions": "error",
    "no-use-before-define": "error",
    "no-useless-call": "error",
    "no-useless-catch": "error",
    "no-useless-computed-key": "error",
    "no-useless-concat": "error",
    "no-useless-constructor": "error",
    "no-useless-rename": "error",
    "no-useless-return": "error",
    "no-var": "error",
    "no-void": "error",
    "no-warning-comments": "error",
    "no-whitespace-before-property": "error",
    "no-with": "error",
    "nonblock-statement-body-position": "error",
    "object-curly-newline": [
      "error",
      {
        "multiline": true
      }
    ],
    "object-curly-spacing": "error",
    "object-property-newline": "error",
    "object-shorthand": "error",
    "one-var": "off",
    "one-var-declaration-per-line": "error",
    "operator-assignment": "error",
    "operator-linebreak": "error",
    "padded-blocks": "off",
    "padding-line-between-statements": "error",
    "prefer-arrow-callback": "off",
    "prefer-const": "off",
    "prefer-destructuring": "error",
    "prefer-numeric-literals": "error",
    "prefer-object-spread": "error",
    "prefer-promise-reject-errors": "error",
    "prefer-reflect": "off",
    "prefer-rest-params": "off",
    "prefer-spread": "off",
    "prefer-template": "error",
    "quote-props": "error",
    "quotes": [
      "error",
      "single"
    ],
    "radix": "error",
    "require-atomic-updates": "error",
    "require-await": "error",
    "require-jsdoc": "off",
    "require-unicode-regexp": "off",
    "rest-spread-spacing": "error",
    "semi": [
      "error",
      "always"
    ],
    "semi-spacing": "error",
    "semi-style": [
      "error",
      "last"
    ],
    "sort-imports": "error",
    "sort-keys": "off",
    "sort-vars": "off",
    "space-after-keywords": "off",
    "space-before-blocks": [
      "error",
      "never"
    ],
    "space-before-function-paren": [
      "error",
      "never"
    ],
    "space-in-parens": [
      "error",
      "never"
    ],
    "space-infix-ops": [
      "error",
      {
        "int32Hint": false
      }
    ],
    "space-return-throw-case": "off",
    "space-unary-ops": "error",
    "spaced-comment": "error",
    "strict": "error",
    "switch-colon-spacing": "error",
    "symbol-description": "error",
    "template-curly-spacing": "error",
    "template-tag-spacing": "error",
    "unicode-bom": [
      "error",
      "never"
    ],
    "valid-jsdoc": "error",
    "vars-on-top": "error",
    "wrap-iife": [
      "error",
      "inside"
    ],
    "wrap-regex": "error",
    "yield-star-spacing": "error",
    "yoda": "error"
  }
};
<|endoftext|>