text:
<!DOCTYPE html>

  <meta charset="utf-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="HandheldFriendly" content="true" />
  <link rel="shortcut icon" href="https://www.epa.gov/sites/all/themes/epa/favicon.ico" type="image/vnd.microsoft.icon" />
  <meta name="MobileOptimized" content="width" />
  <meta http-equiv="cleartype" content="on" />
  <meta http-equiv="ImageToolbar" content="false" />
  <meta name="viewport" content="width=device-width" />
  <meta name="version" content="20161218" />

  <meta name="DC.description" content="" />
  <meta name="DC.title" content="" />
  <title>
  Environmentally Benign Synthesis of Resorcinol from Glucose|

  Research Project Database | Grantee Research Project | ORD | US EPA</title>

  <meta name="keywords" content="" />
  <link rel="shortlink" href="" />
  <link rel="canonical" href="" />
  <meta name="DC.creator" content="" />
  <meta name="DC.language" content="en" />
  <meta name="DC.Subject.epachannel" content="" />
  <meta name="DC.type" content="" />
  <meta name="DC.date.created" content="" />
  <meta name="DC.date.modified" content="2017-01-26" />

  <link type="text/css" rel="stylesheet" href="https://www.epa.gov/misc/ui/jquery.ui.autocomplete.css" media="all" />
  <link type="text/css" rel="stylesheet" href="https://www.epa.gov/sites/all/themes/epa/css/lib/jquery.ui.theme.css" media="all" />
  <link type="text/css" rel="stylesheet" href="https://www.epa.gov/sites/all/libraries/template2/s.css" media="all" />

	<link rel="alternate" type="application/atom+xml" title="EPA.gov All Press Releases" href="https://www.epa.gov/newsreleases/search/rss" />
	<link rel="alternate" type="application/atom+xml" title="EPA.gov Headquarters Press Releases" href="https://www.epa.gov/newsreleases/search/rss/field_press_office/headquarters" />
	<link rel="alternate" type="application/atom+xml" title="Greenversations, EPA's Blog" href="https://blog.epa.gov/blog/feed/" />

Jump to main content

  <hgroup class="site-name-and-slogan">

US EPA

United States Environmental Protection Agency

  </hgroup>
  <form class="epa-search" method="get" action="https://search.epa.gov/epasearch/epasearch">
    Search
    <input class="form-text" placeholder="Search EPA.gov" name="querytext" id="search-box" value=""/>
    <button class="epa-search-button" id="search-button" type="submit" title="Search">Search</button>
    <input type="hidden" name="fld" value="" />
    <input type="hidden" name="areaname" value="" />
    <input type="hidden" name="areacontacts" value="" />
    <input type="hidden" name="areasearchurl" value="" />
    <input type="hidden" name="typeofsearch" value="epa" />
    <input type="hidden" name="result_template" value="2col.ftl" />
    <input type="hidden" name="filter" value="sample4filt.hts" />
  </form>

Contact Us

Project Research Results

Final Report

Related Information

Research Grants

P3: Student Design Competition

Research Fellowships

Small Business Innovation Research (SBIR)

Grantee Research Project Results Search

      Environmentally Benign Synthesis of Resorcinol from Glucose

    EPA Grant Number: R826116

    Title: Environmentally Benign Synthesis of Resorcinol from Glucose

    Investigators:
     Frost, John W.

    Institution:

      Michigan State University

    	EPA Project Officer:

           Richards, April

      Project Period:
      November 1, 1997 through
        October 31, 2000

        Project Amount:

          $337,202

      RFA:
      Technology for a Sustainable Environment (1997)

        		RFA Text |
          Recipients Lists

      Research Category:

          Sustainability
          ,
          Pollution Prevention/Sustainable Development

Description:

      	Resorcinol is a widely used chemical building block globally produced at volumes
of 3.0-3.5 x 107 kg/yr. Demand for resorcinol ranges from its formulation with
formaldehyde to produce wood adhesives and tackifiers in the manufacture of
steel tires to its use in the synthesis of fine chemicals ranging from UV
blockers to the active ingredient in Sucrets. New, environmentally benign routes
are proposed for the synthesis of resorcinol which share the common feature of
employing microbial biocatalysis and use of glucose as a starting material.

Current resorcinol manufacture employs benzene as a starting material.
Benzene is carcinogenic, volatile, and is obtained from nonrenewable petroleum
feedstocks. All of resorcinol's carbon atoms in the proposed syntheses will be
derived from the carbon atoms of glucose. In addition to being nontoxic and
nonvolatile, glucose can be derived from the renewable starch and cellulose
content of plants cultivated on an enormous scale in the U.S. Resorcinol's
oxygen atoms will also be derived from the oxygen atoms of glucose. Use of a
starting material which already contains what will become the two oxygen atoms
of resorcinol avoids high-temperature fusion with caustic lye, high-salt
effluent streams, and explosive intermediates which are associated with
chemically forcing oxygen atoms into the aromatic ring of benzene.

By taking advantage of the diversity of aromatic-biosynthesizing pathways and
enzymes found in nature, the spectrum of chemicals synthesized by
environmentally benign routes from renewable feedstocks can be greatly expanded.
Proposed research is distinguished by the fact that polyketide biosynthesis and
fatty acid biosynthesis will be the pathways chosen for converting glucose into
resorcinol. Previous efforts to replace benzene with glucose as a starting
material in chemical manufacture have employed the common pathway of aromatic
amino acid biosynthesis (the shikimate pathway) as the biocatalytic route for
synthesis of key intermediates or the final chemical product.

The primary objective of the proposed research is to establish the basic
route(s) by which resorcinol can be synthesized from glucose. Fatty acid
biosynthesis and polyketide biosynthesis will be modified so that triacetic acid
lactone (TAL) or 3-hydroxy-5-ketohexanoic acid (HKH) accumulates in microbial
culture supernatants. Abiotic, chemical methodology will then be used to
catalytically convert the microbially produced TAL or HKH into resorcinol. To
create a TAL-synthesizing microbe, fatty acid biosynthesis in Escherichii co!i
K-12 will be modified. The gene encoding 6-methylsalicylic acid synthase will
also be mutagenized and then expressed in Streptomyces coelicolor A(3)2 to
create a TAL- or HKH-synthesizing biocatalyst. For the abiotic, chemical
conversion of TAL and HKM into resorcinol, proposed research is to focus on both the ordering of the chemical steps and the reagents needed to catalyze each step.

Supplemental Keywords:

      biocatalysis, resorcinol, glucose, benzene, renewable, triacetic acid lactone., RFA, Scientific Discipline, Toxics, Sustainable Industry/Business, cleaner production/pollution prevention, Environmental Chemistry, Sustainable Environment, HAPS, Technology for Sustainable Environment, Economics and Business, triacetic acid lactone, cleaner production, waste minimization, waste reduction, environmentally conscious manufacturing, microbial biocatalysis, green process systems, UV blockers, Benzene (including benzene from gasoline), pollution prevention, biosynthesis, alternative chemical synthesis, environmentally-friendly chemical synthesis, green chemistry

Progress and Final Reports:

                Final Report

Top of Page

 The perspectives, information and conclusions conveyed in research project abstracts, progress reports, final reports, journal abstracts and journal publications convey the viewpoints of the principal investigator and may not represent the views and policies of ORD and EPA.  Conclusions drawn by the principal investigators have not been reviewed by the Agency.

Main menu

Environmental Topics

Laws & Regulations

About EPA

Discover.

Accessibility

EPA Administrator

Budget & Performance

Contracting

Grants

No FEAR Act Data

Privacy and Security

Connect.

Data.gov

Inspector General

Jobs

Newsroom

Open Government

Regulations.gov

Subscribe

USA.gov

White House

Ask.

Contact Us

Hotlines

FOIA Requests

Frequent Questions

Follow.

Facebook

Twitter

YouTube

Flickr

Instagram

Last updated on Thursday, January 26, 2017


text:
package org.olat.core.util.session;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicInteger;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.olat.core.commons.persistence.DB;
import org.olat.core.gui.control.Disposable;
import org.olat.core.gui.control.Event;
import org.olat.core.helpers.Settings;
import org.olat.core.id.Identity;
import org.olat.core.id.IdentityEnvironment;
import org.olat.core.id.OLATResourceable;
import org.olat.core.id.Roles;
import org.olat.core.id.context.HistoryManager;
import org.olat.core.logging.AssertException;
import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing;
import org.olat.core.logging.activity.CoreLoggingResourceable;
import org.olat.core.logging.activity.OlatLoggingAction;
import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
import org.olat.core.logging.activity.ThreadLocalUserActivityLoggerInstaller;
import org.olat.core.logging.activity.UserActivityLoggerImpl;
import org.olat.core.util.SessionInfo;
import org.olat.core.util.SignOnOffEvent;
import org.olat.core.util.UserSession;
import org.olat.core.util.cache.CacheWrapper;
import org.olat.core.util.coordinate.CoordinatorManager;
import org.olat.core.util.event.GenericEventListener;
import org.olat.core.util.prefs.Preferences;
import org.olat.core.util.resource.OresHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 *
 * Initial date: 15.11.2012<br>
 * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
 *
 */
@Service
public class UserSessionManager implements GenericEventListener {

	private static final OLog log = Tracing.createLoggerFor(UserSessionManager.class);
	private static final String USERSESSIONKEY = UserSession.class.getName();

	public static final OLATResourceable ORES_USERSESSION = OresHelper.createOLATResourceableType(UserSession.class);
	public static final String STORE_KEY_KILLED_EXISTING_SESSION = "killedExistingSession";

  //clusterNOK cache ??
	private static final Set<UserSession> authUserSessions = new HashSet<UserSession>(2500);
	private static final Set<Long> userNameToIdentity = new HashSet<Long>(2500);
	private static final Set<Long> authUsersNamesOtherNodes = new HashSet<Long>(2500);

	private static final AtomicInteger sessionCountWeb = new AtomicInteger();
	private static final AtomicInteger sessionCountRest = new AtomicInteger();
	private static final AtomicInteger sessionCountDav = new AtomicInteger();

	@Autowired
	private DB dbInstance;
	@Autowired
	private UserSessionModule sessionModule;
	@Autowired
	private CoordinatorManager coordinator;
	@Autowired
	private HistoryManager historyManager;

	private CacheWrapper<Long,Integer> userSessionCache;

	@PostConstruct
	public void initBean() {
		coordinator.getCoordinator().getEventBus().registerFor(this, null, ORES_USERSESSION);
		userSessionCache = coordinator.getCoordinator().getCacher().getCache(UserSessionManager.class.getSimpleName(), "usersession");
	}

	/**
	 * @param session
	 * @return associated user session
	 */
	public UserSession getUserSession(HttpSession session) {
		UserSession us;
		synchronized (session) {//o_clusterOK by:fj
			us = (UserSession) session.getAttribute(USERSESSIONKEY);
			if (us == null) {
				us = new UserSession();
				session.setAttribute(USERSESSIONKEY, us); // triggers the
				// valueBoundEvent -> nothing
				// more to do here
			}
		}
		//set a possible changed session timeout interval
		if(us.isAuthenticated()) {
			session.setMaxInactiveInterval(sessionModule.getSessionTimeoutAuthenticated());
		} else {
			session.setMaxInactiveInterval(sessionModule.getSessionTimeout());
		}
		return us;
	}

	/**
	 * @param hreq
	 * @return associated user session
	 */
	public UserSession getUserSession(HttpServletRequest hreq) {
		// get existing or create new session
		HttpSession httpSession = hreq.getSession(true);
		UserSession usess = getUserSession(httpSession);
		return usess;
	}

	/**
	 * Return the UserSession of the given request if it is already set or null otherwise
	 * @param hreq
	 * @return
	 */
	public UserSession getUserSessionIfAlreadySet(HttpServletRequest hreq) {
		HttpSession session = hreq.getSession(false);
		if (session==null) {
			return null;
		}

		synchronized (session) {//o_clusterOK by:se
			UserSession us = (UserSession) session.getAttribute(USERSESSIONKEY);
			if(us != null && us.isAuthenticated()) {
				session.setMaxInactiveInterval(sessionModule.getSessionTimeoutAuthenticated());
			} else {
				session.setMaxInactiveInterval(sessionModule.getSessionTimeout());
			}
			return us;
		}
	}

  /**
 * @param userName
 * @return the identity or null if no user with userName is currently logged
 *         on
 */
	public boolean isSignedOnIdentity(Long identityKey) {
		synchronized (authUserSessions) {  //o_clusterOK by:fj
			return userNameToIdentity.contains(identityKey);
		}
	}

	public List<Long> getAuthenticatedIdentityKey() {
		synchronized (authUserSessions) {  //o_clusterOK by:fj
			return new ArrayList<Long>(userNameToIdentity);
		}
	}

	/**
	 * @return set of authenticated active user sessions
	 */
	public Set<UserSession> getAuthenticatedUserSessions() {
		Set<UserSession> copy;
		synchronized (authUserSessions) {  //o_clusterOK by:fj
			copy = new HashSet<UserSession>(authUserSessions);
		}
		return copy;
	}

	public int getNumberOfAuthenticatedUserSessions() {
		synchronized(authUserSessions) {
			return authUserSessions.size();
		}
	}

	/**
	 * @return Returns the userSessionsCnt (Web, WebDAV, REST) from this VM
	 */
	public int getUserSessionsCnt() {
	  //clusterNOK ?? return only number of locale sessions ?
		synchronized(authUserSessions) {
			return authUserSessions.size();
		}
	}

	/**
	 * @return The number of users currently logged in using the web interface
	 *         (guests and authenticated users).
	 */
	public int getUserSessionWebCounter() {
		return userSessionCache.size();
	}

	public Collection<Long> getUsersOnline() {
		return userSessionCache.getKeys();
	}

	public boolean isOnline(Long identityKey) {
		return userSessionCache.containsKey(identityKey);
	}

	/**
	 * @return The number of users currently logged in using a WebDAV client.
	 *         Note that currently this only returns the users from this VM as
	 *         the synchronization of user between cluster node is not
	 *         correctly. In the long run we return all users here.
	 */
	public int getUserSessionDavCounter() {
		// clusterNOK ?? return only number of locale sessions ?
		return sessionCountDav.get();
	}

	/**
	 * @return The number of users currently logged in using the REST API. Note
	 *         that currently this only returns the users from this VM as the
	 *         synchronization of user between cluster node is not correctly. In
	 *         the long run we return all users here.
	 */
	public int getUserSessionRestCounter() {
		// clusterNOK ?? return only number of locale sessions ?
		return sessionCountRest.get();
	}

	/**
	 * prior to calling this method, all instance vars must be set.
	 */
	public synchronized void signOn(UserSession usess) {
		//   ^^^^^^^^^^^^ Added synchronized to be symmetric with sign off and to
		//                fix a possible dead-lock see also OLAT-3390

		boolean isDebug = log.isDebug();
		if(isDebug) log.debug("signOn() START");
		if (usess.isAuthenticated()) {
			throw new AssertException("sign on: already signed on!");
		}

		IdentityEnvironment identityEnvironment = usess.getIdentityEnvironment();
		Identity identity = identityEnvironment.getIdentity();
		if (identity == null) {
			throw new AssertException("identity is null in identityEnvironment!");
		}
		SessionInfo sessionInfo = usess.getSessionInfo();
		if (sessionInfo == null) {
			throw new AssertException("sessionInfo was null for identity " + identity);
		}
		//String login = identity.getName();
		usess.setAuthenticated(true);

		if (sessionInfo.isWebDAV()) {
			// load user prefs
			usess.reloadPreferences();
			synchronized (authUserSessions) {  //o_clusterOK by:se
				// we're only adding this webdav session to the authUserSessions - not to the userNameToIdentity.
				// userNameToIdentity is only needed for IM which can't do anything with a webdav session
				authUserSessions.add(usess);
			}
			log.audit("Logged on [via webdav]: " + sessionInfo.toString());
		} else {

			if(isDebug) {
				log.debug("signOn() authUsersNamesOtherNodes.contains "+identity.getName() + ": " + authUsersNamesOtherNodes.contains(identity.getKey()));
			}

			UserSession invalidatedSession = null;
			synchronized (authUserSessions) {  //o_clusterOK by:fj
		    // check if already a session exist for this user
		    if ( (userNameToIdentity.contains(identity.getKey()) || userSessionCache.containsKey(identity.getKey()) )
		         && !sessionInfo.isWebDAV() && !sessionInfo.isREST() && !usess.getRoles().isGuestOnly()) {
		        log.info("Loggin-process II: User has already a session => signOffAndClear existing session");

		        invalidatedSession = getUserSessionForGui(identity.getKey());
		        //remove session to be invalidated
		        //SIDEEFFECT!! to signOffAndClear
		        //if invalidatedSession is removed from authUserSessions
		        //signOffAndClear does not remove the identity.getName().toLowerCase() from the userNameToIdentity
		        //
		        authUserSessions.remove(invalidatedSession);
		    }
		    authUserSessions.add(usess);
				// user can choose upercase letters in identity name, but this has no effect on the
				// database queries, the login form or the IM account. IM works only with lowercase
				// characters -> map stores values as such
				if(isDebug) log.debug("signOn() adding to userNameToIdentity: "+identity.getName().toLowerCase());
				userNameToIdentity.add(identity.getKey());
				userSessionCache.put(identity.getKey(), new Integer(Settings.getNodeId()));
			}

			//reload user prefs
			usess.reloadPreferences();

			log.audit("Logged on: " + sessionInfo.toString());
			CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(new SignOnOffEvent(identity, true), ORES_USERSESSION);

			// THE FOLLOWING CHECK MUST BE PLACED HERE NOT TO PRODUCE A DEAD-LOCK WITH SIGNOFFANDCLEAR
			// check if a session from any browser was invalidated (IE has a cookie set per Browserinstance!!)
			if (invalidatedSession != null || authUsersNamesOtherNodes.contains(identity.getKey())) {
				// put flag killed-existing-session into session-store to show info-message 'only one session for each user' on user-home screen
				usess.putEntry(STORE_KEY_KILLED_EXISTING_SESSION, Boolean.TRUE);
				if(isDebug) log.debug("signOn() removing from authUsersNamesOtherNodes: "+identity.getName());
				authUsersNamesOtherNodes.remove(identity.getKey());
				//OLAT-3381 & OLAT-3382
				if(invalidatedSession != null) {
					signOffAndClear(invalidatedSession);
				}
			}

			if(isDebug) log.debug("signOn() END");
		}

		// update logged in users counters
		if (sessionInfo.isREST()) {
			sessionCountRest.incrementAndGet();
		} else if (sessionInfo.isWebDAV()) {
			sessionCountDav.incrementAndGet();
		} else {
			sessionCountWeb.incrementAndGet();
		}
	}

	/**
	 * called to make sure the current authenticated user (if there is one at all)
	 * is cleared and signed off. This method is firing the SignOnOffEvent Multiuserevent.
	 */
	public void signOffAndClear(UserSession usess) {  //o_clusterOK by:fj
		internSignOffAndClear(usess);
		//commit all changes after sign off, especially commit lock which were
		//deleted by dispose methods
		dbInstance.commit();
	}

	private void internSignOffAndClear(UserSession usess) {
		boolean isDebug = log.isDebug();
		if(isDebug) log.debug("signOffAndClear() START");

		signOffAndClearWithout(usess);
		// handle safely
		try {
			if (usess.isAuthenticated()) {
				SessionInfo sessionInfo = usess.getSessionInfo();
				IdentityEnvironment identityEnvironment = usess.getIdentityEnvironment();
				Identity identity = identityEnvironment.getIdentity();
				log.audit("Logged off: " + sessionInfo);
				CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(new SignOnOffEvent(identity, false), ORES_USERSESSION);
				if(isDebug) log.debug("signOffAndClear() deregistering usersession from eventbus, id="+sessionInfo);
				//fxdiff FXOLAT-231: event on GUI Preferences extern changes
				OLATResourceable ores = OresHelper.createOLATResourceableInstance(Preferences.class, identity.getKey());
				CoordinatorManager.getInstance().getCoordinator().getEventBus().deregisterFor(usess, ores);
			}
		} catch (Exception e) {
			log.error("exception in signOffAndClear: while sending signonoffevent!", e);
		}
		// clear all instance variables, set authenticated to false
		usess.init();
		if(isDebug) log.debug("signOffAndClear() END");
	}

	/**
	 * called from signOffAndClear()
	 * called from event -> MUEvent
	 * the real work to do during sign off but without sending the multiuserevent
	 * this is used in case the user logs in to node1 and was logged in on node2 =>
	 * node2 catches the sign on event and invalidates the user on node2 "silently", e.g.
	 * without firing an event.
	 */
	public void signOffAndClearWithout(final UserSession usess) {
		boolean isDebug = log.isDebug();
		if(isDebug) log.debug("signOffAndClearWithout() START");

		final IdentityEnvironment identityEnvironment = usess.getIdentityEnvironment();
		final SessionInfo sessionInfo = usess.getSessionInfo();
		final Identity ident = identityEnvironment.getIdentity();
		if (isDebug) log.debug("UserSession:::logging off: " + sessionInfo);

		//fxdiff BAKS-7 Resume function
		if(usess.isAuthenticated() && usess.getLastHistoryPoint() != null && !usess.getRoles().isGuestOnly()) {
			historyManager.persistHistoryPoint(ident, usess.getLastHistoryPoint());
		}

		/**
		 * use not RunnableWithException, as exceptionHandlng is inside the run
		 */
		Runnable run = new Runnable() {
			public void run() {
				Object obj = null;
				try {
					// do logging
					if (ident != null) {
						ThreadLocalUserActivityLogger.log(OlatLoggingAction.OLAT_LOGOUT, UserSession.class, CoreLoggingResourceable.wrap(ident));
					} else {
						//System.out.println("identity is null!!!!!!!!!!!!!!!!!!!!!");
					}
					// notify all variables in the store (the values) about the disposal
					// if
					// Disposable
					List<Object> storeList = usess.getStoreValues();

					for (Iterator<Object> it_storevals = storeList.iterator(); it_storevals.hasNext();) {
						obj = it_storevals.next();
						if (obj instanceof Disposable) {
							// synchronous, since triggered by tomcat session timeout or user
							// click and
							// asynchronous, if kicked out by administrator.
							// we assume synchronous
							// !!!!
							// As a reminder, this .dispose() calls dispose on
							// DefaultController which is synchronized.
							// (Windows/WindowManagerImpl/WindowBackOfficeImpl/BaseChiefController/../
							// dispose()
							// !!!! was important for bug OLAT-3390

							((Disposable) obj).dispose();
						}
					}
				} catch (Exception e) {

					String objtostr = "n/a";
					try {
						objtostr = obj.toString();
					} catch (Exception ee) {
						// ignore
					}
					log.error("exception in signOffAndClear: while disposing object:" + objtostr, e);
				}
			}
		};

		ThreadLocalUserActivityLoggerInstaller.runWithUserActivityLogger(run, UserActivityLoggerImpl.newLoggerForValueUnbound(usess));

		synchronized (authUserSessions) {  //o_clusterOK by:fj
			if(authUserSessions.remove(usess)){
				//remove only from identityEnvironment if found in sessions.
				//see also SIDEEFFECT!! line in signOn(..)
				Identity previousSignedOn = identityEnvironment.getIdentity();
				if (previousSignedOn != null) {
					if(isDebug) log.debug("signOffAndClearWithout() removing from userNameToIdentity: "+previousSignedOn.getName().toLowerCase());
					userNameToIdentity.remove(previousSignedOn.getKey());
					userSessionCache.remove(previousSignedOn.getKey());
				}
			} else if (isDebug) {
				log.info("UserSession already removed! for ["+ident+"]");
			}
		}
		// update logged in users counters
		if (sessionInfo != null) {
			if (sessionInfo.isREST()) {
				sessionCountRest.decrementAndGet();
			} else if (sessionInfo.isWebDAV()) {
				sessionCountDav.decrementAndGet();
			} else {
				sessionCountWeb.decrementAndGet();
			}
		}

		if (isDebug) log.debug("signOffAndClearWithout() END");
	}

	/**
	 * only for SignOffEvents
	 * - Usersession keeps book about usernames
	 * - WindowManager responsible to dispose controller chain
	 * @see org.olat.core.util.event.GenericEventListener#event(org.olat.core.gui.control.Event)
	 */
	public void event(Event event) {
		if(event instanceof SignOnOffEvent) {
			SignOnOffEvent se = (SignOnOffEvent) event;
			processSignOnOffEvent(se);
		}
	}

	private void processSignOnOffEvent(SignOnOffEvent se) {
		try {
			boolean debug = log.isDebug();
			if(debug) log.debug("event() START");
			if(debug) log.debug("event() is SignOnOffEvent. isSignOn="+se.isSignOn());
			if (!se.isEventOnThisNode()) {
				// - signOnOff from other node
				// - Single OLAT Instance is never passing by here.
				if (se.isSignOn()) {
					// it is a logged on event
					// -> remember other nodes logged usernames
					if(debug) log.debug("event() adding to authUsersNamesOtherNodes: "+se.getIdentityKey());
					authUsersNamesOtherNodes.add(se.getIdentityKey());
					UserSession usess = getUserSessionForGui(se.getIdentityKey());
					if (usess != null && usess.getSessionInfo() != null && se.getIdentityKey().equals(usess.getSessionInfo().getIdentityKey())
							&& !usess.getSessionInfo().isWebDAV() && !usess.getRoles().isGuestOnly()) {

						// if this listening UserSession instance is from the same user
						// and it is not a WebDAV Session, and it is not GuestSession
						// => log user off on this node
						signOffAndClearWithout(usess);
						usess.init();
					}
				} else {
					// it is logged off event
					// -> remove from other nodes logged on list.
					if(debug) log.debug("event() removing from authUsersNamesOtherNodes: "+se.getIdentityKey());
					authUsersNamesOtherNodes.remove(se.getIdentityKey());
				}
			}
			if(debug) log.debug("event() END");
		} catch (Exception e) {
			log.error("", e);
		}
	}

	/**
	 * Invalidate all sessions except admin-sessions.
	 * @return  Number of invalidated sessions.
	 */
	public int invalidateAllSessions() {
		log.debug("invalidateAllSessions() START");
		int invalidateCounter = 0;
		log.audit("All sessions were invalidated by an administrator");
		//clusterNOK ?? invalidate only locale sessions ?
		Set<UserSession> iterCopy = getAuthenticatedUserSessions();
		for (Iterator<UserSession> iterator = iterCopy.iterator(); iterator.hasNext();) {
			UserSession userSession = iterator.next();
			Roles userRoles = userSession != null ? userSession.getRoles() : null;
			if (userRoles != null && !userRoles.isOLATAdmin()) {
				//do not logout administrators
				try {
					internSignOffAndClear(userSession);
					if(userSession.getSessionInfo() != null && userSession.getSessionInfo().getSession() != null) {
						userSession.getSessionInfo().getSession().invalidate();
					}
					invalidateCounter++;
				} catch(Exception ex) {
					// Session already signed off => do nothing and continues
				}
			}
		}
		log.debug("invalidateAllSessions() END");
		return invalidateCounter;
	}

	/**
	 * Invalidate a given number of oldest (last-click-time) sessions except admin-sessions.
	 * @param nbrSessions  number of sessions whisch will be invalidated
	 * @return  Number of invalidated sessions.
	 */
	public int invalidateOldestSessions(int nbrSessions) {
		int invalidateCounter = 0;
		// 1. Copy authUserSessions in sorted TreeMap
		// This is the Comparator that will be used to sort the TreeSet:
		Comparator<UserSession> sessionComparator = new Comparator<UserSession>() {
			public int compare(UserSession o1, UserSession o2) {
				Long long1 = new Long((o1).getSessionInfo().getLastClickTime());
				Long long2 = new Long((o2).getSessionInfo().getLastClickTime());
				return long1.compareTo(long2);
			}
		};
		// clusterNOK ?? invalidate only locale sessions ?
		TreeSet<UserSession> sortedSet = new TreeSet<UserSession>(sessionComparator);
		sortedSet.addAll(authUserSessions);
		int i = 0;
		for (Iterator<UserSession> iterator = sortedSet.iterator(); iterator.hasNext() && i++<nbrSessions;) {
			try {
				UserSession userSession = (UserSession) iterator.next();
				if (!userSession.getRoles().isOLATAdmin() && !userSession.getSessionInfo().isWebDAV()) {
					internSignOffAndClear(userSession);
					invalidateCounter++;
				}
			} catch (Throwable th) {
				log.warn("Error signOffAndClear ", th);
			}
		}
		return invalidateCounter;
	}

	/**
	 * set session timeout on http session -
	 * @param sessionTimeoutInSec
	 */
	public void setGlobalSessionTimeout(int sessionTimeoutInSec) {
		Collection<UserSession> sessionSnapShot = getAuthenticatedUserSessions();
		for (UserSession session : sessionSnapShot) {
			try{
				SessionInfo sessionInfo = session.getSessionInfo();
				if(sessionInfo != null && sessionInfo.getSession() != null) {
					sessionInfo.getSession().setMaxInactiveInterval(sessionTimeoutInSec);
				}
			} catch(Throwable th){
				log.error("error setting sesssionTimeout", th);
			}
		}
	}

	/**
	 * Lookup non-webdav, non-REST UserSession for username.
	 * @param identityKey
	 * @return user-session or null when no session was founded.
	 */
	private UserSession getUserSessionForGui(Long identityKey) {
		if(identityKey != null) {
			//do not call from somewhere else then signOffAndClear!!
			Collection<UserSession> authUserSessionsCopy = getAuthenticatedUserSessions();
			for (UserSession userSession : authUserSessionsCopy) {
				Identity identity = userSession.getIdentity();
				if (identity != null && identityKey.equals(identity.getKey())
						&& userSession.getSessionInfo() != null
						&& !userSession.getSessionInfo().isWebDAV()
						&& !userSession.getSessionInfo().isREST()) {
					return userSession;
				}
			}
		}
		return null;
	}
}

redpajama_set_name: RedPajamaGithub


text:
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using AutoMapper;
using AutoMapper.EquivalencyExpression;
using HtmlAgilityPack;
using MangaReader.Core.Account;
using MangaReader.Core.DataTrasferObject;
using MangaReader.Core.Manga;
using MangaReader.Core.Services;
using MangaReader.Core.Services.Config;

namespace MangaReader.Core
{
  public abstract class BaseSiteParser : ISiteParser
  {
    protected static ConcurrentDictionary<Type, IMapper> Mappers = new ConcurrentDictionary<Type, IMapper>();

    public abstract Task UpdateNameAndStatus(IManga manga);

    public virtual Task UpdateContentType(IManga manga)
    {
      // Content type can be not changed.
      return Task.CompletedTask;
    }

    public abstract Task UpdateContent(IManga manga);

    public abstract Task UpdatePages(Chapter chapter);

    public abstract UriParseResult ParseUri(Uri uri);

    protected static void UpdateName(IManga manga, string newName)
    {
      if (string.IsNullOrWhiteSpace(newName))
        Log.AddFormat("Не удалось получить имя манги, текущее название - '{0}'.", manga.ServerName);
      else if (newName != manga.ServerName)
        manga.ServerName = newName;
    }

    /// <summary>
    /// Обновляем старые и добавляем новые главы.
    /// </summary>
    /// <param name="manga">Манга.</param>
    /// <param name="chapters">Главы.</param>
    protected void FillMangaChapters(IManga manga, ICollection<ChapterDto> chapters)
    {
      if (!chapters.Any())
        return;

      GetMapper().Map(chapters, manga.Chapters);
      foreach (var chapter in manga.Chapters)
      {
        chapter.Manga = manga;
        foreach (var page in chapter.Container)
        {
          page.Chapter = chapter;
        }
      }
    }

    /// <summary>
    /// Обновляем старые и добавляем новые главы и тома.
    /// </summary>
    /// <param name="manga">Манга.</param>
    /// <param name="volumes">Тома.</param>
    /// <remarks>Перенос главы из тома в том видимо не ловим.</remarks>
    protected void FillMangaVolumes(IManga manga, ICollection<VolumeDto> volumes)
    {
      if (!volumes.Any())
        return;

      GetMapper().Map(volumes, manga.Volumes);
      foreach (var volume in manga.Volumes)
      {
        volume.Manga = manga;
        foreach (var chapter in volume.Container)
        {
          chapter.Volume = volume;
          foreach (var page in chapter.Container)
          {
            page.Chapter = chapter;
          }
        }
      }
    }

    /// <summary>
    /// Обновляем страницы.
    /// </summary>
    /// <param name="manga">Манга.</param>
    /// <param name="pages">Страницы.</param>
    protected void FillMangaPages(IManga manga, ICollection<MangaPageDto> pages)
    {
      if (!pages.Any())
        return;

      GetMapper().Map(pages, manga.Pages);
      foreach (var page in manga.Pages)
      {
        page.Manga = manga;
      }
    }

    public abstract Task<IEnumerable<byte[]>> GetPreviews(IManga manga);

    public virtual IAsyncEnumerable<IManga> Search(string name)
    {
      var hosts = ConfigStorage.Plugins
        .Where(p => p.GetParser().GetType() == this.GetType())
        .Select(p => p.GetSettings().MainUri);
      return hosts.SelectAsync(async host => await GetMangaNodes(name, host).ConfigureAwait(false))
        .Where(nc => nc.Nodes != null)
        .SelectMany(n => n.Nodes.SelectAsync(node => GetMangaFromNode(n.Uri, n.CookieClient, node)))
        .Where(m => m != null);
    }

    protected abstract Task<(HtmlNodeCollection Nodes, Uri Uri, ISiteHttpClient CookieClient)> GetMangaNodes(string name, Uri host);

    protected abstract Task<IManga> GetMangaFromNode(Uri host, ISiteHttpClient client, HtmlNode manga);

    public abstract IMapper GetMapper();
  }
}


text:
define([
	'jquery',
	'underscore',
	'backbone',
	'marionette',
	'tablesorter',
	'text!templates/projects/review/review-projects-list/review-projects-list.tpl',
	'scripts/views/widgets/lists/sortable-table-list-view',
	'scripts/views/projects/review/review-projects-list/review-projects-list-item-view'
], function($, _, Backbone, Marionette, TableSorter, Template, SortableTableListView, ReviewProjectsListItemView) {
	return SortableTableListView.extend({

		//
		// attributes
		//

		childView: ReviewProjectsListItemView,

		sorting: {

			// disable sorting on delete column
			//
			headers: {
				4: {
					sorter: false
				}
			},

			// sort on date column in descending order
			//
			sortList: [[2, 1]]
		},

		//
		// rendering methods
		//

		template: function(data) {
			return _.template(Template, _.extend(data, {
				collection: this.collection,
				showNumbering: this.options.showNumbering
			}));
		},

		childViewOptions: function(model, index) {
			return {
				index: index,
				collection: this.collection,
				showDeactivatedProjects: this.options.showDeactivatedProjects,
				showNumbering: this.options.showNumbering,
				parent: this
			}
		},

		onRender: function() {

			// remove broken rows and shout out the indicies
			//
			this.$el.find('table').find('tbody tr').each(
				function(index){
					if ($(this).children().length === 0) {
						console.log( index );
						$(this).remove();
					}
				}
			);

			// call superclass method
			//
			SortableTableListView.prototype.onRender.call(this);
		}
	});
});


text:
module.exports = exports = function(app){

	// ** Params ** //
	// 2.1 to show simple params ( url : /api/param/simple/paramvalue )
	app.route({
		url: '/api/param/simple/@param',
		id: 'param.simple',
		methods: {
			default: function (req, res, next) {
				res.serve(req.route.params.param)
				return next()
			}
		}
	})

	// 2.2 to show multiparams ( url : /api/param/multi/params/go/here )
	app.route({
		url: '/api/param/multi/...params',
		methods: {
			default: function (req, res, next) {
				res.serve(req.route.params.params)
				return next()
			}
		}
	})

}


text:
namespace uLocate.UI.WebApi
{
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Web.Http;

    using AutoMapper;

    using Umbraco.Core.Models;
    using Umbraco.Core.PropertyEditors;
    using Umbraco.Web.Models.ContentEditing;
    using Umbraco.Web.WebApi;

    [Umbraco.Web.Mvc.PluginController("uLocate")]
    public class DataTypeApiController : UmbracoAuthorizedApiController
    {
        //private LocationService locationService = new LocationService();
        //private LocationTypeService locationTypeService = new LocationTypeService();

        ///// /umbraco/backoffice/uLocate/DataTypeApi/Test
        //[System.Web.Http.AcceptVerbs("GET")]
        //public bool Test()
        //{
        //    return true;
        //}

        /// <summary>
        /// Gets all the DataTypes in this umbraco install.
        /// /umbraco/backoffice/uLocate/DataTypeApi/GetAllDataTypesWithGuids
        /// </summary>
        /// <returns>IEnumerable of GUID & DataType Name</returns>
        public object GetAllDataTypesWithGuids()
        {
            var dataTypes = this.Services.DataTypeService.GetAllDataTypeDefinitions();
            return dataTypes.Select(t => new { guid = t.Key, name = t.Name });
        }

        /// <summary>
        /// Get all uLocate Allowed DataTypes in this Umbraco install (based on the uLocate configuration)
        /// /umbraco/backoffice/uLocate/DataTypeApi/GetAllAvailable
        /// </summary>
        /// <returns>
        /// A <see cref="Dictionary"/> of DataTyp.
        /// </returns>
        [System.Web.Http.AcceptVerbs("GET")]
        public Dictionary<int, string> GetAllAvailable()
        {
            return Data.Helper.GetAllAllowedDataTypes();
        }

        /// <summary>
        /// Get information about a DatatYpe by its name.
        /// /umbraco/backoffice/uLocate/DataTypeApi/GetByName?name=xxx
        /// </summary>
        /// <param name="name">
        /// The name to lookup
        /// </param>
        /// <returns>
        /// An object of type <see cref="DataTypeDisplay"/> or an error.
        /// </returns>
        [System.Web.Http.AcceptVerbs("GET")]
        public object GetByName(string name)
        {
            var all = this.Services.DataTypeService.GetAllDataTypeDefinitions().ToList();
            var dataType = all.FirstOrDefault(x => x.Name == name);
            return this.FormatDataType(dataType);
        }

        //public object GetByKey(string key)
        //{

        //}

        /// <summary>
        /// The format data type.
        /// </summary>
        /// <param name="dtd">
        /// The dtd.
        /// </param>
        /// <returns>
        /// The <see cref="object"/>.
        /// </returns>
        /// <exception cref="HttpResponseException">
        /// </exception>
        protected object FormatDataType(IDataTypeDefinition dtd)
        {
            if (dtd == null)
            {
                throw new HttpResponseException(HttpStatusCode.NotFound);
            }

            var dataTypeDisplay = Mapper.Map<IDataTypeDefinition, DataTypeDisplay>(dtd);
            var propEditor = PropertyEditorResolver.Current.GetByAlias(dtd.PropertyEditorAlias);

            var configDictionairy = new Dictionary<string, object>();

            foreach (var pv in dataTypeDisplay.PreValues)
            {
                configDictionairy.Add(pv.Key, pv.Value);
            }

            return new
            {
                guid = dtd.Key,
                propertyEditorAlias = dtd.PropertyEditorAlias,
                config = configDictionairy,
                view = propEditor.ValueEditor.View
            };
        }

    }
}


text:
import pandas as pd

def test_run():
	#Define date range
	start_date = '2010-01-22'
	start_date = '2010-01-26'
	dates = pd.date_range(start_date, end_date)

	#Create an empty dataframe
	df1 = pd.DataFrame(index = dates)

	#Read SPY data into temporary dataframe
	dfSPY = pd.read_csv("data/SPY.csv", index_col = "Date",
	                    parse_dates = True, usecols = ['Date', 'Adj Close'], na_values = ['nan'])

	#Join the two dataframes using DataFrame.join(), with how='inner'
	df1 = df1.join(dfSPY, how = 'inner')

	#Read in more stocks
	symbols = ['GOOG', 'IBM', 'GLD']
	for symbol in symbols:
		df_temp = pd.read_csv("data/{}.csv".format(symbol), index_col = "Date",
		parse_dates = True, usecols = ['Dates', 'Adj Close'],
		na_values = ['nan'])

		# Rename to prevent clash
		df_temp = df_temp.rename(columns={'Adj Close' : symbol})

		# Use default how='left'
		df = df1.join(df_temp)

	print df1


text:
package com.zoowii.jpa_utils.jdbcorm.sqlmapper;

import com.zoowii.jpa_utils.core.IWrappedQuery;
import com.zoowii.jpa_utils.jdbcorm.ModelMeta;
import com.zoowii.jpa_utils.query.Expr;
import com.zoowii.jpa_utils.query.ParameterBindings;
import com.zoowii.jpa_utils.util.StringUtil;
import org.apache.commons.lang3.tuple.Pair;

import java.util.List;

/**
 * Created by zoowii on 15/1/29.
 */
public class ORMSqlMapper extends SqlMapper {
    @Override
    public String getOfInteger() {
        return "int";
    }

    @Override
    public String getOfLong() {
        return "bigint";
    }

    @Override
    public String getOfFloat() {
        return "float";
    }

    @Override
    public String getOfDouble() {
        return "double";
    }

    @Override
    public String getOfString() {
        return "varchar(255)";
    }

    @Override
    public String getOfBoolean() {
        return "int";
    }

    @Override
    public String getOfString(int length) {
        return String.format("varchar(%d)", length);
    }

    @Override
    public String getOfText(boolean isLob) {
        return "text";
    }

    @Override
    public String getOfBytes(boolean isLob) {
        return "blob";
    }

    @Override
    public String getOfDate() {
        return "date";
    }

    @Override
    public String getOfDateTime() {
        return "datetime";
    }

    @Override
    public String getOfTimestamp() {
        return "timestamp";
    }

    @Override
    public Pair<String, String> getFromSubSql(ModelMeta modelMeta, boolean useAlias, String alias) {
        if(useAlias && (alias == null || alias.isEmpty())) {
            alias = String.format("%s_%s", modelMeta.getModelCls().getSimpleName(), incrementCircleNumber.getAndIncrement() + "");
        }
        String tableAlias = useAlias ?  alias: null;
        String fromSql = useAlias ? String.format(" FROM %s %s ", modelMeta.getModelCls().getSimpleName(), tableAlias) : String.format(" FROM %s ", modelMeta.getModelCls().getSimpleName());
        return Pair.of(fromSql, tableAlias);
    }

    @Override
    public Pair<String, String> getNewParameterVar(ParameterBindings parameterBindings, String key, Object value) {
        String var = "?";
        parameterBindings.addIndexBinding(value);
        return Pair.of(key, var);
    }

    @Override
    public String wrapQueryWithDefaultSelect(ModelMeta modelMeta, String sql) {
        return sql;
    }

    @Override
    public IWrappedQuery limit(IWrappedQuery query, ParameterBindings parameterBindings, int limit) {
        return query;
    }

    @Override
    public IWrappedQuery offset(IWrappedQuery query, ParameterBindings parameterBindings, int offset) {
        return query;
    }

    @Override
    public String getOpConditionSubSql(String op, ModelMeta modelMeta, Object fieldName, Object value, ParameterBindings parameterBindings, String tableAlias) {
        if(Expr.IN.equals(op)) {
            if(value instanceof List) {
                List<Object> valueList = (List<Object>) value;
                for(int i=0;i<valueList.size();++i) {
                    if(valueList.get(i) instanceof String) {
                        valueList.set(i, String.format("'%s'", valueList.get(i)));
                    }
                }
                value = StringUtil.join((List<?>) value, ", ");
            }
            return String.format(" (%s %s (%s)) ", fieldName, op, value);
        }
        parameterBindings.addIndexBinding(value);
        return String.format(" (%s %s ?) ", fieldName, op);
    }
}


text:
package uk.ac.nott.cs.g54dia.multilibrary;
/**
 * Action which loads water into the tanker.
 *
 * @author Neil Madden
 */

/*
 * Copyright (c) 2011 Julian Zapppala (jxz@cs.nott.ac.uk)
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

public class LoadWaterAction implements Action {

    public LoadWaterAction() {}

    public void execute(Environment env, Tanker tank)
        throws ActionFailedException
    {

    	Cell c = env.getCell(tank.getPosition());

    	if (!(c instanceof Well)) {
    		throw new ActionFailedException("LoadWater: Not at Well");
    	}

        if (tank.waterLevel >= Tanker.MAX_WATER) {
            throw new ActionFailedException("LoadWater: Water tank is full");
        }

        tank.waterLevel += Well.WATER_YIELD;

        if (tank.waterLevel > Tanker.MAX_WATER) {
        	tank.waterLevel =Tanker.MAX_WATER;
        }

    }

    public String toString() {
        return "LoadWater";
    }
}


text:
title: 'Hue Development Process - How to do code changes and reviews with Review Board and Git'
author: admin
type: post
date: 2014-07-17T18:57:27+00:00
url: /rbtools-example-how-do-easily-do-code-reviews-with-review-board/
sf_thumbnail_type:
  - none
sf_thumbnail_link_type:
  - link_to_post
sf_detail_type:
  - none
sf_page_title:
  - 1
sf_page_title_style:
  - standard
sf_no_breadcrumbs:
  - 1
sf_page_title_bg:
  - none
sf_page_title_text_style:
  - light
sf_background_image_size:
  - cover
sf_social_sharing:
  - 1
sf_sidebar_config:
  - left-sidebar
sf_left_sidebar:
  - Sidebar-2
sf_right_sidebar:
  - Sidebar-1
sf_caption_position:
  - caption-right
sf_remove_promo_bar:
  - 1
slide_template:
  - default
categories:
  - Development

---

**December 2020**: GitHub pull requests are now prefered https://docs.gethue.com/developer/development/#development-process

**Note:**

During the development process if you are facing any problem then, it is recommended to check your issues at https://discourse.gethue.com/ and https://github.com/cloudera/hue/issues?q=is%3Aissue+. If the solution is not found then, feel free to create an issue at https://github.com/cloudera/hue/issues.

Here is a tutorial about how to use the code review tool [Review Board](https://www.reviewboard.org/) for a better productivity!

# Setup

Hue project uses Review Board and Pull Requests for code reviews. For more complex patches it's advisable to use RB than a plain pull request on github. The advantage of Pull Request is that the CI (syntax check, tests…) automatically runs for you. Along with the web app, a command line tool named RBTool is used to make things easier.

Create accounts in https://review.cloudera.org, https://issues.cloudera.org/browse/HUE and https://github.com and share the usernames

Then, join the 'hue' group in your account https://review.cloudera.org/account/preferences/#groups

Then [download](https://www.reviewboard.org/downloads/rbtools/) the Review Board tools and install it.

If you've never used git and github before, there are bunch of things you need to [do](https://kbroman.org/github_tutorial/pages/first_time.html) before going further.

Now, clone cloudera/hue:

    git clone https://github.com/cloudera/hue

Then, go inside your git repository:

    romain@runreal:~/projects/hue$ rbt setup-repo

    Enter the Review Board server URL: https://review.cloudera.org

    Use the Git repository 'hue' (git://github.com/cloudera/hue.git)? [Yes/No]: yes

    Create '/home/romain/projects/hue/.reviewboardrc' with the following?

    REVIEWBOARD_URL = "https://review.cloudera.org"

    REPOSITORY = "hue"

    BRANCH = "master"

    [Yes/No]: yes

    Config written to /home/romain/projects/hue/.reviewboardrc

Create a new branch with the jira id (HUE-XXX) as the branch name:

    git checkout master
    git pull --rebase origin master
    git checkout -b HUE-XXX

Then make your changes in code:

    git add <file>
    git diff --cached
    git commit -m "HUE-XXX <Ticket summary>"

# Post a review

We have wrapped up the typical submission in a dedicated [tools/scripts/hue-review](https://github.com/cloudera/hue/blob/master/tools/scripts/hue-review) script prefilled with all the details of the commits:

Now we post the review:

    tools/scripts/hue-review HEAD~1..HEAD <reviewers> "HUE-XXX [component] <Ticket summary>" --bugs-closed=HUE-XXX

* Above command must return the review link as given in below example.
* Goto the review link and varify details & press publish. All the reviewers will be informed with an email.

eg:

    tools/scripts/hue-review HEAD~1..HEAD romain,enricoberti,erickt "HUE-2123 [beeswax] Handle cancel state properly" -bugs-closed=HUE-2123

    Review request #4501 posted.

    https://review.cloudera.org/r/4501

Et voila! Here is our review https://review.cloudera.org/r/4501.

**Note**:

If you have more than one diff, update `HEAD~1..HEAD` accordingly (e.g. `HEAD~2..HEAD`)

Now go to the ticket and add a comment with content

* Ticket summary
* Review @ review link

# Update a review

Modify the previous commit diff:

    git add <file>
    git commit --amend

Update the review:

    rbt post -u -r <Review-board-id> HEAD~1..HEAD

Again, go to the review link and varify details & press publish.

# Ship It

Once we get ship it from at least one reviewer, we can push the changes to master

    git rebase origin/master
    git push origin HEAD:ci-commit-master-<yourname>

* The push will auto run the tests and push it to master
* It can be seen on https://circleci.com/gh/cloudera/workflows/hue
  * Two builds would be made - One for Python 2.7 and another for Python 3.6
  * If successful, the change would be auto merged to master
  * On failure, we will get a mail
  * Runs usually take 10-20 min
* Once merged mark the review as submitted - **Close > Submitted**
* Add the commit link to the ticket and mark it as resolved

**Note**:

For lightweight issues, Github [pull requests](https://github.com/cloudera/hue/pulls) are also welcomed! To learn how pull request works please refer this [link](https://github.com/asmeurer/git-workflow).

# Sump-up

We hope that Review Board and these commands will make your life easier and encourage you to [contribute to Hue](https://github.com/cloudera/hue/blob/master/CONTRIBUTING.md) 😉

As usual feel free to send feedback on the [hue-user](http://groups.google.com/a/cloudera.org/group/hue-user) list or [@gethue](https://twitter.com/gethue)!


text:
package org.elasticsearch.action.admin.cluster.node.reload;

import org.elasticsearch.action.support.nodes.BaseNodesRequest;
import org.elasticsearch.common.io.stream.StreamInput;

import java.io.IOException;

/**
 * Request for a reload secure settings action.
 */
public class NodesReloadSecureSettingsRequest extends BaseNodesRequest<NodesReloadSecureSettingsRequest> {

    public NodesReloadSecureSettingsRequest() {
        super((String[]) null);
    }

    public NodesReloadSecureSettingsRequest(StreamInput in) throws IOException {
        super(in);
    }

    /**
     * Reload secure settings only on certain nodes, based on the nodes IDs specified. If none are passed, secure settings will be reloaded
     * on all the nodes.
     */
    public NodesReloadSecureSettingsRequest(final String... nodesIds) {
        super(nodesIds);
    }

}


text:
<?php

namespace Propel\Tests\Runtime\Connection;

use Propel\Tests\TestCase;

/**
 * Tests the PdoConnection class
 *
 * @author Markus Staab <markus.staab@redaxo.de>
 */
class TransactionTraitTest extends TestCase
{
    public function testTransactionRollback()
    {
        $con = $this->getMockForTrait('Propel\Runtime\Connection\TransactionTrait');

        $con->expects($this->once())->method('beginTransaction');
        $con->expects($this->once())->method('rollback');
        $con->expects($this->never())->method('commit');

        try {
            $con->transaction(function () {
                throw new \Exception("boom");
            });
            $this->fail('missing exception');
        } catch (\Exception $e) {
            $this->assertEquals("boom", $e->getMessage(), "exception was rethrown");
        }
    }

    public function testTransactionCommit()
    {
        $con = $this->getMockForTrait('Propel\Runtime\Connection\TransactionTrait');

        $con->expects($this->once())->method('beginTransaction');
        $con->expects($this->never())->method('rollback');
        $con->expects($this->once())->method('commit');

        $this->assertNull($con->transaction(function () {
            // do nothing
        }), "transaction() returns null by default");
    }

    public function testTransactionChaining()
    {
        $con = $this->getMockForTrait('Propel\Runtime\Connection\TransactionTrait');

        $con->expects($this->once())->method('beginTransaction');
        $con->expects($this->never())->method('rollback');
        $con->expects($this->once())->method('commit');

        $this->assertSame("myval", $con->transaction(function () {
            return "myval";
        }), "transaction() returns the returned value from the Closure");
    }

    public function testTransactionNestedCommit()
    {
        $con = $this->getMockForTrait('Propel\Runtime\Connection\TransactionTrait');

        $con->expects($this->exactly(2))->method('beginTransaction');
        $con->expects($this->never())->method('rollback');
        $con->expects($this->exactly(2))->method('commit');

        $this->assertNull($con->transaction(function () use ($con) {
            $this->assertNull($con->transaction(function () {
                // do nothing
            }), "transaction() returns null by default");
        }), "transaction() returns null by default");
    }

    public function testTransactionNestedException()
    {
        $con = $this->getMockForTrait('Propel\Runtime\Connection\TransactionTrait');

        $con->expects($this->exactly(2))->method('beginTransaction');
        $con->expects($this->exactly(2))->method('rollback');
        $con->expects($this->never())->method('commit');

        try {
            $con->transaction(function () use ($con) {
                $con->transaction(function () {
                    throw new \Exception("boooom");
                });
            });
            $this->fail("expecting a nested exception to be re-thrown");
        } catch (\Exception $e) {
            $this->assertEquals("boooom", $e->getMessage());
        }
    }
}


text:
A simple tool to calculate 3D printing times from gcode files.

When given a gcode file as an input, it can be used to create another file with the extension ".timed.gcode" that contains a copy of the original file with extra M117 commands ("Display Message") containing the remaining time at 1-second intervals. This can then be used to print files from an SD card, ie. without host software on a PC, while displaying the remaining time.

# Usage
## Dependencies
* cmake
* boost (filesystem, tokenizer, property_tree)

## Building
Use cmake to build this project. I've created a very simple "build.sh" script that builds gcodetimer under linux, but building it with custom parameters or under another operating system should be trivial:
* Create an empty build folder anywhere and navigate to it
* run "cmake <path to the gcodetimer src folder>"
* run "make"

## Running
gcodetimer ([-i|--info] [-o|--output <output file>] [-s|--stdout] <gcode file> [<gcode file> ...] | --create-config)

  -i, --info: Only print the estimated time for each file, do not generate gcode

  -o, --output: Sets the output filename. Can only be used with a single input file

  -s, --stdout: Prints the generated gcode to stdout instead of saving it to a file.
                   Can only be used with a single input file. -o will be ignored

  --create-config: Generates or completes the config file with any missing defaults

If -o is not specified, the program will create a file of the new name with a '.timed' suffix
  for each input file

# Configuration
In order to calculate the remaining time, this software requires some of your printer's parameters. To get started, run
~~~
gcodetimer --create-config
~~~
This will create a config file in the appropriate folder depending on your operating system:
* Windows: %appdata%\gcodetimer\config.xml
* Linux: $HOME/.config/gcodetimer/config.xml
* Mac OS: $HOME/Library/Application Support/gcodetimer/config.xml

Edit this file according to your needs. The configuration parameters are:
* max_print_accel: The maximum acceleration of your printer during print moves (per axis)
* max_move_accel: The maximum acceleration of your printer during non-print moves (per axis)
* max_jerk: The maximum jerk (instantaneous speed change) settings of your printer
* jerk_efficiency: A factor for the heuristic used to calculate the changes in speed. Start with a value 1 and edit it later on if the timing is off. This factor mostly relates to the effectiveness of the path planning algorithms of your printer's firmware, including the amount of moves it buffers.
* accel_efficiency: Shrinks or grows "max_move_accel" and "max_print_accel". The idea behind this factor is that your printer's processor might not have the processing speed to always drive the motors at the specified maximum values. Start with a value 1 and edit it later on if the timing is off.
* speed_multiplier: This scales the speed of every move. Start with a value 1 and edit it later on if the timing is off.

# Limitations and Hints
 * The time estimation is very simple. It works very well for my printer (approximately +-2 minutes per printing hour), but you might get different results
 * The M117 command is not standard, so this might not work for all printers. Check http://reprap.org/wiki/G-code#M117:_Display_Message *before* using this software!
 * The Repetier firmware (V0.92.9) does not display M117 messages when printing from SD card by default. Check my fork of the firmware for the necessary changes: https://github.com/gonzalezjj/Repetier-Firmware/tree/feature/m117_in_sd_mode


text:
// Copyright (c) Microsoft Corporation.  All rights reserved.
// Licensed under the MIT License.  See License.txt in the project root for license information.

using System.IO;
using Microsoft.AspNet.Scaffolding;

namespace System.Web.OData.Design.Scaffolding
{
    internal static class MvcProjectUtil
    {
        public static readonly string AreaRegistration = "AreaRegistration";
        public static readonly string ControllerSuffix = "Controller";
        public static readonly string DataContextSuffix = "Context";
        public static readonly string ControllerName = "Default{0}Controller";
        public static readonly string PartialViewName = "Partial{0}";
        public static readonly string ViewName = "View{0}";

        public static readonly string DefaultNamespace = "DefaultNamespace";
        public static readonly string PathSeparator = Path.DirectorySeparatorChar.ToString();

        /// <summary>
        /// Regex for selecting the 'Controller' portion of a name.
        /// </summary>
        /// <remarks>
        /// This isn't super-precise, but should do an adequate job matching common identifiers.
        ///
        /// Here's a description. \b makes the match start at a word boundary, so for names with
        /// namespaces, this starts the match after that. The group ([_\d\w]*) matches any number
        /// of underscore, number or letter characters and stores them in a group. Lastly the literal
        /// text Controller, and the $ matches end of string.
        ///
        /// Technically some other characters besides _\d\w are allowed, but this should handled the 99.9% case.
        /// </remarks>
        public static readonly string ControllerNameRegex = @"\b([_\d\w]*)" + ControllerSuffix + "$";

        /// <summary>
        /// Regex for selecting the 'Controller' portion of a name. See the remarks on ControllerNameRegex.
        /// </summary>
        public static readonly string DataContextNameRegex = @"\b([_\d\w]*)" + DataContextSuffix + "$";

        /// <summary>
        /// This method extracts the root name of the controller from the class name of
        /// the controller.
        /// </summary>
        /// <param name="fullControllerName">Full class name of the controller</param>
        /// <returns>The stripped string if the suffix was found, or the same string as the parameter if
        /// no 'Controller' suffix was found</returns>
        public static string StripControllerName(string fullControllerName)
        {
            if (String.IsNullOrEmpty(fullControllerName))
            {
                return fullControllerName;
            }

            return EndsWithController(fullControllerName) ? fullControllerName.Substring(0, fullControllerName.Length - ControllerSuffix.Length)
                                                          : fullControllerName;
        }

        /// <summary>
        /// This method checks to see if a controller name follows the MVC convention of ending the
        /// class name with the suffix 'Controller'.
        /// </summary>
        /// <param name="name">Name of the controller class</param>
        /// <returns>true if the name ends with the correct suffix, false otherwise</returns>
        public static bool EndsWithController(string name)
        {
            return name.EndsWith(ControllerSuffix, StringComparison.Ordinal);
        }

        public static string EnsureTrailingBackSlash(string str)
        {
            if (str != null && !str.EndsWith(PathSeparator, StringComparison.Ordinal))
            {
                str += PathSeparator;
            }
            return str;
        }

        public static string GetDefaultModelsNamespace(string projectDefaultNamespace)
        {
            if (String.IsNullOrEmpty(projectDefaultNamespace))
            {
                return CommonFolderNames.Models;
            }
            else
            {
                return projectDefaultNamespace + "." + CommonFolderNames.Models;
            }
        }

        internal static string GetViewFileExtension(ProjectLanguage language)
        {
            if (language == null)
            {
                throw new ArgumentNullException("language");
            }

            if (language == ProjectLanguage.CSharp)
            {
                return "cshtml";
            }
            else if (language == ProjectLanguage.VisualBasic)
            {
                return "vbhtml";
            }
            else
            {
                throw new InvalidOperationException(Resources.ScaffoldLanguageNotSupported);
            }
        }
    }
}


text:
ACCEPTED

#### According to
Index Fungorum

#### Published in
Trans. Mycol. Soc. Japan 22(1): 62 (1981)

#### Original name
Exobasidium sakataniense S. Hirata

### Remarks
null


text:
<?php
class Pages extends CPagination
{
	const DEFAULT_PAGE_SIZE = 20;

	public $validateCurrentPage = false;

	public function __construct ( $itemCount = 0 )
	{
		$this->setItemCount( $itemCount );
		$this->setPageSize( self::DEFAULT_PAGE_SIZE );
	}
}


text: Examples of using oauth for user authentication.


text:
namespace XamarinShot.Utils
{
    using ARKit;
    using System.Collections.Generic;
    using System.Linq;
    using XamarinShot.Models;

    public static class ARWorldMapExtensions
    {
        public static BoardAnchor BoardAnchor(this ARWorldMap self)
        {
            return self.Anchors.FirstOrDefault(anchor => anchor is BoardAnchor) as BoardAnchor;
        }

        public static List<KeyPositionAnchor> KeyPositionAnchors(this ARWorldMap self)
        {
            return self.Anchors.Where(anchor => anchor is KeyPositionAnchor).Cast<KeyPositionAnchor>().ToList();
        }
    }
}


text:
{% extends "base.html" %}
{% block title %}{{ assessment.name }} - Assessment | Sh00t{% endblock %}

{% block page %}

Dashboard

Assessments

 {{ assessment.name }}

        <form role="form" method="post">
            {% if "success" == submitted %}

                            <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>  Updated

            {% endif %}

                Name
                <input class="form-control" name="name" id="name" value="{{ assessment.name }}" autocomplete="off">

                Project
                <select class="form-control" name="project" id="project">
                {% for project in projects %}
                    <option value="{{ project.id }}"
                    {% if project.id == assessment.project.id %}
                        selected="selected"
                    {% endif %}>
                    {{ project.name }}</option>
                {% endfor %}
                </select>

            <input type="hidden" value="{{ assessment.id }}" id="id" /><input type="hidden" value="{{ assessment.id }}" id="id" />
            <button type="submit" class="btn btn-primary">Update</button>
            <button type="submit" name="delete" value="delete" class="btn btn-danger">Delete</button>
            {% csrf_token %}
        </form>

{% endblock %}
{% block extra_foot %}

{% endblock %}


text:
static CGFloat const kVideoRecordTableViewCellHeight = 168.0f;
static NSInteger const kCacheButtonCornerRadius = 15.0f;
static NSString *const kPlaceholderImageName = @"placeholder";
static NSString *const kFontPercentName = @"HelveticaNeue";
@interface VideoRecordTableViewCell ()

@property (nonatomic, weak) id <LectureMaterialCacheDelegate> actionProxy;
@property (nonatomic, strong) LectureMaterialViewModel *videoMaterial;

@end

@implementation VideoRecordTableViewCell

- (void)awakeFromNib {
    [super awakeFromNib];
    self.circleProgressBar.unitString = @"%";
    self.circleProgressBar.progressAngle = 100;
    self.circleProgressBar.progressLineWidth = 3;
    self.circleProgressBar.progressColor = [UIColor whiteColor];
    self.circleProgressBar.progressStrokeColor = [UIColor whiteColor];
    self.circleProgressBar.progressCapType = 1;
    self.circleProgressBar.valueFontSize = 10;
    self.circleProgressBar.fontColor = [UIColor whiteColor];
    self.circleProgressBar.valueFontName = kFontPercentName;
    self.circleProgressBar.unitFontName = kFontPercentName;
    self.circleProgressBar.emptyLineColor = [UIColor lightTextColor];
    self.circleProgressBar.emptyLineWidth = 0.5;
    self.circleProgressBar.value = 0;
}

- (void)didMoveToSuperview {
    [super didMoveToSuperview];
    self.actionProxy = (id<LectureMaterialCacheDelegate>)[self cd_proxyForProtocol:@protocol(LectureMaterialCacheDelegate)];
}

#pragma mark - NICell methods

- (BOOL)shouldUpdateCellWithObject:(VideoRecordTableViewCellObject *)object {
    self.videoMaterial = object.videoMaterial;
    if (object.previewImageUrl) {
        [self setupPreviewStateWithObject:object];
    } else {
        [self setupNoVideoStateWithObject:object];
    }

    self.removeButton.layer.cornerRadius = kCacheButtonCornerRadius;
    self.downloadButton.layer.cornerRadius = kCacheButtonCornerRadius;
    self.circleProgressBar.layer.cornerRadius = kCacheButtonCornerRadius;

    if ([object.videoMaterial.isDownloading boolValue]) {
        [self.removeButton setHidden:YES];
        [self.downloadButton setHidden:YES];
        [self.circleProgressBar setHidden:NO];
        self.circleProgressBar.value = [object.videoMaterial.percent floatValue];
        return YES;
    }
    BOOL isVideoCached = object.videoMaterial.localURL.length != 0;

    [self.removeButton setHidden:!isVideoCached];
    [self.downloadButton setHidden:isVideoCached];
    [self.circleProgressBar setHidden:YES];
    return YES;
}

+ (CGFloat)heightForObject:(id)object atIndexPath:(NSIndexPath *)indexPath tableView:(UITableView *)tableView {
    return kVideoRecordTableViewCellHeight;
}

#pragma mark - IBAction

- (IBAction)didTapRemoveFromCacheVideoMaterial:(id)sender {
    [self.actionProxy didTapRemoveFromCacheLectureMaterial:self.videoMaterial];
}

- (IBAction)didTapDownloadToCacheVideoMaterial:(id)sender {
    [self.actionProxy didTapDownloadToCacheLectureMaterial:self.videoMaterial];
}

#pragma mark - Private methods

- (void)setupPreviewStateWithObject:(VideoRecordTableViewCellObject *)object {
    self.titleLabel.hidden = YES;
    self.playIconImageView.hidden = NO;
    [self.previewImageView sd_setImageWithURL:object.previewImageUrl
                             placeholderImage:[UIImage imageNamed:kPlaceholderImageName]];
}

- (void)setupNoVideoStateWithObject:(VideoRecordTableViewCellObject *)object {
    self.titleLabel.hidden = NO;
    self.playIconImageView.hidden = YES;
    self.previewImageView.image = [UIImage imageNamed:kPlaceholderImageName];
}

@end


text:
// This file implements unit tests for class Counter.

#include "core/cross/client.h"
#include "tests/common/win/testing_common.h"
#include "core/cross/counter.h"
#include "core/cross/timer.h"

namespace o3d {

class CounterTest : public testing::Test {
 protected:

  CounterTest()
      : object_manager_(g_service_locator) {}

  virtual void SetUp();
  virtual void TearDown();

  CounterManager* counter_manager() { return counter_manager_; }
  Pack* pack() { return pack_; }

 private:

  ServiceDependency<ObjectManager> object_manager_;
  CounterManager *counter_manager_;
  Pack* pack_;
};

void CounterTest::SetUp() {
  counter_manager_ = new CounterManager(g_service_locator);
  pack_ = object_manager_->CreatePack();
}

void CounterTest::TearDown() {
  pack_->Destroy();
  delete counter_manager_;
}

// Tests the creation of a Counter.
TEST_F(CounterTest, Basic) {
  Counter* counter = pack()->Create<Counter>();
  ASSERT_TRUE(counter != NULL);

  // Check that its default params got created.
  EXPECT_TRUE(
      counter->GetParam<ParamBoolean>(Counter::kRunningParamName) != NULL);
  EXPECT_TRUE(
      counter->GetParam<ParamBoolean>(Counter::kForwardParamName) != NULL);
  EXPECT_TRUE(
      counter->GetParam<ParamInteger>(Counter::kCountModeParamName) != NULL);
  EXPECT_TRUE(
      counter->GetParam<ParamFloat>(Counter::kStartParamName) != NULL);
  EXPECT_TRUE(
      counter->GetParam<ParamFloat>(Counter::kEndParamName) != NULL);
  EXPECT_TRUE(
      counter->GetParam<ParamFloat>(Counter::kCountParamName) != NULL);
  EXPECT_TRUE(
      counter->GetParam<ParamFloat>(Counter::kMultiplierParamName) != NULL);

  // Check that the defaults are correct
  EXPECT_EQ(counter->forward(), true);
  EXPECT_EQ(counter->running(), true);
  EXPECT_EQ(counter->count_mode(), Counter::CONTINUOUS);
  EXPECT_EQ(counter->count(), 0.0f);
  EXPECT_EQ(counter->start(), 0.0f);
  EXPECT_EQ(counter->end(), 0.0f);
  EXPECT_EQ(counter->multiplier(), 1.0f);
}

// Tests Counter::Advance
TEST_F(CounterTest, Advance) {
  Counter* counter = pack()->Create<Counter>();
  ASSERT_TRUE(counter != NULL);
  Counter::CounterCallbackQueue queue;

  counter->set_start(1.0f);
  counter->set_end(5.0f);
  counter->Reset();

  // See that it advances.
  EXPECT_EQ(counter->count(), 1.0f);
  counter->Advance(1.0f, &queue);
  EXPECT_EQ(counter->count(), 2.0f);

  // See that forward works.
  counter->set_forward(false);
  counter->Advance(1.0f, &queue);
  EXPECT_EQ(counter->count(), 1.0f);
  counter->set_forward(true);

  // Check that CONTINUOUS works.
  counter->Advance(10.0f, &queue);
  EXPECT_EQ(counter->count(), 11.0f);
  // Check backward as well.
  counter->Advance(-20.0f, &queue);
  EXPECT_EQ(counter->count(), -9.0f);

  // Check that ONCE works.
  counter->Reset();
  counter->set_running(true);
  counter->set_count_mode(Counter::ONCE);
  counter->Advance(10.0f, &queue);
  EXPECT_EQ(counter->count(), counter->end());
  EXPECT_EQ(counter->running(), false);
  // Check backward as well.
  counter->set_running(true);
  counter->Advance(-10.0f, &queue);
  EXPECT_EQ(counter->count(), counter->start());
  EXPECT_EQ(counter->running(), false);
  // Check bounds end.
  counter->SetCount(counter->end());
  counter->set_running(true);
  counter->Advance(1.0f, &queue);
  EXPECT_EQ(counter->count(), counter->end());
  EXPECT_EQ(counter->running(), false);
  // Check bounds start
  counter->SetCount(counter->start());
  counter->set_running(true);
  counter->Advance(-1.0f, &queue);
  EXPECT_EQ(counter->count(), counter->start());
  EXPECT_EQ(counter->running(), false);

  // Check that CYCLE works.
  counter->Reset();
  counter->set_count_mode(Counter::CYCLE);
  counter->Advance(4.0f, &queue);
  EXPECT_EQ(counter->count(), counter->start());
  counter->Advance(5.0f, &queue);
  EXPECT_EQ(counter->count(), counter->start() + 1.0f);
  counter->Advance(-4.0f, &queue);
  EXPECT_EQ(counter->count(), counter->start() + 1.0f);

  // Check that OSCILLATE works.
  counter->Reset();
  counter->set_count_mode(Counter::OSCILLATE);
  counter->Advance(5.0f, &queue);
  EXPECT_EQ(counter->count(), counter->start() + 3.0f);
  EXPECT_EQ(counter->forward(), false);
  counter->Advance(4.0f, &queue);
  EXPECT_EQ(counter->count(), counter->start() + 1.0f);
  EXPECT_EQ(counter->forward(), true);
  counter->Advance(-3.0f, &queue);
  EXPECT_EQ(counter->count(), counter->start() + 2.0f);
  EXPECT_EQ(counter->forward(), false);
  counter->Advance(-4.0f, &queue);
  EXPECT_EQ(counter->count(), counter->start() + 2.0f);
  EXPECT_EQ(counter->forward(), true);
}

// Tests Counter::Reset
TEST_F(CounterTest, Reset) {
  Counter* counter = pack()->Create<SecondCounter>();
  ASSERT_TRUE(counter != NULL);

  counter->set_start(20.0f);
  counter->set_end(40.0f);
  EXPECT_EQ(counter->count(), 0.0f);
  counter->Reset();
  EXPECT_EQ(counter->count(), 20.0f);
  counter->set_forward(false);
  counter->Reset();
  EXPECT_EQ(counter->count(), 40.0f);
}

namespace {

// A CounterCallback that tracks how many times it has been called
// and whether or not it has been deleted.
class TestCounterCallback : public Counter::CounterCallback {
 public:
  explicit TestCounterCallback(bool* deleted)
      : call_count_(0),
        deleted_(deleted) {
    *deleted_ = false;
  }

  ~TestCounterCallback() {
    *deleted_ = true;
  }

  virtual void Run() {
    ++call_count_;
  }

  int call_count() {
    return call_count_;
  }

  void Reset() {
    call_count_ = 0;
  }

 private:
  int call_count_;  // number of times this callback was called.
  bool* deleted_;  // pointer to bool to get set to true when deleted.

  DISALLOW_COPY_AND_ASSIGN(TestCounterCallback);
};

}  // anonymous namespace

// Tests Counter::AddCallback/RemoveCallback
TEST_F(CounterTest, AddRemoveGetCallback) {
  Counter* counter = pack()->Create<Counter>();
  ASSERT_TRUE(counter != NULL);

  const Counter::CounterCallbackInfoArray& counters = counter->GetCallbacks();
  Counter::CounterCallbackInfoArray::const_iterator iter;

  bool test1_deleted;
  bool test2_deleted;
  TestCounterCallback* test1 = new TestCounterCallback(&test1_deleted);
  TestCounterCallback* test2 = new TestCounterCallback(&test2_deleted);
  ASSERT_TRUE(test1 != NULL);
  ASSERT_TRUE(test2 != NULL);
  ASSERT_FALSE(test1_deleted);
  ASSERT_FALSE(test2_deleted);

  // Testing Adding
  counter->AddCallback(2.0f, test2);
  counter->AddCallback(1.0f, test1);
  // Check that both got added.
  ASSERT_EQ(counters.size(), 2U);
  iter = counters.begin();
  EXPECT_EQ(iter->count(), 1.0f);
  ++iter;
  EXPECT_EQ(iter->count(), 2.0f);

  // Check that adding one at the same time removes the other
  counter->AddCallback(2.0f, test1);
  EXPECT_TRUE(test2_deleted);
  ASSERT_EQ(counters.size(), 2U);

  // Check that removing a non-existant callback fails.
  EXPECT_FALSE(counter->RemoveCallback(3.0f));

  // Check that removing one of the duplicated callbacks does not remove the
  // other.
  EXPECT_TRUE(counter->RemoveCallback(1.0f));
  ASSERT_EQ(counters.size(), 1U);
  EXPECT_FALSE(test1_deleted);

  // Check that removing final callback deletes the callback.
  EXPECT_TRUE(counter->RemoveCallback(2.0f));
  ASSERT_EQ(counters.size(), 0U);
  EXPECT_TRUE(test1_deleted);
  EXPECT_FALSE(counter->RemoveCallback(2.0f));

  // Check that callbacks get called correct number of times.
  test1 = new TestCounterCallback(&test1_deleted);
  test2 = new TestCounterCallback(&test2_deleted);
  bool test3_deleted;
  bool test4_deleted;
  bool test5_deleted;
  TestCounterCallback* test3 = new TestCounterCallback(&test3_deleted);
  TestCounterCallback* test4 = new TestCounterCallback(&test4_deleted);
  TestCounterCallback* test5 = new TestCounterCallback(&test5_deleted);
  ASSERT_TRUE(test1 != NULL);
  ASSERT_TRUE(test2 != NULL);
  ASSERT_FALSE(test1_deleted);
  ASSERT_FALSE(test2_deleted);
  counter->set_start(1.0f);
  counter->set_end(5.0f);
  counter->AddCallback(0.0f, test1);  // before start
  counter->AddCallback(1.0f, test2);  // at start
  counter->AddCallback(2.0f, test3);  // in between
  counter->AddCallback(5.0f, test4);  // end end
  counter->AddCallback(6.0f, test5);  // after end.

  Counter::CounterCallbackQueue queue;

  // Test CONTINUOUS
  counter->Reset();
  counter->Advance(0.0f, &queue);  // At 1
  EXPECT_EQ(counter->count(), 1.0f);
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 0);
  EXPECT_EQ(test2->call_count(), 0);
  EXPECT_EQ(test3->call_count(), 0);
  EXPECT_EQ(test4->call_count(), 0);
  EXPECT_EQ(test5->call_count(), 0);
  counter->Advance(1.0f, &queue);  // At 2
  EXPECT_EQ(counter->count(), 2.0f);
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 0);
  EXPECT_EQ(test2->call_count(), 1);
  EXPECT_EQ(test3->call_count(), 1);
  EXPECT_EQ(test4->call_count(), 0);
  EXPECT_EQ(test5->call_count(), 0);
  counter->Advance(3.0f, &queue);  // At 5
  EXPECT_EQ(counter->count(), 5.0f);
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 0);
  EXPECT_EQ(test2->call_count(), 1);
  EXPECT_EQ(test3->call_count(), 1);
  EXPECT_EQ(test4->call_count(), 1);
  EXPECT_EQ(test5->call_count(), 0);
  counter->Advance(3.0f, &queue);  // At 8
  EXPECT_EQ(counter->count(), 8.0f);
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 0);
  EXPECT_EQ(test2->call_count(), 1);
  EXPECT_EQ(test3->call_count(), 1);
  EXPECT_EQ(test4->call_count(), 1);
  EXPECT_EQ(test5->call_count(), 1);
  counter->Advance(-3.0f, &queue);  // At 5
  EXPECT_EQ(counter->count(), 5.0f);
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 0);
  EXPECT_EQ(test2->call_count(), 1);
  EXPECT_EQ(test3->call_count(), 1);
  EXPECT_EQ(test4->call_count(), 2);
  EXPECT_EQ(test5->call_count(), 2);
  counter->Advance(-3.0f, &queue);  // At 2
  EXPECT_EQ(counter->count(), 2.0f);
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 0);
  EXPECT_EQ(test2->call_count(), 1);
  EXPECT_EQ(test3->call_count(), 2);
  EXPECT_EQ(test4->call_count(), 2);
  EXPECT_EQ(test5->call_count(), 2);
  counter->Advance(-2.0f, &queue);  // At 0
  EXPECT_EQ(counter->count(), 0.0f);
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 1);
  EXPECT_EQ(test2->call_count(), 2);
  EXPECT_EQ(test3->call_count(), 2);
  EXPECT_EQ(test4->call_count(), 2);
  EXPECT_EQ(test5->call_count(), 2);

  // Test ONCE
  test1->Reset();
  test2->Reset();
  test3->Reset();
  test4->Reset();
  test5->Reset();
  counter->Reset();
  counter->set_count_mode(Counter::ONCE);
  counter->Advance(0.0f, &queue);  // At 1
  EXPECT_EQ(counter->count(), 1.0f);
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 0);
  EXPECT_EQ(test2->call_count(), 0);
  EXPECT_EQ(test3->call_count(), 0);
  EXPECT_EQ(test4->call_count(), 0);
  EXPECT_EQ(test5->call_count(), 0);
  counter->Advance(10.0f, &queue);  // At 5
  EXPECT_EQ(counter->count(), 5.0f);
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 0);
  EXPECT_EQ(test2->call_count(), 1);
  EXPECT_EQ(test3->call_count(), 1);
  EXPECT_EQ(test4->call_count(), 1);
  EXPECT_EQ(test5->call_count(), 0);
  counter->set_forward(false);
  counter->Advance(10.0f, &queue);  // At 1
  EXPECT_EQ(counter->count(), 1.0f);
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 0);
  EXPECT_EQ(test2->call_count(), 2);
  EXPECT_EQ(test3->call_count(), 2);
  EXPECT_EQ(test4->call_count(), 2);
  EXPECT_EQ(test5->call_count(), 0);

  // Test CYCLE
  test1->Reset();
  test2->Reset();
  test3->Reset();
  test4->Reset();
  test5->Reset();
  counter->set_forward(true);
  counter->Reset();
  counter->set_count_mode(Counter::CYCLE);
  counter->Advance(4.0f, &queue);  // At 1.0 (1 cycle)
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 0);
  EXPECT_EQ(test2->call_count(), 1);
  EXPECT_EQ(test3->call_count(), 1);
  EXPECT_EQ(test4->call_count(), 1);
  EXPECT_EQ(test5->call_count(), 0);
  counter->Advance(22.0f, &queue);  // At 3.0 (5 cycles + 2)
  EXPECT_EQ(counter->count(), 3.0f);
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 0);
  EXPECT_EQ(test2->call_count(), 7);
  EXPECT_EQ(test3->call_count(), 7);
  EXPECT_EQ(test4->call_count(), 6);
  EXPECT_EQ(test5->call_count(), 0);
  counter->Advance(-21.0f, &queue);  // At 2.0 (5 cycles + 1)
  EXPECT_EQ(counter->count(), 2.0f);
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 0);
  EXPECT_EQ(test2->call_count(), 12);
  EXPECT_EQ(test3->call_count(), 13);
  EXPECT_EQ(test4->call_count(), 11);
  EXPECT_EQ(test5->call_count(), 0);

  // Test OSCILLATE
  test1->Reset();
  test2->Reset();
  test3->Reset();
  test4->Reset();
  test5->Reset();
  counter->Reset();
  counter->set_forward(true);
  counter->set_count_mode(Counter::OSCILLATE);
  counter->Advance(22.0f, &queue);  // At 3.0 (5 cycles)
  EXPECT_EQ(counter->count(), 3.0f);
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 0);
  EXPECT_EQ(test2->call_count(), 5);
  EXPECT_EQ(test3->call_count(), 5);
  EXPECT_EQ(test4->call_count(), 6);
  EXPECT_EQ(test5->call_count(), 0);
  counter->Advance(-21.0f, &queue);  // At 2.0 (5 cycles)
  EXPECT_EQ(counter->count(), 2.0f);
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 0);
  EXPECT_EQ(test2->call_count(), 9);
  EXPECT_EQ(test3->call_count(), 10);
  EXPECT_EQ(test4->call_count(), 12);
  EXPECT_EQ(test5->call_count(), 0);

  // Check start < end case ----------------------------

  counter->set_start(5.0f);
  counter->set_end(1.0f);

  // Test CONTINUOUS
  test1->Reset();
  test2->Reset();
  test3->Reset();
  test4->Reset();
  test5->Reset();
  counter->set_count_mode(Counter::CONTINUOUS);
  counter->Reset();
  counter->Advance(0.0f, &queue);  // At 5
  EXPECT_EQ(counter->count(), 5.0f);
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 0);
  EXPECT_EQ(test2->call_count(), 0);
  EXPECT_EQ(test3->call_count(), 0);
  EXPECT_EQ(test4->call_count(), 0);
  EXPECT_EQ(test5->call_count(), 0);
  counter->Advance(1.0f, &queue);  // At 4
  EXPECT_EQ(counter->count(), 4.0f);
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 0);
  EXPECT_EQ(test2->call_count(), 0);
  EXPECT_EQ(test3->call_count(), 0);
  EXPECT_EQ(test4->call_count(), 1);
  EXPECT_EQ(test5->call_count(), 0);
  counter->Advance(3.0f, &queue);  // At 1
  EXPECT_EQ(counter->count(), 1.0f);
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 0);
  EXPECT_EQ(test2->call_count(), 1);
  EXPECT_EQ(test3->call_count(), 1);
  EXPECT_EQ(test4->call_count(), 1);
  EXPECT_EQ(test5->call_count(), 0);
  counter->Advance(3.0f, &queue);  // At -2
  EXPECT_EQ(counter->count(), -2.0f);
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 1);
  EXPECT_EQ(test2->call_count(), 1);
  EXPECT_EQ(test3->call_count(), 1);
  EXPECT_EQ(test4->call_count(), 1);
  EXPECT_EQ(test5->call_count(), 0);
  counter->Advance(-3.0f, &queue);  // At 1
  EXPECT_EQ(counter->count(), 1.0f);
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 2);
  EXPECT_EQ(test2->call_count(), 2);
  EXPECT_EQ(test3->call_count(), 1);
  EXPECT_EQ(test4->call_count(), 1);
  EXPECT_EQ(test5->call_count(), 0);
  counter->Advance(-3.0f, &queue);  // At 4
  EXPECT_EQ(counter->count(), 4.0f);
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 2);
  EXPECT_EQ(test2->call_count(), 2);
  EXPECT_EQ(test3->call_count(), 2);
  EXPECT_EQ(test4->call_count(), 1);
  EXPECT_EQ(test5->call_count(), 0);
  counter->Advance(-2.0f, &queue);  // At 6
  EXPECT_EQ(counter->count(), 6.0f);
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 2);
  EXPECT_EQ(test2->call_count(), 2);
  EXPECT_EQ(test3->call_count(), 2);
  EXPECT_EQ(test4->call_count(), 2);
  EXPECT_EQ(test5->call_count(), 1);

  // Test ONCE
  test1->Reset();
  test2->Reset();
  test3->Reset();
  test4->Reset();
  test5->Reset();
  counter->Reset();
  counter->set_count_mode(Counter::ONCE);
  counter->Advance(0.0f, &queue);  // At 5
  EXPECT_EQ(counter->count(), 5.0f);
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 0);
  EXPECT_EQ(test2->call_count(), 0);
  EXPECT_EQ(test3->call_count(), 0);
  EXPECT_EQ(test4->call_count(), 0);
  EXPECT_EQ(test5->call_count(), 0);
  counter->Advance(10.0f, &queue);  // At 1
  EXPECT_EQ(counter->count(), 1.0f);
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 0);
  EXPECT_EQ(test2->call_count(), 1);
  EXPECT_EQ(test3->call_count(), 1);
  EXPECT_EQ(test4->call_count(), 1);
  EXPECT_EQ(test5->call_count(), 0);
  counter->set_forward(false);
  counter->Advance(10.0f, &queue);  // At 5
  EXPECT_EQ(counter->count(), 5.0f);
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 0);
  EXPECT_EQ(test2->call_count(), 2);
  EXPECT_EQ(test3->call_count(), 2);
  EXPECT_EQ(test4->call_count(), 2);
  EXPECT_EQ(test5->call_count(), 0);

  // Test CYCLE
  test1->Reset();
  test2->Reset();
  test3->Reset();
  test4->Reset();
  test5->Reset();
  counter->Reset();
  counter->set_forward(true);
  counter->set_count_mode(Counter::CYCLE);
  counter->Advance(22.0f, &queue);  // At 3.0 (5 cycles + 2)
  EXPECT_EQ(counter->count(), 3.0f);
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 0);
  EXPECT_EQ(test2->call_count(), 5);
  EXPECT_EQ(test3->call_count(), 5);
  EXPECT_EQ(test4->call_count(), 6);
  EXPECT_EQ(test5->call_count(), 0);
  counter->Advance(-21.0f, &queue);  // At 4.0 (5 cycles + 1)
  EXPECT_EQ(counter->count(), 4.0f);
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 0);
  EXPECT_EQ(test2->call_count(), 10);
  EXPECT_EQ(test3->call_count(), 10);
  EXPECT_EQ(test4->call_count(), 11);
  EXPECT_EQ(test5->call_count(), 0);

  // Test OSCILLATE
  test1->Reset();
  test2->Reset();
  test3->Reset();
  test4->Reset();
  test5->Reset();
  counter->Reset();
  counter->set_forward(true);
  counter->set_count_mode(Counter::OSCILLATE);
  counter->Advance(22.0f, &queue);  // At 3.0 (5 cycles)
  EXPECT_EQ(counter->count(), 3.0f);
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 0);
  EXPECT_EQ(test2->call_count(), 6);
  EXPECT_EQ(test3->call_count(), 6);
  EXPECT_EQ(test4->call_count(), 5);
  EXPECT_EQ(test5->call_count(), 0);
  counter->Advance(-21.0f, &queue);  // At 4.0 (5 cycles)
  EXPECT_EQ(counter->count(), 4.0f);
  queue.CallCounterCallbacks();
  EXPECT_EQ(test1->call_count(), 0);
  EXPECT_EQ(test2->call_count(), 12);
  EXPECT_EQ(test3->call_count(), 12);
  EXPECT_EQ(test4->call_count(), 9);
  EXPECT_EQ(test5->call_count(), 0);

  // Check RemoveAllCallbacks.
  counter->RemoveAllCallbacks();
  EXPECT_EQ(counters.size(), 0U);
  EXPECT_TRUE(test1_deleted);
  EXPECT_TRUE(test2_deleted);
  EXPECT_TRUE(test3_deleted);
  EXPECT_TRUE(test4_deleted);
  EXPECT_TRUE(test5_deleted);
}

// Tests SecondCounter.
TEST_F(CounterTest, SecondCounter) {
  SecondCounter* counter = pack()->Create<SecondCounter>();
  ASSERT_TRUE(counter != NULL);

  EXPECT_EQ(0.0f, counter->count());
  counter_manager()->AdvanceCounters(2.0f, 1.0f);
  EXPECT_EQ(1.0f, counter->count());
}

// Tests RenderFrameCounter.
TEST_F(CounterTest, RenderFrameCounter) {
  RenderFrameCounter* counter = pack()->Create<RenderFrameCounter>();
  ASSERT_TRUE(counter != NULL);

  EXPECT_EQ(0.0f, counter->count());
  counter_manager()->AdvanceRenderFrameCounters(1.0f);
  EXPECT_EQ(1.0f, counter->count());
}

// Tests TickCounter.
TEST_F(CounterTest, TickCounter) {
  TickCounter* counter = pack()->Create<TickCounter>();
  ASSERT_TRUE(counter != NULL);

  EXPECT_EQ(0.0f, counter->count());
  counter_manager()->AdvanceCounters(1.0f, 2.0f);
  EXPECT_EQ(1.0f, counter->count());
}

}  // namespace o3d


text:
salt.states.sysfs
==================

.. automodule:: salt.states.sysfs
    :members:


text:
class Resource_Holder;
class World;
class Player;

class Zone
{
    public:
        virtual ~Zone() = default;

        void update(World& world, Player& player, float dt);

        void draw();

        Zone_ID getID() const;

        template<typename... Args>
        void addProjectile(Args&&... args)
        {
            m_projetiles.emplace_back(std::forward<Args>(args)...);
        }

    protected:
        Zone(const sf::Texture& background, Zone_ID id);

        void addEntity(std::unique_ptr<Entity>);

        virtual void onUpdate   (World& world, Player& player, float dt) = 0;
        virtual void onDraw     () = 0;

        int checkForDeadEntities(Player& player);
        bool entityDamaged      ();

    private:
        sf::RectangleShape m_background;
        sf::RectangleShape m_shakeGround;

        std::vector<std::unique_ptr<Entity>> m_entities;
        std::vector<Projectile> m_projetiles;

        Zone_ID m_id;
};

#endif // ZONE_H_INCLUDED


text:
<?php

class Collection extends ArrayObject
{
	public function add($dataArray)
	{
		foreach($dataArray as $value) $this->append($value);
	}

	public function offsetSet($index, $value)
	{
		parent::offsetSet($index, $value);
	}
}

$data1=array('one', 'two', 'three');
$data2=array('four', 'five');

$foo=new Collection($data1);
$foo->add($data2);

print_r($foo->getArrayCopy());

echo "Done\n";
?>


text:
pi-dnetc Cookbook
=================
Intalls the [distributed.net](http://distributed.net) client on your Raspberry Pi.

Requirements
------------
Raspberry Pi :-)

Attributes
----------

#### pi-dnetc::default

    Key
    Type
    Description
    Default

    <tt>['pi-dnetc']['OGR-28']</tt>
    Boolean
    whether to run OGR or not
    <tt>true</tt>

    <tt>['pi-dnetc']['RC-72']</tt>
    Boolean
    whether to run OGR or not
    <tt>true</tt>

TODO: not implemented yet!

Usage
-----
#### pi-dnetc::default

e.g.
Just include `pi-dnetc` in your node's `run_list`:

```json
{
  "name":"my_node",
  "run_list": [
    "recipe[pi-dnetc]"
  ]
}
```

Contributing
------------
TODO: (optional) If this is a public cookbook, detail the process for contributing. If this is a private cookbook, remove this section.

e.g.
1. Fork the repository on Github
2. Create a named feature branch (like `add_component_x`)
3. Write your change
4. Write tests for your change (if applicable)
5. Run the tests, ensuring they all pass
6. Submit a Pull Request using Github

License and Authors
-------------------
Authors: Andreas Fritzler

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this software except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.


text:
/**
 * ping.js
 * Simply returns PONG. Useful for checking the health from the load balancers.
 *
 * @author  Jason Valdron <jason@valdron.ca>
 * @package di-api
 */

(function() {
  'use strict';

  // Export the route function.
  module.exports = function(app){

    // GET /ping - Responds with 200 PONG.
    app.get('/ping', function(req, res){

      return res.status(200).send('PONG');

    });

  };

})();


text:
<!DOCTYPE html>
<html>

<script type="text/javascript">
(function (window) {
  'use strict'

  const document = window.document
  const tangojs = window.tangojs

  class SeededPrng {
    constructor (seed) {
      this._seed = seed
    }
    nextDouble () {
      const x = Math.sin(this._seed++) * 10000
      return x - Math.floor(x)
    }
  }

  const prng = new SeededPrng(10)
  const randcf = () => Math.round(prng.nextDouble() * 255)
  const randomColor = () => `rgb(${randcf()},${randcf()},${randcf()})`

  const timeFormat = 'HH:mm:ss'

  const plotOptions = {
    responsive: true,
    maintainAspectRatio: false,
    title: {
      display: false
    },
    tooltips: {
      enabled: false
    },
    animation: {
      duration: 0 // the plot is unreadable with animation
      // easing: 'easeOutBack'
    },
    scales: {
      xAxes: [{
        type: 'time',
        display: true,
        time: {
          displayFormats: {
              millisecond: timeFormat,
              second: timeFormat,
              minute: timeFormat,
              hour: timeFormat
          }
        },
        scaleLabel: {
          display: true,
          labelString: 'time'
        },
        gridLines: {
          display: false
        }
      }],
      yAxes: [{
        display: true,
        scaleLabel: {
          display: true,
          labelString: 'value'
        }
      }]
    }
  }

  class TangoJsTrendElement extends window.HTMLElement {

    createdCallback () {

      this.root = this.createShadowRoot()
      this.dom = this.createLocalDom()
      this.root.appendChild(this.dom.grid)

      this.plot = this.createPlot(this.dom.canvas.getContext('2d'))

      this.onResizeCallback = () => {
        this.plot.chart.resize()
      }

      this.mutationObserver = new MutationObserver(this.onResizeCallback)
      this.mutationObserver.observe(this, { attributes: true })

      window.addEventListener('resize', this.onResizeCallback)
    }

    attachedCallback () {
      this.onResizeCallback()
    }

    detachedCallback () {
      this.mutationObserver.disconnect()
    }

    createLocalDom () {

      const grid = document.createElement('div')
      const canvas = document.createElement('canvas')
      grid.appendChild(canvas)

      Object.assign(this.style, {
        display: 'flex',
        flexDirection: 'column'
      })

      Object.assign(grid.style, {
        flex: 1,
        height: '100%'
      })

      return { grid, canvas }
    }

    /**
     * @public
     */
    resize() {
      this.onResizeCallback()
    }

    createPlot (context) {
      const data = {
        labels: [new Date()],
        datasets: []
      }
      const chart = new Chart(context, {
        type: 'line',
        data: data,
        options: plotOptions
      })
      return { data, chart }
    }

    createProxy (model) {
      const [_, devname, name] = model.match(/^(.+)\/([A-Za-z0-9_]+)$/)
      return new tangojs.core.api.AttributeProxy(devname, name)
    }

    readProxy (proxy) {
      return proxy.read()
    }

    onModelRead (deviceAttributes) {

      const readDate = (new Date()).getTime()

      this.plot.data.labels.push(readDate)
      this.trimDataset(this.plot.data.labels)

      Object.keys(deviceAttributes).forEach((model, i) => {
        const dataset = this.plot.data.datasets[i].data
        dataset.push({ x: readDate, y: deviceAttributes[model].value })
        this.trimDataset(dataset)
      })

      this.plot.chart.update()
    }

    trimDataset (dataset) {
      while (dataset.length > this.dataLimit) {
        dataset.shift()
      }
    }

    recreateDatasets (modelArray) {
      this.plot.data.datasets = modelArray.map(model => {
        return {
          label: model,
          data: [],
          fill: false,
          tension: 0.0,
          // metaData: undefined, // Chart.js bug ?
          borderColor: randomColor()
        }
      })
    }

  }

  window.tangojs.web.util.mixins.withPolledModel.call(
    TangoJsTrendElement.prototype)

  window.tangojs.web.util.mixins.withReflectedAttributes.call(
    TangoJsTrendElement.prototype,
    {
      model: {
        type: [Array, String],
        onChange: function (model) {
          if (!model) {
            return
          }
          this.onModelChange(model)
          this.recreateDatasets(model)
        }
      },
      pollPeriod: {
        type: 'number',
        defaultValue: 1000,
        onChange: TangoJsTrendElement.prototype.onPollPeriodChange
      },
      dataLimit: {
        type: 'number',
        defaultValue: 20
      }
    })

  window.tangojs.web.util.registerComponent(
    'tangojs-trend',
    TangoJsTrendElement,
    {
      capabilities: {
        attributeModel: true,
        commandModel: false,
        statusModel: false,
        readOnlyModel: true
      },
      attributes: {
        'model': { type: [Array, String] },
        'poll-period': { type: Number },
        'data-limit': { type: Number }
      }
    })

})(window)

</script>

</html>