<commit_before>'use strict'

const extend = require('deep-extend')
const UnixFS = require('ipfs-unixfs')
const pull = require('pull-stream')
const through = require('pull-through')
const parallel = require('async/parallel')
const waterfall = require('async/waterfall')
const dagPB = require('ipld-dag-pb')
const CID = require('cids')
const multihash = require('multihashing-async')

const reduce = require('./reduce')

const DAGNode = dagPB.DAGNode

const defaultOptions = {
  chunkerOptions: {
    maxChunkSize: 262144,
    avgChunkSize: 262144
  },
  rawLeaves: false,
  hashAlg: 'sha2-256',
  leafType: 'file',
  cidVersion: 0
}

module.exports = function builder (createChunker, ipld, createReducer, _options) {
  const options = extend({}, defaultOptions, _options)
  options.cidVersion = options.cidVersion || options.cidVersion
  options.hashAlg = options.hashAlg || defaultOptions.hashAlg

  if (options.hashAlg !== 'sha2-256') {
    options.cidVersion = 1
  }

  return function (source) {
    return function (items, cb) {
      parallel(items.map((item) => (cb) => {
        if (!item.content) {
          // item is a directory
          return createAndStoreDir(item, (err, node) => {
            if (err) {
              return cb(err)
            }
            if (node) {
              source.push(node)
            }
            cb()
          })
        }

        // item is a file
        createAndStoreFile(item, (err, node) => {
          if (err) {
            return cb(err)
          }
          if (node) {
            source.push(node)
          }
          cb()
        })
      }), cb)
    }
  }

  function createAndStoreDir (item, callback) {
    // 1. create the empty dir dag node
    // 2. write it to the dag store

    const d = new UnixFS('directory')

    waterfall([
      (cb) => DAGNode.create(d.marshal(), [], options.hashAlg, cb),
      (node, cb) => {
        if (options.onlyHash) {
          return cb(null, node)
        }

        const cid = new CID(options.cidVersion, 'dag-pb', node.multihash)

        node = new DAGNode(
          node.data,
          node.links,
          node.serialized,
          cid
        )

        ipld.put(node, {
          cid
        }, (err) => cb(err, node))
      }
    ], (err, node) => {
      if (err) {
        return callback(err)
      }
      callback(null, {
        path: item.path,
        multihash: node.cid.buffer,
        size: node.size
      })
    })
  }

  function createAndStoreFile (file, callback) {
    if (Buffer.isBuffer(file.content)) {
      file.content = pull.values([file.content])
    }

    if (typeof file.content !== 'function') {
      return callback(new Error('invalid content'))
    }

    const reducer = createReducer(reduce(file, ipld, options), options)
    let chunker

    try {
      chunker = createChunker(options.chunkerOptions)
    } catch (error) {
      return callback(error)
    }

    let previous
    let count = 0

    pull(
      file.content,
      chunker,
      pull.map(chunk => {
        if (options.progress && typeof options.progress === 'function') {
          options.progress(chunk.byteLength)
        }
        return Buffer.from(chunk)
      }),
      pull.asyncMap((buffer, callback) => {
        if (options.rawLeaves) {
          return multihash(buffer, options.hashAlg, (error, hash) => {
            if (error) {
              return callback(error)
            }

            return callback(null, {
              multihash: hash,
              size: buffer.length,
              leafSize: buffer.length,
              cid: new CID(1, 'raw', hash),
              data: buffer
            })
          })
        }

        const file = new UnixFS(options.leafType, buffer)

        DAGNode.create(file.marshal(), [], options.hashAlg, (err, node) => {
          if (err) {
            return callback(err)
          }

          callback(null, {
            multihash: node.multihash,
            size: node.size,
            leafSize: file.fileSize(),
            cid: new CID(options.cidVersion, 'dag-pb', node.multihash),
            data: node
          })
        })
      }),
      pull.asyncMap((leaf, callback) => {
        if (options.onlyHash) {
          return callback(null, leaf)
        }

        ipld.put(leaf.data, {
          cid: leaf.cid
        }, (error) => callback(error, leaf))
      }),
      pull.map((leaf) => {
        return {
          path: file.path,
          multihash: leaf.cid.buffer,
          size: leaf.size,
          leafSize: leaf.leafSize,
          name: '',
          cid: leaf.cid
        }
      }),
      through( // mark as single node if only one single node
        function onData (data) {
          count++
          if (previous) {
            this.queue(previous)
          }
          previous = data
        },
        function ended () {
          if (previous) {
            if (count === 1) {
              previous.single = true
            }
            this.queue(previous)
          }
          this.queue(null)
        }
      ),
      reducer,
      pull.collect((err, roots) => {
        if (err) {
          callback(err)
        } else {
          callback(null, roots[0])
        }
      })
    )
  }
}
<commit_msg>fix: do not use cid property of DAGNodes just yet<commit_after>'use strict'

const extend = require('deep-extend')
const UnixFS = require('ipfs-unixfs')
const pull = require('pull-stream')
const through = require('pull-through')
const parallel = require('async/parallel')
const waterfall = require('async/waterfall')
const dagPB = require('ipld-dag-pb')
const CID = require('cids')
const multihash = require('multihashing-async')

const reduce = require('./reduce')

const DAGNode = dagPB.DAGNode

const defaultOptions = {
  chunkerOptions: {
    maxChunkSize: 262144,
    avgChunkSize: 262144
  },
  rawLeaves: false,
  hashAlg: 'sha2-256',
  leafType: 'file',
  cidVersion: 0
}

module.exports = function builder (createChunker, ipld, createReducer, _options) {
  const options = extend({}, defaultOptions, _options)
  options.cidVersion = options.cidVersion || options.cidVersion
  options.hashAlg = options.hashAlg || defaultOptions.hashAlg

  if (options.hashAlg !== 'sha2-256') {
    options.cidVersion = 1
  }

  return function (source) {
    return function (items, cb) {
      parallel(items.map((item) => (cb) => {
        if (!item.content) {
          // item is a directory
          return createAndStoreDir(item, (err, node) => {
            if (err) {
              return cb(err)
            }
            if (node) {
              source.push(node)
            }
            cb()
          })
        }

        // item is a file
        createAndStoreFile(item, (err, node) => {
          if (err) {
            return cb(err)
          }
          if (node) {
            source.push(node)
          }
          cb()
        })
      }), cb)
    }
  }

  function createAndStoreDir (item, callback) {
    // 1. create the empty dir dag node
    // 2. write it to the dag store

    const d = new UnixFS('directory')

    waterfall([
      (cb) => DAGNode.create(d.marshal(), [], options.hashAlg, cb),
      (node, cb) => {
        if (options.onlyHash) {
          return cb(null, node)
        }

        const cid = new CID(options.cidVersion, 'dag-pb', node.multihash)

        node = new DAGNode(
          node.data,
          node.links,
          node.serialized,
          cid
        )

        ipld.put(node, {
          cid
        }, (err) => cb(err, node))
      }
    ], (err, node) => {
      if (err) {
        return callback(err)
      }
      callback(null, {
        path: item.path,
        multihash: node.multihash,
        size: node.size
      })
    })
  }

  function createAndStoreFile (file, callback) {
    if (Buffer.isBuffer(file.content)) {
      file.content = pull.values([file.content])
    }

    if (typeof file.content !== 'function') {
      return callback(new Error('invalid content'))
    }

    const reducer = createReducer(reduce(file, ipld, options), options)
    let chunker

    try {
      chunker = createChunker(options.chunkerOptions)
    } catch (error) {
      return callback(error)
    }

    let previous
    let count = 0

    pull(
      file.content,
      chunker,
      pull.map(chunk => {
        if (options.progress && typeof options.progress === 'function') {
          options.progress(chunk.byteLength)
        }
        return Buffer.from(chunk)
      }),
      pull.asyncMap((buffer, callback) => {
        if (options.rawLeaves) {
          return multihash(buffer, options.hashAlg, (error, hash) => {
            if (error) {
              return callback(error)
            }

            return callback(null, {
              multihash: hash,
              size: buffer.length,
              leafSize: buffer.length,
              cid: new CID(1, 'raw', hash),
              data: buffer
            })
          })
        }

        const file = new UnixFS(options.leafType, buffer)

        DAGNode.create(file.marshal(), [], options.hashAlg, (err, node) => {
          if (err) {
            return callback(err)
          }

          callback(null, {
            multihash: node.multihash,
            size: node.size,
            leafSize: file.fileSize(),
            cid: new CID(options.cidVersion, 'dag-pb', node.multihash),
            data: node
          })
        })
      }),
      pull.asyncMap((leaf, callback) => {
        if (options.onlyHash) {
          return callback(null, leaf)
        }

        ipld.put(leaf.data, {
          cid: leaf.cid
        }, (error) => callback(error, leaf))
      }),
      pull.map((leaf) => {
        return {
          path: file.path,
          multihash: leaf.cid.buffer,
          size: leaf.size,
          leafSize: leaf.leafSize,
          name: '',
          cid: leaf.cid
        }
      }),
      through( // mark as single node if only one single node
        function onData (data) {
          count++
          if (previous) {
            this.queue(previous)
          }
          previous = data
        },
        function ended () {
          if (previous) {
            if (count === 1) {
              previous.single = true
            }
            this.queue(previous)
          }
          this.queue(null)
        }
      ),
      reducer,
      pull.collect((err, roots) => {
        if (err) {
          callback(err)
        } else {
          callback(null, roots[0])
        }
      })
    )
  }
}
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { IndexLink } from 'react-router';
import { LinkContainer } from 'react-router-bootstrap';
import { Navbar, Nav, NavItem } from 'react-bootstrap';
import Helmet from 'react-helmet';
import { isLoaded as isAuthLoaded, load as loadAuth, logout } from 'redux/modules/auth';
import { pushState } from 'redux-router';
import connectData from 'helpers/connectData';
import config from '../../config';

function fetchData(getState, dispatch) {
  const promises = [];
  if (!isAuthLoaded(getState())) {
    promises.push(dispatch(loadAuth()));
  }
  return Promise.all(promises);
}

@connectData(fetchData)
@connect(
  state => ({user: state.auth.user}),
  {logout, pushState})
export default class App extends Component {
  static propTypes = {
    children: PropTypes.object.isRequired,
    user: PropTypes.object,
    logout: PropTypes.func.isRequired,
    pushState: PropTypes.func.isRequired
  };

  static contextTypes = {
    store: PropTypes.object.isRequired
  };

  componentWillReceiveProps(nextProps) {
    if (!this.props.user && nextProps.user) {
      // login
      this.props.pushState(null, '/loginSuccess');
    } else if (this.props.user && !nextProps.user) {
      // logout
      this.props.pushState(null, '/');
    }
  }

  handleLogout = (event) => {
    event.preventDefault();
    this.props.logout();
  }

  render() {
    const {user} = this.props;
    const styles = require('./App.scss');

    return (

        <Helmet {...config.app.head}/>
        <Navbar fixedTop>
          <Navbar.Header>
            <Navbar.Brand>
              <IndexLink to="/" activeStyle={{color: '#33e0ff'}}>

                {config.app.title}
              </IndexLink>
            </Navbar.Brand>
            <Navbar.Toggle/>
          </Navbar.Header>

          <Navbar.Collapse eventKey={0}>

              <LinkContainer to="/about">
                <NavItem eventKey={4}>About Us</NavItem>
              </LinkContainer>
              <LinkContainer to="/checkin">
                <NavItem eventKey={5}>Check in</NavItem>
              </LinkContainer>
              <LinkContainer to="/guests">
                <NavItem eventKey={6}>Guests</NavItem>
              </LinkContainer>
              {!user &&
              <LinkContainer to="/login">
                <NavItem eventKey={8}>Login</NavItem>
              </LinkContainer>}
              {user &&
              <LinkContainer to="/logout">
                <NavItem eventKey={9} className="logout-link" onClick={this.handleLogout}>
                  Logout
                </NavItem>
              </LinkContainer>}

            {user &&

Logged in as {user.name}.
}
          </Navbar.Collapse>
        </Navbar>

          {this.props.children}

          Have questions? Ask for help Email

    );
  }
}
<commit_msg>Updating email message<commit_after>import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { IndexLink } from 'react-router';
import { LinkContainer } from 'react-router-bootstrap';
import { Navbar, Nav, NavItem } from 'react-bootstrap';
import Helmet from 'react-helmet';
import { isLoaded as isAuthLoaded, load as loadAuth, logout } from 'redux/modules/auth';
import { pushState } from 'redux-router';
import connectData from 'helpers/connectData';
import config from '../../config';

function fetchData(getState, dispatch) {
  const promises = [];
  if (!isAuthLoaded(getState())) {
    promises.push(dispatch(loadAuth()));
  }
  return Promise.all(promises);
}

@connectData(fetchData)
@connect(
  state => ({user: state.auth.user}),
  {logout, pushState})
export default class App extends Component {
  static propTypes = {
    children: PropTypes.object.isRequired,
    user: PropTypes.object,
    logout: PropTypes.func.isRequired,
    pushState: PropTypes.func.isRequired
  };

  static contextTypes = {
    store: PropTypes.object.isRequired
  };

  componentWillReceiveProps(nextProps) {
    if (!this.props.user && nextProps.user) {
      // login
      this.props.pushState(null, '/loginSuccess');
    } else if (this.props.user && !nextProps.user) {
      // logout
      this.props.pushState(null, '/');
    }
  }

  handleLogout = (event) => {
    event.preventDefault();
    this.props.logout();
  }

  render() {
    const {user} = this.props;
    const styles = require('./App.scss');

    return (

        <Helmet {...config.app.head}/>
        <Navbar fixedTop>
          <Navbar.Header>
            <Navbar.Brand>
              <IndexLink to="/" activeStyle={{color: '#33e0ff'}}>

                {config.app.title}
              </IndexLink>
            </Navbar.Brand>
            <Navbar.Toggle/>
          </Navbar.Header>

          <Navbar.Collapse eventKey={0}>

              <LinkContainer to="/about">
                <NavItem eventKey={4}>About Us</NavItem>
              </LinkContainer>
              <LinkContainer to="/checkin">
                <NavItem eventKey={5}>Check in</NavItem>
              </LinkContainer>
              <LinkContainer to="/guests">
                <NavItem eventKey={6}>Guests</NavItem>
              </LinkContainer>
              {!user &&
              <LinkContainer to="/login">
                <NavItem eventKey={8}>Login</NavItem>
              </LinkContainer>}
              {user &&
              <LinkContainer to="/logout">
                <NavItem eventKey={9} className="logout-link" onClick={this.handleLogout}>
                  Logout
                </NavItem>
              </LinkContainer>}

            {user &&

Logged in as {user.name}.
}
          </Navbar.Collapse>
        </Navbar>

          {this.props.children}

          Have questions? Email

    );
  }
}
<|endoftext|>


<commit_before>//= require ./support/jquery
//= require esphinx_ui
//= require esphinx/ajax
//= require esphinx/support/function
//= require esphinx/support/array
//= require esphinx/observer

(function ($module) {
    "use strict";

    $module.extend({
        modal: function () {

            // var
            //     index;

            // debugger

            this.domObject = this.domObject || null;

            // global scope (public)
            // runtime set
            // self.close = function () {
            this.close = function () {
                // o objeto deveria ser detruído da memória??
                modal.hide();

                modalMask.replaceToggleClass("basicss-transparent", "basicss-opacity-transition");

                time = parseFloat(
                    modalMask.css("transition-duration")
                ) * 1000;
                setTimeout(function () {
                    wrapperModal.remove();
                }, time);

                self.deleteSingleton();
            };

            this.hide = function () {
                modal.hide();

                modalMask.replaceToggleClass("basicss-transparent", "basicss-opacity-transition");

                wrapperModal.css("zIndex", -1);

            };

            this.show = function () {
                wrapperModal = wrapperModal || self.domObject;
                wrapperModal.css("zIndex", 0);
                // modalMask = ;
                // moda = ;
                modalMask
                    .replaceToggleClass("basicss-transparent",
                        "basicss-opacity-transition");
                // debugger
                modal.show();
            };

            var
                self = this,
                $ = jQuery,
                args = arguments[0],
                body = $("body"),
                time = 0,

                wrapperModal,
                modalMask,
                modal,
                header,
                headerActions,
                btnClose,
                content,
                btnHide,
                index,
                instance,

                setButtonsAction = function () {

                    $(document).off("keydown").on("keydown", function (e) {
                        if (e.keyCode === 27) {
                            self.hide();
                        }
                    });

                    btnHide.click(function () {
                        self.hide();
                    });

                    btnClose.click(function () {
                        self.close();
                    });

                },

                observeContent = function () {
                    esPhinx(content[0]).observe({
                        config: {
                            childList: true
                        },
                        done: function () {
                            modal.centralizeOn($(document));
                        }
                    });
                },

                create = function () {
                    wrapperModal = $("

")
                        .addClass("esphinx-ui-wrapper-modal");
                    modalMask = $("

")
                        .addClass("esphinx-ui-modal-mask basicss-fixed" +
                            " basicss-transparent");
                    modal = $("

").addClass("esphinx-ui-modal" +
                        " basicss-hidden");
                    header = $("

")
                        .addClass("esphinx-ui-modal-header");
                    headerActions = $("

")
                        .addClass("esphinx-ui-modal-header-actions");
                    btnClose = $("")
                        .addClass("esphinx-ui-modal-btn-close button");
                    btnHide = $("")
                        .addClass("esphinx-ui-modal-btn-hide button");
                    content = $("

")
                        .addClass("esphinx-ui-modal-content");

                    body.append(wrapperModal);

                    wrapperModal
                        .append(modalMask)
                        .append(modal);

                    modal
                        .append(header)
                        .css({
                            "max-height": $(window).height(),
                            "max-width": $(document).width()
                        });

                    header.append(headerActions);

                    headerActions.append(btnClose);
                    headerActions.append(btnHide);

                    modal.append(content);

                    setButtonsAction();

                    observeContent();

                    if (args.url) {
                        esPhinx.ajax.get({
                            url: args.url,
                            readyStateChange: function (xhr) {
                                if (args.load) {
                                    args.load(modal, xhr);
                                }
                            }
                        }).done(function (answer) {
                            content.append(answer);
                            self.show();
                        });
                    }

                    self.domObject = wrapperModal;

                };

            if (!(this instanceof esPhinx.ui.modal)) {
                if (self = Singleton.instanceExists
                    .apply(esPhinx.ui.modal, arguments.flatten())) {
                    debugger
                    self.show();
                } else {
                    debugger
                    return this.modal.singleton(arguments);
                }
            } else {
                debugger
                create();
            }

            return self;
        }
    });

})(esPhinx.ui);
<commit_msg>suposto código final de modal<commit_after>//= require ./support/jquery
//= require esphinx_ui
//= require esphinx/ajax
//= require esphinx/support/function
//= require esphinx/support/array
//= require esphinx/observer

(function ($module) {
    "use strict";

    $module.extend({
        modal: function () {

            // aparentemente o var realmente faz com que variáveis locais sejam atributos privados de classe, visto que seus valores são mantidos
            // this.domObject = this.domObject || null;

            // global scope (public)
            // runtime set
            this.close = function () {
                // o objeto deveria ser detruído da memória??
                modal.hide();

                modalMask.replaceToggleClass("basicss-transparent", "basicss-opacity-transition");

                time = parseFloat(
                    modalMask.css("transition-duration")
                ) * 1000;
                setTimeout(function () {
                    wrapperModal.remove();
                }, time);

                self.deleteSingleton();
            };

            this.hide = function () {
                modal.hide();

                modalMask.replaceToggleClass("basicss-transparent", "basicss-opacity-transition");

                wrapperModal.css("zIndex", -1);

            };

            this.show = function () {
                // debugger;
                // wrapperModal = wrapperModal || self.domObject;
                wrapperModal.css("zIndex", 0);
                modalMask
                    .replaceToggleClass("basicss-transparent",
                        "basicss-opacity-transition");

                modal.show();
            };

            var
                self = this,
                $ = jQuery,
                args = arguments[0],
                body = $("body"),
                time = 0,

                wrapperModal,
                modalMask,
                modal,
                header,
                headerActions,
                btnClose,
                content,
                btnHide,
                index,
                instance,

                setButtonsAction = function () {

                    $(document).off("keydown").on("keydown", function (e) {
                        if (e.keyCode === 27) {
                            self.hide();
                        }
                    });

                    btnHide.click(function () {
                        self.hide();
                    });

                    btnClose.click(function () {
                        self.close();
                    });

                },

                observeContent = function () {
                    esPhinx(content[0]).observe({
                        config: {
                            childList: true
                        },
                        done: function () {
                            modal.centralizeOn($(document));
                        }
                    });
                },

                create = function () {
                    wrapperModal = $("

")
                        .addClass("esphinx-ui-wrapper-modal");
                    modalMask = $("

")
                        .addClass("esphinx-ui-modal-mask basicss-fixed" +
                            " basicss-transparent");
                    modal = $("

").addClass("esphinx-ui-modal" +
                        " basicss-hidden");
                    header = $("

")
                        .addClass("esphinx-ui-modal-header");
                    headerActions = $("

")
                        .addClass("esphinx-ui-modal-header-actions");
                    btnClose = $("")
                        .addClass("esphinx-ui-modal-btn-close button");
                    btnHide = $("")
                        .addClass("esphinx-ui-modal-btn-hide button");
                    content = $("

")
                        .addClass("esphinx-ui-modal-content");

                    body.append(wrapperModal);

                    wrapperModal
                        .append(modalMask)
                        .append(modal);

                    modal
                        .append(header)
                        .css({
                            "max-height": $(window).height(),
                            "max-width": $(document).width()
                        });

                    header.append(headerActions);

                    headerActions.append(btnClose);
                    headerActions.append(btnHide);

                    modal.append(content);

                    setButtonsAction();

                    observeContent();

                    if (args.url) {
                        esPhinx.ajax.get({
                            url: args.url,
                            readyStateChange: function (xhr) {
                                if (args.load) {
                                    args.load(modal, xhr);
                                }
                            }
                        }).done(function (answer) {
                            content.append(answer);
                            self.show();
                        });
                    }

                    // self.domObject = wrapperModal;

                };

            if (!(this instanceof esPhinx.ui.modal)) {
                if (self = Singleton.instanceExists
                    .apply(esPhinx.ui.modal, arguments.flatten())) {
                    self.show();
                } else {
                    return this.modal.singleton(arguments);
                }
            } else {
                create();
            }

            return self;
        }
    });

})(esPhinx.ui);
<|endoftext|>


<commit_before>$(function() {
  var defaultOptions = {
    plugins: "autolink,contextmenu,paste,fullscreen,inlinepopups,table,preview,style, purposeImageManagerPlugin",
    theme_advanced_statusbar_location: "none",
    theme_advanced_toolbar_location: "top",
    theme_advanced_font_sizes: "8px=8px,9px=9px,10px=10px,11px=11px,12px=12px,13px=13px,14px=14px,15px=15px,16px=16px,17px=17px,18px=18px,19px=19px,20px=20px",
    convert_urls: false,
    forced_root_block: false,
    dialog_type: "modal",
    style_formats: [
        {title: 'Paragraph', block: 'p'},
        {title: 'Heading 1', block: 'h1'},
        {title: 'Heading 2', block: 'h2'},
        {title: 'Heading 3', block: 'h3'},
        {title: 'Heading 4', block: 'h4'}
    ],
    schema: "html5",
    width: "100%",
    setup: function(editor) {
      editor.onChange.add(function() { Purpose.setConfirmUnload(true); });
      editor.onSubmit.add(function() { Purpose.setConfirmUnload(false); });
    }
  };

  var fullEditor = $.extend({}, defaultOptions, {
    theme_advanced_buttons1: "bold,italic,underline,|,justifyleft,justifycenter,justifyright,|,styleselect,fontselect,fontsizeselect,styleprops,removeformat,|,preview,code,fullscreen",
    theme_advanced_buttons2: "bullist,numlist,hr,|,outdent,indent,|,undo,redo,|,link,unlink,image,|,tablecontrols,forecolor,backcolor,purposeImageManagerPlugin",
    verify_css_classes: true,
    schema: "html4"
  });

  var regularEditor = $.extend({}, defaultOptions, {
    theme_advanced_buttons1: "bold,italic,underline,|,justifyleft,justifycenter,justifyright,|,styleselect,|,hr",
    theme_advanced_buttons2: "bullist,numlist,|,outdent,indent,|,undo,redo,|,link,unlink,image,|,code,fullscreen, purposeImageManagerPlugin"
  });

  var compactEditor = $.extend({}, defaultOptions, {
    theme_advanced_buttons1: "bold,italic,underline,|,undo,redo,|,link,unlink,|,code"
  });

  var minimalEditor = $.extend({}, defaultOptions, {
    theme_advanced_buttons1: "bullist,|,undo,redo,|,link,unlink,|,code"
  });

  $('textarea.html-full-editor').livequery(function() { $(this).tinymce($.extend(fullEditor, this.dataset));});

  $('[data-script-directionality="left-to-right"] textarea.html-editor').livequery(function() { $(this).tinymce($.extend(regularEditor, this.dataset));});
  $('[data-script-directionality="right-to-left"] textarea.html-editor').livequery(function() { $(this).tinymce($.extend(regularEditor, {skin: 'right_to_left'}, this.dataset));});

  $('[data-script-directionality="left-to-right"] textarea.html-compact-editor').livequery(function() { $(this).tinymce(compactEditor) });
  $('[data-script-directionality="right-to-left"] textarea.html-compact-editor').livequery(function() { $(this).tinymce($.extend(compactEditor, {skin: 'right_to_left'})) });

  $('[data-script-directionality="left-to-right"] textarea.html-minimal-editor').livequery(function() { $(this).tinymce(minimalEditor) });
  $('[data-script-directionality="right-to-left"] textarea.html-minimal-editor').livequery(function() { $(this).tinymce($.extend(minimalEditor, {skin: 'right_to_left'})) });
});
<commit_msg>[john] - [bug] adding modules creates RTL style module<commit_after>$(function() {
  var defaultOptions = {
    plugins: "autolink,contextmenu,paste,fullscreen,inlinepopups,table,preview,style, purposeImageManagerPlugin",
    theme_advanced_statusbar_location: "none",
    theme_advanced_toolbar_location: "top",
    theme_advanced_font_sizes: "8px=8px,9px=9px,10px=10px,11px=11px,12px=12px,13px=13px,14px=14px,15px=15px,16px=16px,17px=17px,18px=18px,19px=19px,20px=20px",
    convert_urls: false,
    forced_root_block: false,
    dialog_type: "modal",
    style_formats: [
        {title: 'Paragraph', block: 'p'},
        {title: 'Heading 1', block: 'h1'},
        {title: 'Heading 2', block: 'h2'},
        {title: 'Heading 3', block: 'h3'},
        {title: 'Heading 4', block: 'h4'}
    ],
    schema: "html5",
    width: "100%",
    setup: function(editor) {
      editor.onChange.add(function() { Purpose.setConfirmUnload(true); });
      editor.onSubmit.add(function() { Purpose.setConfirmUnload(false); });
    }
  };

  var fullEditor = $.extend({}, defaultOptions, {
    theme_advanced_buttons1: "bold,italic,underline,|,justifyleft,justifycenter,justifyright,|,styleselect,fontselect,fontsizeselect,styleprops,removeformat,|,preview,code,fullscreen",
    theme_advanced_buttons2: "bullist,numlist,hr,|,outdent,indent,|,undo,redo,|,link,unlink,image,|,tablecontrols,forecolor,backcolor,purposeImageManagerPlugin",
    verify_css_classes: true,
    schema: "html4"
  });

  var regularEditor = $.extend({}, defaultOptions, {
    theme_advanced_buttons1: "bold,italic,underline,|,justifyleft,justifycenter,justifyright,|,styleselect,|,hr",
    theme_advanced_buttons2: "bullist,numlist,|,outdent,indent,|,undo,redo,|,link,unlink,image,|,code,fullscreen, purposeImageManagerPlugin"
  });

  var compactEditor = $.extend({}, defaultOptions, {
    theme_advanced_buttons1: "bold,italic,underline,|,undo,redo,|,link,unlink,|,code"
  });

  var minimalEditor = $.extend({}, defaultOptions, {
    theme_advanced_buttons1: "bullist,|,undo,redo,|,link,unlink,|,code"
  });

  $('textarea.html-full-editor').livequery(function() { $(this).tinymce($.extend(fullEditor, this.dataset));});

  $('div[data-script-directionality="left-to-right"] textarea.html-editor').livequery(function() {
    $(this).tinymce($.extend({}, regularEditor, this.dataset));
  });
  $('div[data-script-directionality="right-to-left"] textarea.html-editor').livequery(function() {
    $(this).tinymce($.extend({}, regularEditor, {skin: 'right_to_left'}, this.dataset));
  });

  $('[data-script-directionality="left-to-right"] textarea.html-compact-editor').livequery(function() { $(this).tinymce(compactEditor) });
  $('[data-script-directionality="right-to-left"] textarea.html-compact-editor').livequery(function() {
    $(this).tinymce($.extend({}, compactEditor, {skin: 'right_to_left'}));
  });

  $('[data-script-directionality="left-to-right"] textarea.html-minimal-editor').livequery(function() {
    $(this).tinymce(minimalEditor);
  });
  $('[data-script-directionality="right-to-left"] textarea.html-minimal-editor').livequery(function() {
    $(this).tinymce($.extend({}, minimalEditor, {skin: 'right_to_left'}));
  });
});
<|endoftext|>


<commit_before>/* eslint-disable no-restricted-syntax, no-invalid-this */
'use strict';

// MODULES //

var setReadOnly = require( '@stdlib/utils/define-read-only-property' );
var isPositive = require( '@stdlib/assert/is-positive-number' ).isPrimitive;
var isNumber = require( '@stdlib/assert/is-number' ).isPrimitive;
var isnan = require( '@stdlib/assert/is-nan' );
var entropy = require( '@stdlib/math/base/dists/logistic/entropy' );
var kurtosis = require( '@stdlib/math/base/dists/logistic/kurtosis' );
var mean = require( '@stdlib/math/base/dists/logistic/mean' );
var median = require( '@stdlib/math/base/dists/logistic/median' );
var mode = require( '@stdlib/math/base/dists/logistic/mode' );
var skewness = require( '@stdlib/math/base/dists/logistic/skewness' );
var stdev = require( '@stdlib/math/base/dists/logistic/stdev' );
var variance = require( '@stdlib/math/base/dists/logistic/variance' );
var cdf = require( '@stdlib/math/base/dists/logistic/cdf' );
var logcdf = require( '@stdlib/math/base/dists/logistic/logcdf' );
var logpdf = require( '@stdlib/math/base/dists/logistic/logpdf' );
var mgf = require( '@stdlib/math/base/dists/logistic/mgf' );
var pdf = require( '@stdlib/math/base/dists/logistic/pdf' );
var quantile = require( '@stdlib/math/base/dists/logistic/quantile' );

// FUNCTIONS //

/**
* Evaluates the cumulative distribution function (CDF).
*
* @private
* @param {number} x - input value
* @returns {Probability} evaluated CDF
*/
function logisticCDF( x ) {
	return cdf( x, this.mu, this.s );
}

/**
* Evaluates the natural logarithm of the cumulative distribution function (logCDF).
*
* @private
* @param {number} x - input value
* @returns {number} evaluated logCDF
*/
function logisticLogCDF( x ) {
	return logcdf( x, this.mu, this.s );
}

/**
* Evaluates the natural logarithm of the probability density function (logPDF).
*
* @private
* @param {number} x - input value
* @returns {number} evaluated logPDF
*/
function logisticLogPDF( x ) {
	return logpdf( x, this.mu, this.s );
}

/**
* Evaluates the moment-generating function (MGF).
*
* @private
* @param {number} t - input value
* @returns {number} evaluated MGF
*/
function logisticMGF( t ) {
	return mgf( t, this.mu, this.s );
}

/**
* Evaluates the probability density function (PDF).
*
* @private
* @param {number} x - input value
* @returns {number} evaluated PDF
*/
function logisticPDF( x ) {
	return pdf( x, this.mu, this.s );
}

/**
* Evaluates the quantile function.
*
* @private
* @param {Probability} p - input probability
* @returns {number} evaluated quantile function
*/
function logisticQuantile( p ) {
	return quantile( p, this.mu, this.s );
}

// MAIN //

/**
* Logistic distribution constructor.
*
* @constructor
* @param {number} [mu=0.0] - location parameter
* @param {PositiveNumber} [s=1.0] - scale parameter
* @throws {TypeError} `s` must be a positive number
* @returns {Logistic} distribution instance
*
* @example
* var logistic = new Logistic( 1.0, 1.0 );
*
* var y = logistic.cdf( 1.5 );
* // returns ~0.622
*
* var mu = logistic.mean;
* // returns 1.0
*/
function Logistic() {
	var mu;
	var s;
	if ( !(this instanceof Logistic) ) {
		if ( arguments.length === 0 ) {
			return new Logistic();
		}
		return new Logistic( arguments[ 0 ], arguments[ 1 ] );
	}
	if ( arguments.length ) {
		mu = arguments[ 0 ];
		s = arguments[ 1 ];
		if ( !isNumber( mu ) || isnan( mu ) ) {
			throw new TypeError( 'invalid input argument. Location parameter `mu` must be a number primitive. Value: `' + mu + '`' );
		}
		if ( !isPositive( s ) ) {
			throw new TypeError( 'invalid input argument. Scale parameter `s` must be a positive number. Value: `' + s + '`' );
		}
	} else {
		mu = 0.0;
		s = 1.0;
	}
	Object.defineProperty( this, 'mu', {
		'configurable': false,
		'enumerable': true,
		'get': function get() {
			return mu;
		},
		'set': function set( value ) {
			if ( !isNumber( value ) || isnan( value ) ) {
				throw new TypeError( 'invalid value. Must be a number primitive. Value: `' + value + '`' );
			}
			mu = value;
		}
	});
	Object.defineProperty( this, 's', {
		'configurable': false,
		'enumerable': true,
		'get': function get() {
			return s;
		},
		'set': function set( value ) {
			if ( !isPositive( value ) ) {
				throw new TypeError( 'invalid value. Must be a positive number. Value: `' + value + '`' );
			}
			s = value;
		}
	});
	return this;
}

/**
* Logistic distribution differential entropy.
*
* @memberof Logistic.prototype
* @name entropy
* @type {number}
* @see [differential entropy]{@link https://en.wikipedia.org/wiki/Entropy_%28information_theory%29}
*
* @example
* var logistic = new Logistic( 4.0, 12.0 );
*
* var v = logistic.entropy;
* // returns ~4.485
*/
Object.defineProperty( Logistic.prototype, 'entropy', {
	'configurable': false,
	'enumerable': true,
	'get': function get() {
		return entropy( this.mu, this.s );
	}
});

/**
* Logistic distribution excess kurtosis.
*
* @memberof Logistic.prototype
* @name kurtosis
* @type {number}
* @see [kurtosis]{@link https://en.wikipedia.org/wiki/Kurtosis}
*
* @example
* var logistic = new Logistic( 4.0, 12.0 );
*
* var v = logistic.kurtosis;
* // returns 1.2
*/
Object.defineProperty( Logistic.prototype, 'kurtosis', {
	'configurable': false,
	'enumerable': true,
	'get': function get() {
		return kurtosis( this.mu, this.s );
	}
});

/**
* Logistic distribution expected value.
*
* @memberof Logistic.prototype
* @name mean
* @type {number}
* @see [expected value]{@link https://en.wikipedia.org/wiki/Expected_value}
*
* @example
* var logistic = new Logistic( 4.0, 12.0 );
*
* var v = logistic.mean;
* // returns 4.0
*/
Object.defineProperty( Logistic.prototype, 'mean', {
	'configurable': false,
	'enumerable': true,
	'get': function get() {
		return mean( this.mu, this.s );
	}
});

/**
* Logistic distribution median.
*
* @memberof Logistic.prototype
* @name median
* @type {number}
* @see [median]{@link https://en.wikipedia.org/wiki/Median}
*
* @example
* var logistic = new Logistic( 4.0, 12.0 );
*
* var v = logistic.median;
* // returns 4.0
*/
Object.defineProperty( Logistic.prototype, 'median', {
	'configurable': false,
	'enumerable': true,
	'get': function get() {
		return median( this.mu, this.s );
	}
});

/**
* Logistic distribution mode.
*
* @memberof Logistic.prototype
* @name mode
* @type {number}
* @see [mode]{@link https://en.wikipedia.org/wiki/Mode_%28statistics%29}
*
* @example
* var logistic = new Logistic( 4.0, 12.0 );
*
* var v = logistic.mode;
* // returns 4.0
*/
Object.defineProperty( Logistic.prototype, 'mode', {
	'configurable': false,
	'enumerable': true,
	'get': function get() {
		return mode( this.mu, this.s );
	}
});

/**
* Logistic distribution skewness.
*
* @memberof Logistic.prototype
* @name skewness
* @type {number}
* @see [skewness]{@link https://en.wikipedia.org/wiki/Skewness}
*
* @example
* var logistic = new Logistic( 4.0, 12.0 );
*
* var v = logistic.skewness;
* // returns 0.0
*/
Object.defineProperty( Logistic.prototype, 'skewness', {
	'configurable': false,
	'enumerable': true,
	'get': function get() {
		return skewness( this.mu, this.s );
	}
});

/**
* Logistic distribution standard deviation.
*
* @memberof Logistic.prototype
* @name stdev
* @type {PositiveNumber}
* @see [standard deviation]{@link https://en.wikipedia.org/wiki/Standard_deviation}
*
* @example
* var logistic = new Logistic( 4.0, 12.0 );
*
* var v = logistic.stdev;
* // returns ~21.766
*/
Object.defineProperty( Logistic.prototype, 'stdev', {
	'configurable': false,
	'enumerable': true,
	'get': function get() {
		return stdev( this.mu, this.s );
	}
});

/**
* Logistic distribution variance.
*
* @memberof Logistic.prototype
* @name variance
* @type {PositiveNumber}
* @see [variance]{@link https://en.wikipedia.org/wiki/Variance}
*
* @example
* var logistic = new Logistic( 4.0, 12.0 );
*
* var v = logistic.variance;
* // returns ~473.741
*/
Object.defineProperty( Logistic.prototype, 'variance', {
	'configurable': false,
	'enumerable': true,
	'get': function get() {
		return variance( this.mu, this.s );
	}
});

/**
* Evaluates the cumulative distribution function (CDF).
*
* @memberof Logistic.prototype
* @name cdf
* @type {Function}
* @param {number} x - input value
* @returns {number} evaluated CDF
* @see [cdf]{@link https://en.wikipedia.org/wiki/Cumulative_distribution_function}
*
* @example
* var logistic = new Logistic( 2.0, 4.0 );
*
* var v = logistic.cdf( 0.5 );
* // returns ~0.407
*/
setReadOnly( Logistic.prototype, 'cdf', logisticCDF );

/**
* Evaluates the natural logarithm of the cumulative distribution function (logCDF).
*
* @memberof Logistic.prototype
* @name logcdf
* @type {Function}
* @param {number} x - input value
* @returns {number} evaluated logCDF
* @see [cdf]{@link https://en.wikipedia.org/wiki/Cumulative_distribution_function}
*
* @example
* var logistic = new Logistic( 2.0, 4.0 );
*
* var v = logistic.logcdf( 0.5 );
* // returns ~-0.898
*/
setReadOnly( Logistic.prototype, 'logcdf', logisticLogCDF );

/**
* Evaluates the natural logarithm of the probability density function (logPDF).
*
* @memberof Logistic.prototype
* @name logpdf
* @type {Function}
* @param {number} x - input value
* @returns {number} evaluated logPDF
* @see [pdf]{@link https://en.wikipedia.org/wiki/Probability_density_function}
*
* @example
* var logistic = new Logistic( 2.0, 4.0 );
*
* var v = logistic.logpdf( 0.8 );
* // returns ~-2.795
*/
setReadOnly( Logistic.prototype, 'logpdf', logisticLogPDF );

/**
* Evaluates the moment-generating function (MGF).
*
* @memberof Logistic.prototype
* @name mgf
* @type {Function}
* @param {number} t - input value
* @returns {number} evaluated MGF
* @see [mgf]{@link https://en.wikipedia.org/wiki/Moment-generating_function}
*
* @example
* var logistic = new Logistic( 2.0, 4.0 );
*
* var v = logistic.mgf( 0.2 );
* // returns ~6.379
*/
setReadOnly( Logistic.prototype, 'mgf', logisticMGF );

/**
* Evaluates the probability density function (PDF).
*
* @memberof Logistic.prototype
* @name pdf
* @type {Function}
* @param {number} x - input value
* @returns {number} evaluated PDF
* @see [pdf]{@link https://en.wikipedia.org/wiki/Probability_density_function}
*
* @example
* var logistic = new Logistic( 2.0, 4.0 );
*
* var v = logistic.pdf( 0.8 );
* // returns 0.0625
*/
setReadOnly( Logistic.prototype, 'pdf', logisticPDF );

/**
* Evaluates the quantile function.
*
* @memberof Logistic.prototype
* @name quantile
* @type {Function}
* @param {Probability} p - input probability
* @returns {number} evaluated quantile function
* @see [quantile function]{@link https://en.wikipedia.org/wiki/Quantile_function}
*
* @example
* var logistic = new Logistic( 2.0, 4.0 );
*
* var v = logistic.quantile( 0.5 );
* // returns 2.0
*/
setReadOnly( Logistic.prototype, 'quantile', logisticQuantile );

// EXPORTS //

module.exports = Logistic;
<commit_msg>Re-arrange JSDoc tags<commit_after>/* eslint-disable no-restricted-syntax, no-invalid-this */
'use strict';

// MODULES //

var setReadOnly = require( '@stdlib/utils/define-read-only-property' );
var isPositive = require( '@stdlib/assert/is-positive-number' ).isPrimitive;
var isNumber = require( '@stdlib/assert/is-number' ).isPrimitive;
var isnan = require( '@stdlib/assert/is-nan' );
var entropy = require( '@stdlib/math/base/dists/logistic/entropy' );
var kurtosis = require( '@stdlib/math/base/dists/logistic/kurtosis' );
var mean = require( '@stdlib/math/base/dists/logistic/mean' );
var median = require( '@stdlib/math/base/dists/logistic/median' );
var mode = require( '@stdlib/math/base/dists/logistic/mode' );
var skewness = require( '@stdlib/math/base/dists/logistic/skewness' );
var stdev = require( '@stdlib/math/base/dists/logistic/stdev' );
var variance = require( '@stdlib/math/base/dists/logistic/variance' );
var cdf = require( '@stdlib/math/base/dists/logistic/cdf' );
var logcdf = require( '@stdlib/math/base/dists/logistic/logcdf' );
var logpdf = require( '@stdlib/math/base/dists/logistic/logpdf' );
var mgf = require( '@stdlib/math/base/dists/logistic/mgf' );
var pdf = require( '@stdlib/math/base/dists/logistic/pdf' );
var quantile = require( '@stdlib/math/base/dists/logistic/quantile' );

// FUNCTIONS //

/**
* Evaluates the cumulative distribution function (CDF).
*
* @private
* @param {number} x - input value
* @returns {Probability} evaluated CDF
*/
function logisticCDF( x ) {
	return cdf( x, this.mu, this.s );
}

/**
* Evaluates the natural logarithm of the cumulative distribution function (logCDF).
*
* @private
* @param {number} x - input value
* @returns {number} evaluated logCDF
*/
function logisticLogCDF( x ) {
	return logcdf( x, this.mu, this.s );
}

/**
* Evaluates the natural logarithm of the probability density function (logPDF).
*
* @private
* @param {number} x - input value
* @returns {number} evaluated logPDF
*/
function logisticLogPDF( x ) {
	return logpdf( x, this.mu, this.s );
}

/**
* Evaluates the moment-generating function (MGF).
*
* @private
* @param {number} t - input value
* @returns {number} evaluated MGF
*/
function logisticMGF( t ) {
	return mgf( t, this.mu, this.s );
}

/**
* Evaluates the probability density function (PDF).
*
* @private
* @param {number} x - input value
* @returns {number} evaluated PDF
*/
function logisticPDF( x ) {
	return pdf( x, this.mu, this.s );
}

/**
* Evaluates the quantile function.
*
* @private
* @param {Probability} p - input probability
* @returns {number} evaluated quantile function
*/
function logisticQuantile( p ) {
	return quantile( p, this.mu, this.s );
}

// MAIN //

/**
* Logistic distribution constructor.
*
* @constructor
* @param {number} [mu=0.0] - location parameter
* @param {PositiveNumber} [s=1.0] - scale parameter
* @throws {TypeError} `s` must be a positive number
* @returns {Logistic} distribution instance
*
* @example
* var logistic = new Logistic( 1.0, 1.0 );
*
* var y = logistic.cdf( 1.5 );
* // returns ~0.622
*
* var mu = logistic.mean;
* // returns 1.0
*/
function Logistic() {
	var mu;
	var s;
	if ( !(this instanceof Logistic) ) {
		if ( arguments.length === 0 ) {
			return new Logistic();
		}
		return new Logistic( arguments[ 0 ], arguments[ 1 ] );
	}
	if ( arguments.length ) {
		mu = arguments[ 0 ];
		s = arguments[ 1 ];
		if ( !isNumber( mu ) || isnan( mu ) ) {
			throw new TypeError( 'invalid input argument. Location parameter `mu` must be a number primitive. Value: `' + mu + '`' );
		}
		if ( !isPositive( s ) ) {
			throw new TypeError( 'invalid input argument. Scale parameter `s` must be a positive number. Value: `' + s + '`' );
		}
	} else {
		mu = 0.0;
		s = 1.0;
	}
	Object.defineProperty( this, 'mu', {
		'configurable': false,
		'enumerable': true,
		'get': function get() {
			return mu;
		},
		'set': function set( value ) {
			if ( !isNumber( value ) || isnan( value ) ) {
				throw new TypeError( 'invalid value. Must be a number primitive. Value: `' + value + '`' );
			}
			mu = value;
		}
	});
	Object.defineProperty( this, 's', {
		'configurable': false,
		'enumerable': true,
		'get': function get() {
			return s;
		},
		'set': function set( value ) {
			if ( !isPositive( value ) ) {
				throw new TypeError( 'invalid value. Must be a positive number. Value: `' + value + '`' );
			}
			s = value;
		}
	});
	return this;
}

/**
* Logistic distribution differential entropy.
*
* @name entropy
* @memberof Logistic.prototype
* @type {number}
* @see [differential entropy]{@link https://en.wikipedia.org/wiki/Entropy_%28information_theory%29}
*
* @example
* var logistic = new Logistic( 4.0, 12.0 );
*
* var v = logistic.entropy;
* // returns ~4.485
*/
Object.defineProperty( Logistic.prototype, 'entropy', {
	'configurable': false,
	'enumerable': true,
	'get': function get() {
		return entropy( this.mu, this.s );
	}
});

/**
* Logistic distribution excess kurtosis.
*
* @name kurtosis
* @memberof Logistic.prototype
* @type {number}
* @see [kurtosis]{@link https://en.wikipedia.org/wiki/Kurtosis}
*
* @example
* var logistic = new Logistic( 4.0, 12.0 );
*
* var v = logistic.kurtosis;
* // returns 1.2
*/
Object.defineProperty( Logistic.prototype, 'kurtosis', {
	'configurable': false,
	'enumerable': true,
	'get': function get() {
		return kurtosis( this.mu, this.s );
	}
});

/**
* Logistic distribution expected value.
*
* @name mean
* @memberof Logistic.prototype
* @type {number}
* @see [expected value]{@link https://en.wikipedia.org/wiki/Expected_value}
*
* @example
* var logistic = new Logistic( 4.0, 12.0 );
*
* var v = logistic.mean;
* // returns 4.0
*/
Object.defineProperty( Logistic.prototype, 'mean', {
	'configurable': false,
	'enumerable': true,
	'get': function get() {
		return mean( this.mu, this.s );
	}
});

/**
* Logistic distribution median.
*
* @name median
* @memberof Logistic.prototype
* @type {number}
* @see [median]{@link https://en.wikipedia.org/wiki/Median}
*
* @example
* var logistic = new Logistic( 4.0, 12.0 );
*
* var v = logistic.median;
* // returns 4.0
*/
Object.defineProperty( Logistic.prototype, 'median', {
	'configurable': false,
	'enumerable': true,
	'get': function get() {
		return median( this.mu, this.s );
	}
});

/**
* Logistic distribution mode.
*
* @name mode
* @memberof Logistic.prototype
* @type {number}
* @see [mode]{@link https://en.wikipedia.org/wiki/Mode_%28statistics%29}
*
* @example
* var logistic = new Logistic( 4.0, 12.0 );
*
* var v = logistic.mode;
* // returns 4.0
*/
Object.defineProperty( Logistic.prototype, 'mode', {
	'configurable': false,
	'enumerable': true,
	'get': function get() {
		return mode( this.mu, this.s );
	}
});

/**
* Logistic distribution skewness.
*
* @name skewness
* @memberof Logistic.prototype
* @type {number}
* @see [skewness]{@link https://en.wikipedia.org/wiki/Skewness}
*
* @example
* var logistic = new Logistic( 4.0, 12.0 );
*
* var v = logistic.skewness;
* // returns 0.0
*/
Object.defineProperty( Logistic.prototype, 'skewness', {
	'configurable': false,
	'enumerable': true,
	'get': function get() {
		return skewness( this.mu, this.s );
	}
});

/**
* Logistic distribution standard deviation.
*
* @name stdev
* @memberof Logistic.prototype
* @type {PositiveNumber}
* @see [standard deviation]{@link https://en.wikipedia.org/wiki/Standard_deviation}
*
* @example
* var logistic = new Logistic( 4.0, 12.0 );
*
* var v = logistic.stdev;
* // returns ~21.766
*/
Object.defineProperty( Logistic.prototype, 'stdev', {
	'configurable': false,
	'enumerable': true,
	'get': function get() {
		return stdev( this.mu, this.s );
	}
});

/**
* Logistic distribution variance.
*
* @name variance
* @memberof Logistic.prototype
* @type {PositiveNumber}
* @see [variance]{@link https://en.wikipedia.org/wiki/Variance}
*
* @example
* var logistic = new Logistic( 4.0, 12.0 );
*
* var v = logistic.variance;
* // returns ~473.741
*/
Object.defineProperty( Logistic.prototype, 'variance', {
	'configurable': false,
	'enumerable': true,
	'get': function get() {
		return variance( this.mu, this.s );
	}
});

/**
* Evaluates the cumulative distribution function (CDF).
*
* @name cdf
* @memberof Logistic.prototype
* @type {Function}
* @param {number} x - input value
* @returns {number} evaluated CDF
* @see [cdf]{@link https://en.wikipedia.org/wiki/Cumulative_distribution_function}
*
* @example
* var logistic = new Logistic( 2.0, 4.0 );
*
* var v = logistic.cdf( 0.5 );
* // returns ~0.407
*/
setReadOnly( Logistic.prototype, 'cdf', logisticCDF );

/**
* Evaluates the natural logarithm of the cumulative distribution function (logCDF).
*
* @name logcdf
* @memberof Logistic.prototype
* @type {Function}
* @param {number} x - input value
* @returns {number} evaluated logCDF
* @see [cdf]{@link https://en.wikipedia.org/wiki/Cumulative_distribution_function}
*
* @example
* var logistic = new Logistic( 2.0, 4.0 );
*
* var v = logistic.logcdf( 0.5 );
* // returns ~-0.898
*/
setReadOnly( Logistic.prototype, 'logcdf', logisticLogCDF );

/**
* Evaluates the natural logarithm of the probability density function (logPDF).
*
* @name logpdf
* @memberof Logistic.prototype
* @type {Function}
* @param {number} x - input value
* @returns {number} evaluated logPDF
* @see [pdf]{@link https://en.wikipedia.org/wiki/Probability_density_function}
*
* @example
* var logistic = new Logistic( 2.0, 4.0 );
*
* var v = logistic.logpdf( 0.8 );
* // returns ~-2.795
*/
setReadOnly( Logistic.prototype, 'logpdf', logisticLogPDF );

/**
* Evaluates the moment-generating function (MGF).
*
* @name mgf
* @memberof Logistic.prototype
* @type {Function}
* @param {number} t - input value
* @returns {number} evaluated MGF
* @see [mgf]{@link https://en.wikipedia.org/wiki/Moment-generating_function}
*
* @example
* var logistic = new Logistic( 2.0, 4.0 );
*
* var v = logistic.mgf( 0.2 );
* // returns ~6.379
*/
setReadOnly( Logistic.prototype, 'mgf', logisticMGF );

/**
* Evaluates the probability density function (PDF).
*
* @name pdf
* @memberof Logistic.prototype
* @type {Function}
* @param {number} x - input value
* @returns {number} evaluated PDF
* @see [pdf]{@link https://en.wikipedia.org/wiki/Probability_density_function}
*
* @example
* var logistic = new Logistic( 2.0, 4.0 );
*
* var v = logistic.pdf( 0.8 );
* // returns 0.0625
*/
setReadOnly( Logistic.prototype, 'pdf', logisticPDF );

/**
* Evaluates the quantile function.
*
* @name quantile
* @memberof Logistic.prototype
* @type {Function}
* @param {Probability} p - input probability
* @returns {number} evaluated quantile function
* @see [quantile function]{@link https://en.wikipedia.org/wiki/Quantile_function}
*
* @example
* var logistic = new Logistic( 2.0, 4.0 );
*
* var v = logistic.quantile( 0.5 );
* // returns 2.0
*/
setReadOnly( Logistic.prototype, 'quantile', logisticQuantile );

// EXPORTS //

module.exports = Logistic;
<|endoftext|>


<commit_before>import Ember from "ember";
import config from '../../config/environment';

export default Ember.Controller.extend( {
    store: Ember.inject.service(),
    session: Ember.inject.service(),

    queryParams: [ 'sel_users', 'achievement' ],
    achievement: undefined,
    sel_users: [],
    selected_users: [],
    add_user: Ember.computed.alias('model.users.firstObject'),
    task: undefined,
    saving: false,

    sel_user_param_observer: function() {
        var self = this;
        var users = this.get("sel_users").map(function(elem) {
            return self.get("store").find("user", elem);
        });
        this.set("selected_users", users);
    }.observes("sel_users"),

    actions: {
        'delete-user': function(user){
            this.get("selected_users").removeObject(user);
        },

        'add-user': function(){
            var users = this.get("selected_users");
            var new_user = this.get("add_user");

            if (users.contains(new_user)) {
                alert("Uživatel se již nacházi v seznamu!");
            } else {
                users.addObject(new_user);
            }
        },

        'achievement-grant': function(){
            var self = this;

            self.set("saving", true);
            self.set("grant_error", "");
            self.set("grant_status", "");

            console.log(self.get("task"));
            console.log(self.get("achievement.id"));

            if (self.get("achievement") === undefined) {
                self.set("achievement", self.get("model.achievements.firstObject.id"));
            }

            var tsk = null;
            if (self.get("task")) {
                tsk = self.get("task");
            }

            var send_data = {
                'achievement' : Number(self.get("achievement")),
                'task' : tsk,
                'users' : self.get("selected_users").map(function(elem){
                            return Number(elem.get("id"));
                        })
            };

            self.get('session').authorize('authorizer:oauth2', function(header, h) {
                    Ember.$.ajax({
                            url: config.API_LOC + "/admin/achievements/grant",
                            contentType: "application/json",
                            type: 'POST',
                            data: JSON.stringify(send_data, null, '\t'),
                            beforeSend: function(xhr) {
                                    xhr.setRequestHeader(header, h);
                                    self.set("grant_status", "Odesílám požadavek ...");
                            },
                            success: function() {
                                    self.set("grant_status", "Trofej úspěšně přidělena.");
                                    self.set("saving", false);
                            },
                            error: function(xhr) {
                                    self.set("grant_status", undefined);
                                    self.set("grant_error", "Chybová odpověď serveru:\n"+xhr.responseText);
                                    self.set("saving", false);
                            }
                    });
            });

        },
    },
});
<commit_msg>Integrity.<commit_after>import Ember from "ember";
import config from '../../config/environment';

export default Ember.Controller.extend( {
    store: Ember.inject.service(),
    session: Ember.inject.service(),

    needs:[ 'admin/users' ],
    queryParams: [ 'sel_users', 'achievement' ],
    achievement: undefined,
    sel_users: [],
    selected_users: [],
    add_user: Ember.computed.alias('model.users.firstObject'),
    task: undefined,
    saving: false,

    sel_user_param_observer: function() {
        var self = this;
        var users = this.get("sel_users").map(function(elem) {
            return self.get("store").find("user", elem);
        });
        this.set("selected_users", users);
    }.observes("sel_users"),

    actions: {
        'delete-user': function(user){
            this.get("selected_users").removeObject(user);
        },

        'add-user': function(){
            var users = this.get("selected_users");
            var new_user = this.get("add_user");

            if (users.contains(new_user)) {
                alert("Uživatel se již nacházi v seznamu!");
            } else {
                users.addObject(new_user);
            }
        },

        'achievement-grant': function(){
            var self = this;

            self.set("saving", true);
            self.set("grant_error", "");
            self.set("grant_status", "");

            self.get('controllers.admin/users').set('users_plain', []);

            if (self.get("achievement") === undefined) {
                self.set("achievement", self.get("model.achievements.firstObject.id"));
            }

            var tsk = null;
            if (self.get("task")) {
                tsk = self.get("task");
            }

            var send_data = {
                'achievement' : Number(self.get("achievement")),
                'task' : tsk,
                'users' : self.get("selected_users").map(function(elem){
                            return Number(elem.get("id"));
                        })
            };

            self.get('session').authorize('authorizer:oauth2', function(header, h) {
                    Ember.$.ajax({
                            url: config.API_LOC + "/admin/achievements/grant",
                            contentType: "application/json",
                            type: 'POST',
                            data: JSON.stringify(send_data, null, '\t'),
                            beforeSend: function(xhr) {
                                    xhr.setRequestHeader(header, h);
                                    self.set("grant_status", "Odesílám požadavek ...");
                            },
                            success: function() {
                                    self.set("grant_status", "Trofej úspěšně přidělena.");
                                    self.set("saving", false);
                            },
                            error: function(xhr) {
                                    self.set("grant_status", undefined);
                                    self.set("grant_error", "Chybová odpověď serveru:\n"+xhr.responseText);
                                    self.set("saving", false);
                            }
                    });
            });

        },
    },
});
<|endoftext|>


<commit_before>/* global window document beforeEach afterEach describe it */
import {
  spinners,
  getSpinnerClasses,
  setSpinning,
  cancelSpinning,
} from '../components/spinners';

describe('spinners init', () => {
  afterEach(() => {
    document.querySelectorAll.restore();
  });

  it('should call getElements once with the correct selector', () => {
    sinon.spy(document, 'querySelectorAll');
    spinners();
    expect(document.querySelectorAll.getCall(0).args[0]).toBe('[data-sprk-spinner="click"]');
  });
});

describe('getSpinnerClasses tests', () => {
  it('should return the two base spinner classes with no options', () => {
    const expected = 'sprk-c-Spinner sprk-c-Spinner--circle';
    expect(getSpinnerClasses({})).toEqual(expected);
  });

  it('should add the large class if the option is set', () => {
    const expected = 'sprk-c-Spinner sprk-c-Spinner--circle sprk-c-Spinner--large';
    expect(getSpinnerClasses({ size: 'large' })).toEqual(expected);
  });

  it('should add the dark class if the option is set', () => {
    const expected = 'sprk-c-Spinner sprk-c-Spinner--circle sprk-c-Spinner--dark';
    expect(getSpinnerClasses({ lightness: 'dark' })).toEqual(expected);
  });
});

describe('spinners UI tests', () => {
  let spinnerContainer;
  let event;

  beforeEach(() => {
    spinnerContainer = document.createElement('button');
    spinnerContainer.setAttribute('data-sprk-spinner', 'click');
    spinnerContainer.textContent = 'Submit';
    sinon.spy(spinnerContainer, 'addEventListener');
    sinon.spy(spinnerContainer, 'setAttribute');
    document.body.append(spinnerContainer);
    spinners();
  });

  afterEach(() => {
    document.body.innerHTML = '';
    spinnerContainer.addEventListener.restore();
    spinnerContainer.setAttribute.restore();
  });

  it('should attach a click handler to the spinner container', () => {
    expect(spinnerContainer.addEventListener.calledOnce).toBe(true);
    expect(spinnerContainer.addEventListener.getCall(0).args[0]).toBe('click');
  });

  it('should start the spinning if its clicked', () => {
    spinnerContainer.click();
    expect(spinnerContainer.querySelector('div').classList.contains('sprk-c-Spinner--circle')).toBe(true);
  });

  it('should remove spinners if the sprk-cancel-spinners event is triggered on window', () => {
    spinnerContainer.click();
    expect(spinnerContainer.querySelector('div').classList.contains('sprk-c-Spinner--circle')).toBe(true);
    event = new window.Event('sprk-cancel-spinners');
    window.dispatchEvent(event);
    expect(spinnerContainer.querySelector('div')).toBe(null);
  });

  it('should use no text when removing spinners if the sprk-cancel-spinners event is triggered on window and there was no text saved', () => {
    spinnerContainer.click();
    spinnerContainer.removeAttribute('data-sprk-spinner-text');
    expect(spinnerContainer.querySelector('div').classList.contains('sprk-c-Spinner--circle')).toBe(true);
    event = new window.Event('sprk-cancel-spinners');
    window.dispatchEvent(event);
    expect(spinnerContainer.querySelector('div')).toBe(null);
    expect(spinnerContainer.textContent).toBe('');
  });

  it('should not try to start spinning something thats already spinning', () => {
    spinnerContainer.click();
    expect(spinnerContainer.setAttribute.calledThrice).toBe(true);
    expect(spinnerContainer.querySelector('div').classList.contains('sprk-c-Spinner--circle')).toBe(true);
    spinnerContainer.click();
    expect(spinnerContainer.setAttribute.getCalls().length).toBe(3);
  });
});

describe('setSpinning tests', () => {
  let spinnerContainer;

  beforeEach(() => {
    spinnerContainer = document.createElement('button');
    spinnerContainer.textContent = 'Submit';
  });

  it('should replace the content with a spinner', () => {
    setSpinning(spinnerContainer, {});
    expect(spinnerContainer.firstChild.classList.contains('sprk-c-Spinner')).toBe(true);
  });

  it('should set the original text to a data-sprk-spinner-text attr', () => {
    setSpinning(spinnerContainer, {});
    expect(spinnerContainer.getAttribute('data-sprk-spinner-text') === 'Submit').toBe(true);
  });

  it('should set the data-sprk-has-spinner attr to true', () => {
    setSpinning(spinnerContainer, {});
    expect(spinnerContainer.getAttribute('data-sprk-has-spinner') === 'true').toBe(true);
  });

  it('should set the original width to the style attr', () => {
    setSpinning(spinnerContainer, {});
    const expected = 'width: 0px';
    expect(spinnerContainer.getAttribute('style')).toEqual(expected);
  });
});

describe('cancelSpinning tests', () => {
  let spinnerContainer;

  beforeEach(() => {
    spinnerContainer = document.createElement('button');
    spinnerContainer.textContent = 'Submit';
    setSpinning(spinnerContainer, {});
  });

  it('should remove the spinner', () => {
    cancelSpinning(spinnerContainer);
    expect(spinnerContainer.innerHTML).toBe('Submit');
  });

  it('should replace the content with the contents of data-sprk-spinner-text', () => {
    cancelSpinning(spinnerContainer);
    expect(spinnerContainer.textContent).toEqual(spinnerContainer.getAttribute('data-sprk-spinner-text'));
  });

  it('should remove the data-sprk-has-spinner attr', () => {
    cancelSpinning(spinnerContainer, {});
    expect(spinnerContainer.getAttribute('data-sprk-has-spinner')).toBe(null);
  });

  it('should remove the style attr', () => {
    cancelSpinning(spinnerContainer, {});
    expect(spinnerContainer.getAttribute('style')).toBe(null);
  });
});
<commit_msg>add html tests<commit_after>/* global window document beforeEach afterEach describe it */
import {
  spinners,
  getSpinnerClasses,
  setSpinning,
  cancelSpinning,
} from '../components/spinners';

describe('spinners init', () => {
  afterEach(() => {
    document.querySelectorAll.restore();
  });

  it('should call getElements once with the correct selector', () => {
    sinon.spy(document, 'querySelectorAll');
    spinners();
    expect(document.querySelectorAll.getCall(0).args[0]).toBe('[data-sprk-spinner="click"]');
  });
});

describe('getSpinnerClasses tests', () => {
  it('should return the two base spinner classes with no options', () => {
    const expected = 'sprk-c-Spinner sprk-c-Spinner--circle';
    expect(getSpinnerClasses({})).toEqual(expected);
  });

  it('should add the large class if the option is set', () => {
    const expected = 'sprk-c-Spinner sprk-c-Spinner--circle sprk-c-Spinner--large';
    expect(getSpinnerClasses({ size: 'large' })).toEqual(expected);
  });

  it('should add the dark class if the option is set', () => {
    const expected = 'sprk-c-Spinner sprk-c-Spinner--circle sprk-c-Spinner--dark';
    expect(getSpinnerClasses({ lightness: 'dark' })).toEqual(expected);
  });
});

describe('spinners UI tests', () => {
  let spinnerContainer;
  let event;

  beforeEach(() => {
    spinnerContainer = document.createElement('button');
    spinnerContainer.setAttribute('data-sprk-spinner', 'click');
    spinnerContainer.textContent = 'Submit';
    sinon.spy(spinnerContainer, 'addEventListener');
    sinon.spy(spinnerContainer, 'setAttribute');
    document.body.append(spinnerContainer);
    spinners();
  });

  afterEach(() => {
    document.body.innerHTML = '';
    spinnerContainer.addEventListener.restore();
    spinnerContainer.setAttribute.restore();
  });

  it('should attach a click handler to the spinner container', () => {
    expect(spinnerContainer.addEventListener.calledOnce).toBe(true);
    expect(spinnerContainer.addEventListener.getCall(0).args[0]).toBe('click');
  });

  it('should start the spinning if its clicked', () => {
    spinnerContainer.click();
    expect(spinnerContainer.querySelector('div').classList.contains('sprk-c-Spinner--circle')).toBe(true);
  });

  it('should add the loading aria label if spinner is clicked', () => {
    spinnerContainer.click();
    expect(spinnerContainer.getAttribute('aria-label')).toBe('Loading');
  });

  it('should remove the loading aria label if the sprk-cancel-spinners event is triggered on window', () => {
    spinnerContainer.click();
    expect(spinnerContainer.querySelector('div').classList.contains('sprk-c-Spinner--circle')).toBe(true);
    event = new window.Event('sprk-cancel-spinners');
    window.dispatchEvent(event);
    expect(spinnerContainer.getAttribute('aria-label')).toBe(null);
  });

  it('should remove spinners if the sprk-cancel-spinners event is triggered on window', () => {
    spinnerContainer.click();
    expect(spinnerContainer.querySelector('div').classList.contains('sprk-c-Spinner--circle')).toBe(true);
    event = new window.Event('sprk-cancel-spinners');
    window.dispatchEvent(event);
    expect(spinnerContainer.querySelector('div')).toBe(null);
  });

  it('should use no text when removing spinners if the sprk-cancel-spinners event is triggered on window and there was no text saved', () => {
    spinnerContainer.click();
    spinnerContainer.removeAttribute('data-sprk-spinner-text');
    expect(spinnerContainer.querySelector('div').classList.contains('sprk-c-Spinner--circle')).toBe(true);
    event = new window.Event('sprk-cancel-spinners');
    window.dispatchEvent(event);
    expect(spinnerContainer.querySelector('div')).toBe(null);
    expect(spinnerContainer.textContent).toBe('');
  });

  it('should not try to start spinning something thats already spinning', () => {
    spinnerContainer.click();
    expect(spinnerContainer.setAttribute.getCalls().length).toBe(4);
    expect(spinnerContainer.querySelector('div').classList.contains('sprk-c-Spinner--circle')).toBe(true);
    spinnerContainer.click();
    expect(spinnerContainer.setAttribute.getCalls().length).toBe(4);
  });
});

describe('setSpinning tests', () => {
  let spinnerContainer;

  beforeEach(() => {
    spinnerContainer = document.createElement('button');
    spinnerContainer.textContent = 'Submit';
  });

  it('should replace the content with a spinner', () => {
    setSpinning(spinnerContainer, {});
    expect(spinnerContainer.firstChild.classList.contains('sprk-c-Spinner')).toBe(true);
  });

  it('should set the original text to a data-sprk-spinner-text attr', () => {
    setSpinning(spinnerContainer, {});
    expect(spinnerContainer.getAttribute('data-sprk-spinner-text') === 'Submit').toBe(true);
  });

  it('should set the data-sprk-has-spinner attr to true', () => {
    setSpinning(spinnerContainer, {});
    expect(spinnerContainer.getAttribute('data-sprk-has-spinner') === 'true').toBe(true);
  });

  it('should set the original width to the style attr', () => {
    setSpinning(spinnerContainer, {});
    const expected = 'width: 0px';
    expect(spinnerContainer.getAttribute('style')).toEqual(expected);
  });
});

describe('cancelSpinning tests', () => {
  let spinnerContainer;

  beforeEach(() => {
    spinnerContainer = document.createElement('button');
    spinnerContainer.textContent = 'Submit';
    setSpinning(spinnerContainer, {});
  });

  it('should remove the spinner', () => {
    cancelSpinning(spinnerContainer);
    expect(spinnerContainer.innerHTML).toBe('Submit');
  });

  it('should replace the content with the contents of data-sprk-spinner-text', () => {
    cancelSpinning(spinnerContainer);
    expect(spinnerContainer.textContent).toEqual(spinnerContainer.getAttribute('data-sprk-spinner-text'));
  });

  it('should remove the data-sprk-has-spinner attr', () => {
    cancelSpinning(spinnerContainer, {});
    expect(spinnerContainer.getAttribute('data-sprk-has-spinner')).toBe(null);
  });

  it('should remove the style attr', () => {
    cancelSpinning(spinnerContainer, {});
    expect(spinnerContainer.getAttribute('style')).toBe(null);
  });
});
<|endoftext|>


<commit_before>/* eslint no-console:0 */
'use strict'
import { connect } from 'react-redux'
import { denormalizeArticles, getAbsPath } from '../utils/index'
import { fetchArticleIfNeeded } from '../actions/article'
import { fetchArticlesByUuidIfNeeded, fetchRelatedArticlesIfNeeded } from '../actions/articles'
import { setReadProgress, setPageType, setPageTitle, setArticleTopicList } from '../actions/header'
import { ARTICLE, TOPIC, appId } from '../constants/index'
import _ from 'lodash'
import * as ArticleComponents from '../components/article/index'
import Footer from '../components/Footer'
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import classNames from 'classnames'
import commonStyles from '../components/article/Common.scss'
import DocumentMeta from 'react-document-meta'
import async from 'async'
import fbIcon from '../../static/asset/fb.svg'
import lineIcon from '../../static/asset/line.svg'
import styles from './Article.scss'
import leadingImgStyles from '../components/article/LeadingImage.scss'
import twitterIcon from '../../static/asset/twitter.svg'

let articlePostition = {
  beginY: 120,
  endY: 200,
  percent: 0
}

const ArticlePlaceholder = () => {
  return (

)
}

class Article extends Component {

  // for server side rendering,
  // we get not only the article itself but also get related articles and
  // other articles in the same topic for BETTER SEO
  static fetchData({ params, store }) {
    // get article itself first
    return store.dispatch(fetchArticleIfNeeded(params.slug)).then(() => {
      let state = store.getState()
      let articleId = _.get(state, 'selectedArticle.id')
      let article = _.get(state, [ 'entities', 'articles', articleId ])
      let topicId = _.get(article, 'topics')
      let relateds = _.get(article, 'relateds')

      // fetch related articles and other articles in the same topic
      return new Promise((resolve, reject) => { // eslint-disable-line
        // load in parallel
        async.parallel([
          function (callback) {
            store.dispatch(fetchRelatedArticlesIfNeeded(articleId, relateds))
              .then(() => {
                callback(null)
              })
          },
          function (callback) {
            store.dispatch(fetchArticlesByUuidIfNeeded(topicId, TOPIC))
              .then(() => {
                callback(null)
              })
          }
        ], (err, results) => { // eslint-disable-line
          if (err) {
            console.warn('fetchData occurs error:', err)
          }
          resolve()
        })
      })
    })
  }

  constructor(props) {
    super(props)
    this._setArticleBounding = this._setArticleBounding.bind(this)
    this._handleScroll = this._handleScroll.bind(this)
  }

  componentDidMount() {
    this.props.setPageType(ARTICLE)
    this._setArticleBounding()
    this._sendPageLevelAction()
    window.addEventListener('resize', this._setArticleBounding)

    // detect sroll position
    window.addEventListener('scroll', this._handleScroll)
  }

  componentDidUpdate() {
    this._setArticleBounding()
    this._sendPageLevelAction()
  }

  componentWillMount() {
    const { params, selectedArticle } = this.props
    let slug = _.get(params, 'slug')

    // Check if selectedArticle is up to date
    if (_.get(selectedArticle, 'slug') !== slug) {
      // fetch data we need to render the whole article page
      this._fetchData()
    }
  }

  componentWillReceiveProps(nextProps) {
    const { params, selectedArticle } = nextProps
    const slug = _.get(params, 'slug')

    // Check if selectedArticle is up to date
    if (selectedArticle.slug !== slug) {
      // fetch data we need to render the whole article page
      this._fetchData()
    }
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this._setArticleBounding)
    window.removeEventListener('scroll', this._handleScroll)
  }

  _sendPageLevelAction() {
    const { entities, selectedArticle, setArticleTopicList, setPageTitle } = this.props

    let article = _.get(entities, [ 'articles', selectedArticle.id ], {})
    let topicName = _.get(entities, [ 'topics', _.get(article, 'topics'), 'name' ])

    // set navbar title for this article
    setPageTitle(article.id, article.title, topicName)

    let topicArr = this._getTopicArticles(_.get(article, 'topics'))
    // dispatch action for the navbar to display article list
    setArticleTopicList(topicArr)
  }

  // fetch article whole data, including body, related articls and other articles in the same topic
  _fetchData() {
    const { entities, fetchArticleIfNeeded, fetchArticlesByUuidIfNeeded, fetchRelatedArticlesIfNeeded, params, slugToId } = this.props
    let slug = _.get(params, 'slug')

    // fetch article
    fetchArticleIfNeeded(slug)

    let article = _.get(entities, [ 'articles', slugToId[slug] ])
    let topicId = _.get(article, 'topics')
    let relateds = _.get(article, 'relateds')

    //  fetch other articles in the same topic
    fetchArticlesByUuidIfNeeded(topicId, TOPIC)

    // fetch related articles
    fetchRelatedArticlesIfNeeded(_.get(article, 'id'), relateds)
  }

  _getCumulativeOffset(element) {
    let top = 0
    do {
      top += element.offsetTop  || 0
      element = element.offsetParent
    } while(element)

    return top
  }

  _setArticleBounding() {
    const beginEl = ReactDOM.findDOMNode(this.refs.progressBegin)
    const endEl = ReactDOM.findDOMNode(this.refs.progressEnding)
    articlePostition.beginY = _.get(beginEl, 'offsetTop', articlePostition.beginY)
    articlePostition.endY = _.get(endEl, 'offsetTop', articlePostition.endY)
  }

  _handleScroll() {
    const { beginY, endY, percent } = articlePostition
    let scrollRatio = Math.abs((window.scrollY-beginY) / (endY-beginY))
    if(window.scrollY < beginY) {
      scrollRatio = 0
    } else if (scrollRatio > 1) {
      scrollRatio = 1
    }
    let curPercent = Math.round(scrollRatio*100)
    if(percent!== curPercent) {
      articlePostition.percent = curPercent
      // update the header progress bar
      this.props.setReadProgress(curPercent)
    }
  }

  _composeAuthors(article) {
    article = article || {}
    let authors = []
    const list = [ 'writters', 'photographers', 'designers', 'engineers' ]
    list.forEach((item) => {
      if (Array.isArray(article[item])) {
        article[item].forEach((author) => {
          // remove 's'. writters -> writter
          let type = item.slice(0, -1)
          authors.push(_.merge({}, author, { type: type }))
        })
      }
    })
    return authors
  }

  _getTopicArticles(topicId) {
    const { articlesByUuids, entities } = this.props
    let articleIds = _.get(articlesByUuids, [ topicId, 'items' ], [])
    return _.map(articleIds, (id) => _.merge({}, _.get(entities, [ 'articles', id ])))
  }

  render() {
    const { entities, params, selectedArticle } = this.props
    const isFetching = _.get(selectedArticle, 'isFetching')

    if (_.get(selectedArticle, 'slug') !== _.get(params, 'slug')) {
      return null
    }

    let article = denormalizeArticles(_.get(selectedArticle, 'id'), entities)[0] || {}
    let topicArr = this._getTopicArticles(_.get(article, 'topics.id'))
    let topicName = _.get(article, 'topics.name')
    let relatedArticles = _.get(article, 'relateds')
    let authors = this._composeAuthors(article)
    let bodyData = _.get(article, [ 'content', 'apiData' ], [])
    let heroImage = _.get(article, [ 'heroImage' ], null)
    let heroImageSize = _.get(article, [ 'heroImageSize' ], 'normal')
    let introData = _.get(article, [ 'brief', 'apiData' ], [])
    let copyright = _.get(article, [ 'copyright' ], [])
    const cUrl = getAbsPath(this.context.location.pathname, this.context.location.search)

    let topicBox = topicName ?
{topicName}
 : null
    const meta = {
      title: _.get(article, [ 'title' ], '報導者'),
      description: _.get(article, [ 'ogDescription' ], ''),
      canonical: 'https://www.twreporter.org/a/' + _.get(article, [ 'slug' ], []),
      meta: { property: {} },
      auto: { ograph: true }
    }

    if (_.get(heroImage, [ 'image', 'url' ])) {
      _.set(meta, [ 'meta', 'property', 'og:image' ], _.get(heroImage, [ 'image', 'url' ]))
    }

    return (
      <DocumentMeta {...meta}>

          {isFetching ?
<ArticlePlaceholder />
 :

              <hgroup>
                {topicBox}

{article.title}

              </hgroup>

              <ArticleComponents.HeadingAuthor
                authors={authors}
                extendByline={_.get(article, 'extendByline')}
              >
                <ArticleComponents.PublishDate
                  date={article.publishedDate}
                />
              </ArticleComponents.HeadingAuthor>
              <ArticleComponents.ShareBt
                appId={appId}
                url={cUrl}
                title={article.title}
                fbIcon={fbIcon}
                twitterIcon={twitterIcon}
                lineIcon={lineIcon}
              />

              <ArticleComponents.LeadingImage
                size={heroImageSize}
                image={_.get(heroImage, [ 'image', 'resizedTargets' ])}
                id={_.get(heroImage, 'id')}
                description={_.get(heroImage, 'description' )}
              />

              <ArticleComponents.Introduction
                data={introData}
              />

            <ArticleComponents.Body
              data={bodyData}
            />

                <ArticleComponents.BottomTags
                  data={article.tags}
                />

              <ArticleComponents.BottomRelateds
                relateds={relatedArticles}
                currentId={article.id}
                topicName={topicName}
                topicArr={topicArr}
              />

          }
          {/*<ArticleComponents.PageNavigation
            article={ _.get(article, [ 'relateds', 0 ])}
            navigate="next"
          />
          <ArticleComponents.PageNavigation
            article={_.get(article, [ 'relateds', 1 ])}
            navigate="previous"
          />*/}

      </DocumentMeta>
    )
  }
}

function mapStateToProps(state) {
  return {
    articlesByUuids: state.articlesByUuids,
    entities: state.entities,
    selectedArticle: state.selectedArticle,
    slugToId: state.slugToId
  }
}

Article.contextTypes = {
  device: React.PropTypes.string,
  location: React.PropTypes.object
}

export { Article }
export default connect(mapStateToProps, { fetchArticleIfNeeded, fetchRelatedArticlesIfNeeded,
  fetchArticlesByUuidIfNeeded, setReadProgress, setPageType, setPageTitle, setArticleTopicList })(Article)
<commit_msg>Fix content placeholder align<commit_after>/* eslint no-console:0 */
'use strict'
import { connect } from 'react-redux'
import { denormalizeArticles, getAbsPath } from '../utils/index'
import { fetchArticleIfNeeded } from '../actions/article'
import { fetchArticlesByUuidIfNeeded, fetchRelatedArticlesIfNeeded } from '../actions/articles'
import { setReadProgress, setPageType, setPageTitle, setArticleTopicList } from '../actions/header'
import { ARTICLE, TOPIC, appId } from '../constants/index'
import _ from 'lodash'
import * as ArticleComponents from '../components/article/index'
import Footer from '../components/Footer'
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import classNames from 'classnames'
import commonStyles from '../components/article/Common.scss'
import DocumentMeta from 'react-document-meta'
import async from 'async'
import fbIcon from '../../static/asset/fb.svg'
import lineIcon from '../../static/asset/line.svg'
import styles from './Article.scss'
import leadingImgStyles from '../components/article/LeadingImage.scss'
import twitterIcon from '../../static/asset/twitter.svg'

let articlePostition = {
  beginY: 120,
  endY: 200,
  percent: 0
}

const ArticlePlaceholder = () => {
  return (

)
}

class Article extends Component {

  // for server side rendering,
  // we get not only the article itself but also get related articles and
  // other articles in the same topic for BETTER SEO
  static fetchData({ params, store }) {
    // get article itself first
    return store.dispatch(fetchArticleIfNeeded(params.slug)).then(() => {
      let state = store.getState()
      let articleId = _.get(state, 'selectedArticle.id')
      let article = _.get(state, [ 'entities', 'articles', articleId ])
      let topicId = _.get(article, 'topics')
      let relateds = _.get(article, 'relateds')

      // fetch related articles and other articles in the same topic
      return new Promise((resolve, reject) => { // eslint-disable-line
        // load in parallel
        async.parallel([
          function (callback) {
            store.dispatch(fetchRelatedArticlesIfNeeded(articleId, relateds))
              .then(() => {
                callback(null)
              })
          },
          function (callback) {
            store.dispatch(fetchArticlesByUuidIfNeeded(topicId, TOPIC))
              .then(() => {
                callback(null)
              })
          }
        ], (err, results) => { // eslint-disable-line
          if (err) {
            console.warn('fetchData occurs error:', err)
          }
          resolve()
        })
      })
    })
  }

  constructor(props) {
    super(props)
    this._setArticleBounding = this._setArticleBounding.bind(this)
    this._handleScroll = this._handleScroll.bind(this)
  }

  componentDidMount() {
    this.props.setPageType(ARTICLE)
    this._setArticleBounding()
    this._sendPageLevelAction()
    window.addEventListener('resize', this._setArticleBounding)

    // detect sroll position
    window.addEventListener('scroll', this._handleScroll)
  }

  componentDidUpdate() {
    this._setArticleBounding()
    this._sendPageLevelAction()
  }

  componentWillMount() {
    const { params, selectedArticle } = this.props
    let slug = _.get(params, 'slug')

    // Check if selectedArticle is up to date
    if (_.get(selectedArticle, 'slug') !== slug) {
      // fetch data we need to render the whole article page
      this._fetchData()
    }
  }

  componentWillReceiveProps(nextProps) {
    const { params, selectedArticle } = nextProps
    const slug = _.get(params, 'slug')

    // Check if selectedArticle is up to date
    if (selectedArticle.slug !== slug) {
      // fetch data we need to render the whole article page
      this._fetchData()
    }
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this._setArticleBounding)
    window.removeEventListener('scroll', this._handleScroll)
  }

  _sendPageLevelAction() {
    const { entities, selectedArticle, setArticleTopicList, setPageTitle } = this.props

    let article = _.get(entities, [ 'articles', selectedArticle.id ], {})
    let topicName = _.get(entities, [ 'topics', _.get(article, 'topics'), 'name' ])

    // set navbar title for this article
    setPageTitle(article.id, article.title, topicName)

    let topicArr = this._getTopicArticles(_.get(article, 'topics'))
    // dispatch action for the navbar to display article list
    setArticleTopicList(topicArr)
  }

  // fetch article whole data, including body, related articls and other articles in the same topic
  _fetchData() {
    const { entities, fetchArticleIfNeeded, fetchArticlesByUuidIfNeeded, fetchRelatedArticlesIfNeeded, params, slugToId } = this.props
    let slug = _.get(params, 'slug')

    // fetch article
    fetchArticleIfNeeded(slug)

    let article = _.get(entities, [ 'articles', slugToId[slug] ])
    let topicId = _.get(article, 'topics')
    let relateds = _.get(article, 'relateds')

    //  fetch other articles in the same topic
    fetchArticlesByUuidIfNeeded(topicId, TOPIC)

    // fetch related articles
    fetchRelatedArticlesIfNeeded(_.get(article, 'id'), relateds)
  }

  _getCumulativeOffset(element) {
    let top = 0
    do {
      top += element.offsetTop  || 0
      element = element.offsetParent
    } while(element)

    return top
  }

  _setArticleBounding() {
    const beginEl = ReactDOM.findDOMNode(this.refs.progressBegin)
    const endEl = ReactDOM.findDOMNode(this.refs.progressEnding)
    articlePostition.beginY = _.get(beginEl, 'offsetTop', articlePostition.beginY)
    articlePostition.endY = _.get(endEl, 'offsetTop', articlePostition.endY)
  }

  _handleScroll() {
    const { beginY, endY, percent } = articlePostition
    let scrollRatio = Math.abs((window.scrollY-beginY) / (endY-beginY))
    if(window.scrollY < beginY) {
      scrollRatio = 0
    } else if (scrollRatio > 1) {
      scrollRatio = 1
    }
    let curPercent = Math.round(scrollRatio*100)
    if(percent!== curPercent) {
      articlePostition.percent = curPercent
      // update the header progress bar
      this.props.setReadProgress(curPercent)
    }
  }

  _composeAuthors(article) {
    article = article || {}
    let authors = []
    const list = [ 'writters', 'photographers', 'designers', 'engineers' ]
    list.forEach((item) => {
      if (Array.isArray(article[item])) {
        article[item].forEach((author) => {
          // remove 's'. writters -> writter
          let type = item.slice(0, -1)
          authors.push(_.merge({}, author, { type: type }))
        })
      }
    })
    return authors
  }

  _getTopicArticles(topicId) {
    const { articlesByUuids, entities } = this.props
    let articleIds = _.get(articlesByUuids, [ topicId, 'items' ], [])
    return _.map(articleIds, (id) => _.merge({}, _.get(entities, [ 'articles', id ])))
  }

  render() {
    const { entities, params, selectedArticle } = this.props
    const isFetching = _.get(selectedArticle, 'isFetching')

    if (_.get(selectedArticle, 'slug') !== _.get(params, 'slug')) {
      return null
    }

    let article = denormalizeArticles(_.get(selectedArticle, 'id'), entities)[0] || {}
    let topicArr = this._getTopicArticles(_.get(article, 'topics.id'))
    let topicName = _.get(article, 'topics.name')
    let relatedArticles = _.get(article, 'relateds')
    let authors = this._composeAuthors(article)
    let bodyData = _.get(article, [ 'content', 'apiData' ], [])
    let heroImage = _.get(article, [ 'heroImage' ], null)
    let heroImageSize = _.get(article, [ 'heroImageSize' ], 'normal')
    let introData = _.get(article, [ 'brief', 'apiData' ], [])
    let copyright = _.get(article, [ 'copyright' ], [])
    const cUrl = getAbsPath(this.context.location.pathname, this.context.location.search)

    let topicBox = topicName ?
{topicName}
 : null
    const meta = {
      title: _.get(article, [ 'title' ], '報導者'),
      description: _.get(article, [ 'ogDescription' ], ''),
      canonical: 'https://www.twreporter.org/a/' + _.get(article, [ 'slug' ], []),
      meta: { property: {} },
      auto: { ograph: true }
    }

    if (_.get(heroImage, [ 'image', 'url' ])) {
      _.set(meta, [ 'meta', 'property', 'og:image' ], _.get(heroImage, [ 'image', 'url' ]))
    }

    return (
      <DocumentMeta {...meta}>

          {isFetching ?
<ArticlePlaceholder />
 :

              <hgroup>
                {topicBox}

{article.title}

              </hgroup>

              <ArticleComponents.HeadingAuthor
                authors={authors}
                extendByline={_.get(article, 'extendByline')}
              >
                <ArticleComponents.PublishDate
                  date={article.publishedDate}
                />
              </ArticleComponents.HeadingAuthor>
              <ArticleComponents.ShareBt
                appId={appId}
                url={cUrl}
                title={article.title}
                fbIcon={fbIcon}
                twitterIcon={twitterIcon}
                lineIcon={lineIcon}
              />

              <ArticleComponents.LeadingImage
                size={heroImageSize}
                image={_.get(heroImage, [ 'image', 'resizedTargets' ])}
                id={_.get(heroImage, 'id')}
                description={_.get(heroImage, 'description' )}
              />

              <ArticleComponents.Introduction
                data={introData}
              />

            <ArticleComponents.Body
              data={bodyData}
            />

                <ArticleComponents.BottomTags
                  data={article.tags}
                />

              <ArticleComponents.BottomRelateds
                relateds={relatedArticles}
                currentId={article.id}
                topicName={topicName}
                topicArr={topicArr}
              />

          }
          {/*<ArticleComponents.PageNavigation
            article={ _.get(article, [ 'relateds', 0 ])}
            navigate="next"
          />
          <ArticleComponents.PageNavigation
            article={_.get(article, [ 'relateds', 1 ])}
            navigate="previous"
          />*/}

      </DocumentMeta>
    )
  }
}

function mapStateToProps(state) {
  return {
    articlesByUuids: state.articlesByUuids,
    entities: state.entities,
    selectedArticle: state.selectedArticle,
    slugToId: state.slugToId
  }
}

Article.contextTypes = {
  device: React.PropTypes.string,
  location: React.PropTypes.object
}

export { Article }
export default connect(mapStateToProps, { fetchArticleIfNeeded, fetchRelatedArticlesIfNeeded,
  fetchArticlesByUuidIfNeeded, setReadProgress, setPageType, setPageTitle, setArticleTopicList })(Article)
<|endoftext|>