text:
<merge  xmlns:android="http://schemas.android.com/apk/res/android"
    >
    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="@drawable/white_grey_border_bottom">

        <android.support.v7.widget.Toolbar
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/profileToolBar">

            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent">

                <ImageView
                    android:layout_width="25dp"
                    android:layout_height="25dp"
                    android:layout_marginEnd="20dp"
                    android:layout_centerVertical="true"
                    android:id="@+id/ivBackArrow"
                    android:src="@drawable/ic_backarrow"/>

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerVertical="true"
                    android:text="joshua_paul_marion"
                    android:textSize="20sp"
                    android:textColor="@color/black"
                    android:layout_marginStart="15dp"
                    android:id="@+id/username"
                    android:layout_toRightOf="@id/ivBackArrow"/>

            </RelativeLayout>

        </android.support.v7.widget.Toolbar>

    </android.support.design.widget.AppBarLayout>

</merge>


text:
use Irssi;
use Irssi::Irc;
use strict;
use vars qw($VERSION %IRSSI);
$VERSION = "1.0.0";
%IRSSI = (
	authors => "Timo 'cras' Sirainen, Leszek Matok",
	contact => "lam\@lac.pl",
	name => "autorejoin",
	description => "Automatically rejoin to channel after being kick, after a (short) user-defined delay",
	license => "GPLv2",
	changed => "10.3.2002 14:00"
);

# How many seconds to wait before the rejoin?
# TODO: make this a /setting
my $delay = 1;

my @tags;
my $acttag = 0;

sub rejoin {
	my ( $data ) = @_;
	my ( $tag, $servtag, $channel, $pass ) = split( / +/, $data );

	my $server = Irssi::server_find_tag( $servtag );
	$server->send_raw( "JOIN $channel $pass" ) if ( $server );
	Irssi::timeout_remove( $tags[$tag] );
}

sub event_rejoin_kick {
	my ( $server, $data ) = @_;
	my ( $channel, $nick ) = split( / +/, $data );

	return if ( $server->{ nick } ne $nick );

	# check if channel has password
	my $chanrec = $server->channel_find( $channel );
	my $password = $chanrec->{ key } if ( $chanrec );
	my $rejoinchan = $chanrec->{ name } if ( $chanrec );
	my $servtag = $server->{ tag };

	Irssi::print "Rejoining $rejoinchan in $delay seconds.";
	$tags[$acttag] = Irssi::timeout_add( $delay * 1000, "rejoin", "$acttag $servtag $rejoinchan $password" );
	$acttag++;
	$acttag = 0 if ( $acttag > 60 );
}

Irssi::signal_add( 'event kick', 'event_rejoin_kick' );

redpajama_set_name: RedPajamaGithub


text:
<?php

namespace MqSeries;

/**
 * QueueIsEmptyException
 *
 * @package MqSeries
 */
class QueueIsEmptyException extends \Exception
{

}


text:
#include <assert.h>
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <queue>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <thread>

#include "dbb.h"
#include "util.h"

#include "univalue.h"
#include "libbitpay-wallet-client/bpwalletclient.h"

#include "hidapi/hidapi.h"
#include "openssl/sha.h"
#include <openssl/err.h>
#include <openssl/rand.h>

#include <event2/event.h>
#include <event2/http.h>
#include <event2/buffer.h>
#include <event2/util.h>
#include <event2/keyvalq_struct.h>
#include <sys/signal.h>

#include "config/_dbb-config.h"

#ifdef DBB_ENABLE_QT
#include <QApplication>
#include <QPushButton>

#include "qt/dbbgui.h"

extern void doubleSha256(char* string, unsigned char* hashOut);

static DBBDaemonGui* widget;
#endif

std::condition_variable queueCondVar;
std::mutex cs_queue;

//TODO: migrate tuple to a class
typedef std::tuple<std::string, std::string, std::function<void(const std::string&)> > t_cmdCB;
std::queue<t_cmdCB> cmdQueue;
std::atomic<bool> stopThread;
std::atomic<bool> notified;

//executeCommand adds a command to the thread queue and notifies the tread to work down the queue
void executeCommand(const std::string& cmd, const std::string& password, std::function<void(const std::string&)> cmdFinished)
{
    std::unique_lock<std::mutex> lock(cs_queue);
    cmdQueue.push(t_cmdCB(cmd, password, cmdFinished));
    notified = true;
    queueCondVar.notify_one();
}

//simple function for the LED blick command
static void led_blink(struct evhttp_request* req, void* arg)
{
    printf("Received a request for %s\nDispatching dbb command\n", evhttp_request_get_uri(req));

    //dispatch command
    executeCommand("{\"led\" : \"toggle\"}", "0000", [](const std::string& cmdOut) {
    });

    //form a response, mind, no cmd result is available at this point, at the moment we don't block the http response thread
    struct evbuffer* out = evbuffer_new();
    evbuffer_add_printf(out, "Command dispatched\n");
    evhttp_send_reply(req, 200, "OK", out);
}

char uri_root[512];
int main(int argc, char** argv)
{
    struct event_base* base;
    struct evhttp* http;
    struct evhttp_bound_socket* handle;

    unsigned short port = 15520;

    if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
        return (1);

    base = event_base_new();
    if (!base) {
        fprintf(stderr, "Couldn't create an event_base: exiting\n");
        return 1;
    }

    http = evhttp_new(base);
    evhttp_set_cb(http, "/led/blink", led_blink, NULL);
    handle = evhttp_bind_socket_with_handle(http, "0.0.0.0", port);

    //TODO: factor out thread
    std::thread cmdThread([&]() {
        //TODO, the locking is to broad at the moment
        //  during executing a command the queue is locked
        //  and therefore no new commands can be added
        //  copy the command and callback and release the lock
        //  would be a solution

        std::unique_lock<std::mutex> lock(cs_queue);
        while (!stopThread) {
            while (!notified) {  // loop to avoid spurious wakeups
                queueCondVar.wait(lock);
            }
            while (!cmdQueue.empty()) {
                std::string cmdOut;
                t_cmdCB cmdCB = cmdQueue.front();
                std::string cmd = std::get<0>(cmdCB);
                std::string password = std::get<1>(cmdCB);

                if (!password.empty())
                {
                    std::string base64str;
                    std::string unencryptedJson;
                    try
                    {
                        DBB::encryptAndEncodeCommand(cmd, password, base64str);
                        if (!DBB::sendCommand(base64str, cmdOut))
                            unencryptedJson = "sending command failed";
                        else
                            DBB::decryptAndDecodeCommand(cmdOut, password, unencryptedJson);
                    }
                    catch (const std::exception& ex) {
                        unencryptedJson = "response decryption failed: "+cmdOut;
                    }

                    cmdOut = unencryptedJson;
                }
                else
                {
                    DBB::sendCommand(cmd, cmdOut);
                }
                std::get<2>(cmdCB)(cmdOut);
                cmdQueue.pop();
            }
            notified = false;
        }
    });

    //create a thread for the http handling
    std::thread usbCheckThread([&]() {
        while(1)
        {
            //check devices
            if (!DBB::isConnectionOpen())
            {
                if (DBB::openConnection())
                {
#ifdef DBB_ENABLE_QT
                //TODO, check if this requires locking
                if (widget)
                    widget->deviceStateHasChanged(true);
#endif
                }
                else
                {
#ifdef DBB_ENABLE_QT
                if (widget)
                    widget->deviceStateHasChanged(false);
#endif
                }
            }
            std::this_thread::sleep_for(std::chrono::milliseconds(1000));
        }
    });

    ECC_Start();

#ifdef DBB_ENABLE_QT
#if QT_VERSION > 0x050100
    // Generate high-dpi pixmaps
    QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#endif

    //create a thread for the http handling
    std::thread httpThread([&]() {
        event_base_dispatch(base);
    });

    QApplication app(argc, argv);

    widget = new DBBDaemonGui(0);
    widget->show();
    app.exec();
#else
    //directly start libevents main run loop
    event_base_dispatch(base);
#endif

    ECC_Stop();
    exit(1);
}


text:
table.versionInfo {
  table-layout: auto !important;
}

table.versionInfo th, table.versionInfo td {
  padding: 2px;
}

table.versionInfo th {
  text-align: center;
  font-weight: bold;
}


text:
package com.bv.eidss.model.generated;

import android.content.ContentValues;
import android.database.Cursor;
import android.os.Parcel;

import com.bv.eidss.R;
import com.bv.eidss.model.CaseStatus;
import com.bv.eidss.model.interfaces.IFieldChanged;
import com.bv.eidss.model.interfaces.ICallable;
import com.bv.eidss.model.interfaces.FieldMetadata;
import com.bv.eidss.utils.DateHelpers;
import com.bv.eidss.utils.EidssUtils;

import org.json.JSONException;
import org.json.JSONObject;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;

import java.io.IOException;
import java.text.Format;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.List;
import java.util.ArrayList;

public class Species_object {
    protected Boolean bChanged;
    public Boolean getChanged() { return bChanged; }

    protected IFieldChanged _fieldChangedHandler;
    public IFieldChanged getFieldChangedHandler() { return _fieldChangedHandler; }
    public void setFieldChangedHandler(IFieldChanged value) { _fieldChangedHandler = value; }

    public Species_object()
    {
        bChanged = false;
        _datCreateDate = DateHelpers.Today();
    }
  public static String eidss_SpeciesType = "VetCase.Species.SpeciesType";
  public static String eidss_TotalAnimalQty = "VetCase.Species.Total";
  public static String eidss_DeadAnimalQty = "VetCase.Species.Dead";
  public static String eidss_SickAnimalQty = "VetCase.Species.Sick";
  public static String eidss_Note = "VetCase.Species.strNote";
  public static String eidss_AverageAge = "VetCase.Species.strAverageAge";
  public static String eidss_StartOfSignsDate = "VetCase.Species.StartOfSign";

    public static List<FieldMetadata> fieldMetadata = new ArrayList<FieldMetadata>() {{{{
        add(new FieldMetadata(eidss_SpeciesType, R.string.Species_idfsSpeciesType, new ICallable<Long, Species_object>() { public Long call(Species_object t) { return t.getSpeciesType(); }}));
        add(new FieldMetadata(eidss_TotalAnimalQty, R.string.Species_intTotalAnimalQty, new ICallable<Integer, Species_object>() { public Integer call(Species_object t) { return t.getTotalAnimalQty(); }}));
        add(new FieldMetadata(eidss_DeadAnimalQty, R.string.Species_intDeadAnimalQty, new ICallable<Integer, Species_object>() { public Integer call(Species_object t) { return t.getDeadAnimalQty(); }}));
        add(new FieldMetadata(eidss_SickAnimalQty, R.string.Species_intSickAnimalQty, new ICallable<Integer, Species_object>() { public Integer call(Species_object t) { return t.getSickAnimalQty(); }}));
        add(new FieldMetadata(eidss_Note, R.string.Species_strNote, new ICallable<String, Species_object>() { public String call(Species_object t) { return t.getNote(); }}));
        add(new FieldMetadata(eidss_AverageAge, R.string.Species_intAverageAge, new ICallable<Integer, Species_object>() { public Integer call(Species_object t) { return t.getAverageAge(); }}));
        add(new FieldMetadata(eidss_StartOfSignsDate, R.string.Species_datStartOfSignsDate, new ICallable<Date, Species_object>() { public Date call(Species_object t) { return t.getStartOfSignsDate(); }}));
    }}}};

    // system fields
    protected long _id;
    public long getId() { return _id; }
    public void setId(long value) { _id = value; }
    protected String _strLastSynError;
    public String getLastSynError() { return _strLastSynError; }
    public void setLastSynError(String value) { _strLastSynError = value; }
    protected int _intStatus; //  1 - new; 2 - synchronized; 3 - changed; 4 - unloaded;
    public int getStatus() { return _intStatus; }
    public void setStatusChanged() { _intStatus = CaseStatus.CHANGED; }
    public void setStatusSyn() { _intStatus = CaseStatus.SYNCHRONIZED; }
    public void setStatusUploaded() { _intStatus = CaseStatus.UNLOADED; }
    protected int _intChanged; //  0 - not; 1 - yes;
    public void clearChanged() { _intChanged = 0; }
    protected Date _datCreateDate;
    public Date getCreateDate() { return _datCreateDate; }

//fields
  protected long _idParent;
  public long getParent(){return _idParent;}
   public void setParent(long value) { bChanged = bChanged || _idParent != value; _intChanged = ((_intChanged == 1) || _idParent != value) ? 1 : 0; if (_idParent != value) { if (_fieldChangedHandler != null) { _fieldChangedHandler.FieldChanged("idParent", _idParent, value); } _idParent = value; }}
  protected long _idfsFormTemplate;
  public long getFormTemplate(){return _idfsFormTemplate;}
   public void setFormTemplate(long value) { bChanged = bChanged || _idfsFormTemplate != value; _intChanged = ((_intChanged == 1) || _idfsFormTemplate != value) ? 1 : 0; if (_idfsFormTemplate != value) { if (_fieldChangedHandler != null) { _fieldChangedHandler.FieldChanged("idfsFormTemplate", _idfsFormTemplate, value); } _idfsFormTemplate = value; }}
  protected long _idfObservation;
  public long getObservation(){return _idfObservation;}
   public void setObservation(long value) { bChanged = bChanged || _idfObservation != value; _intChanged = ((_intChanged == 1) || _idfObservation != value) ? 1 : 0; if (_idfObservation != value) { if (_fieldChangedHandler != null) { _fieldChangedHandler.FieldChanged("idfObservation", _idfObservation, value); } _idfObservation = value; }}
  protected long _idfsSpeciesType;
  public long getSpeciesType(){return _idfsSpeciesType;}
   public void setSpeciesType(long value) { bChanged = bChanged || _idfsSpeciesType != value; _intChanged = ((_intChanged == 1) || _idfsSpeciesType != value) ? 1 : 0; if (_idfsSpeciesType != value) { if (_fieldChangedHandler != null) { _fieldChangedHandler.FieldChanged("idfsSpeciesType", _idfsSpeciesType, value); } _idfsSpeciesType = value; }}
  protected int _intTotalAnimalQty;
  public int getTotalAnimalQty(){return _intTotalAnimalQty;}
   public void setTotalAnimalQty(int value) { bChanged = bChanged || _intTotalAnimalQty != value; _intChanged = ((_intChanged == 1) || _intTotalAnimalQty != value) ? 1 : 0; if (_intTotalAnimalQty != value) { if (_fieldChangedHandler != null) { _fieldChangedHandler.FieldChanged("intTotalAnimalQty", _intTotalAnimalQty, value); } _intTotalAnimalQty = value; }}
  protected int _intDeadAnimalQty;
  public int getDeadAnimalQty(){return _intDeadAnimalQty;}
   public void setDeadAnimalQty(int value) { bChanged = bChanged || _intDeadAnimalQty != value; _intChanged = ((_intChanged == 1) || _intDeadAnimalQty != value) ? 1 : 0; if (_intDeadAnimalQty != value) { if (_fieldChangedHandler != null) { _fieldChangedHandler.FieldChanged("intDeadAnimalQty", _intDeadAnimalQty, value); } _intDeadAnimalQty = value; }}
  protected int _intSickAnimalQty;
  public int getSickAnimalQty(){return _intSickAnimalQty;}
   public void setSickAnimalQty(int value) { bChanged = bChanged || _intSickAnimalQty != value; _intChanged = ((_intChanged == 1) || _intSickAnimalQty != value) ? 1 : 0; if (_intSickAnimalQty != value) { if (_fieldChangedHandler != null) { _fieldChangedHandler.FieldChanged("intSickAnimalQty", _intSickAnimalQty, value); } _intSickAnimalQty = value; }}
  protected String _strNote;
  public String getNote(){return _strNote;}
   public void setNote(String value) { if(_strNote == null && value == null) return; bChanged = bChanged || _strNote == null || value == null || !_strNote.equals(value); _intChanged = ((_intChanged == 1) || _strNote == null || value == null || !_strNote.equals(value)) ? 1 : 0; if (_strNote == null || value == null || !_strNote.equals(value)) { if (_fieldChangedHandler != null) { _fieldChangedHandler.FieldChanged("strNote", _strNote, value); } _strNote = value; }}
  protected int _intAverageAge;
  public int getAverageAge(){return _intAverageAge;}
   public void setAverageAge(int value) { bChanged = bChanged || _intAverageAge != value; _intChanged = ((_intChanged == 1) || _intAverageAge != value) ? 1 : 0; if (_intAverageAge != value) { if (_fieldChangedHandler != null) { _fieldChangedHandler.FieldChanged("intAverageAge", _intAverageAge, value); } _intAverageAge = value; }}
  protected Date _datStartOfSignsDate;
  public Date getStartOfSignsDate(){return _datStartOfSignsDate;}
   public void setStartOfSignsDate(Date value) { if(_datStartOfSignsDate == null && value == null) return; bChanged = bChanged || _datStartOfSignsDate == null || value == null || !_datStartOfSignsDate.equals(value); _intChanged = ((_intChanged == 1) || _datStartOfSignsDate == null || value == null || !_datStartOfSignsDate.equals(value)) ? 1 : 0; if (_datStartOfSignsDate == null || value == null || !_datStartOfSignsDate.equals(value)) { if (_fieldChangedHandler != null) { _fieldChangedHandler.FieldChanged("datStartOfSignsDate", _datStartOfSignsDate, value); } _datStartOfSignsDate = value; }}

protected static Species_object FromCursor(Cursor cursor, Species_object ret)
{

Format formatterDateTime = DateHelpers.getDateTimeFormatter();
Format formatterDate = DateHelpers.getDateFormatter();

try {
    ret._id = cursor.getLong(cursor.getColumnIndex("id"));
    ret._strLastSynError = cursor.getString(cursor.getColumnIndex("strLastSynError"));
    ret._intStatus = cursor.getInt(cursor.getColumnIndex("intStatus"));
    ret._intChanged = cursor.getInt(cursor.getColumnIndex("intChanged"));
    String strDate = cursor.getString(cursor.getColumnIndex("datCreateDate"));
    if (strDate != null) ret._datCreateDate = (Date)formatterDateTime.parseObject(strDate);
  ret._idParent = cursor.getLong(cursor.getColumnIndex("idParent"));
  ret._idfsFormTemplate = cursor.getLong(cursor.getColumnIndex("idfsFormTemplate"));
  ret._idfObservation = cursor.getLong(cursor.getColumnIndex("idfObservation"));
  ret._idfsSpeciesType = cursor.getLong(cursor.getColumnIndex("idfsSpeciesType"));
  ret._intTotalAnimalQty = cursor.getInt(cursor.getColumnIndex("intTotalAnimalQty"));
  ret._intDeadAnimalQty = cursor.getInt(cursor.getColumnIndex("intDeadAnimalQty"));
  ret._intSickAnimalQty = cursor.getInt(cursor.getColumnIndex("intSickAnimalQty"));
  ret._strNote = cursor.getString(cursor.getColumnIndex("strNote"));
  ret._intAverageAge = cursor.getInt(cursor.getColumnIndex("intAverageAge"));
  ret._datStartOfSignsDate = EidssUtils.ParseDate(cursor, formatterDate, "datStartOfSignsDate");
    ret.bChanged = false;
}
catch (ParseException e)
{
    e.printStackTrace();
    return ret;
}
return ret;
}

protected ContentValues ContentValuesInternal()
{
    String strDate = null;
    ContentValues ret = new ContentValues();
    Format formatterDateTime = DateHelpers.getDateTimeFormatter();
    Format formatterDate = DateHelpers.getDateFormatter();
    if (_id != 0)
        ret.put("id", _id);
    ret.put("strLastSynError", _strLastSynError);
    ret.put("intStatus", _intStatus);
    ret.put("intChanged", _intChanged);
    if (_datCreateDate != null)
        strDate = formatterDateTime.format(_datCreateDate);
    ret.put("datCreateDate", strDate);
    strDate = null;
  ret.put("idParent", _idParent);
  ret.put("idfsFormTemplate", _idfsFormTemplate);
  ret.put("idfObservation", _idfObservation);
  ret.put("idfsSpeciesType", _idfsSpeciesType);
  ret.put("intTotalAnimalQty", _intTotalAnimalQty);
  ret.put("intDeadAnimalQty", _intDeadAnimalQty);
  ret.put("intSickAnimalQty", _intSickAnimalQty);
  ret.put("strNote", _strNote);
  ret.put("intAverageAge", _intAverageAge);
    strDate = null;
  if (_datStartOfSignsDate != null)
      strDate = formatterDate.format(_datStartOfSignsDate);
  ret.put("datStartOfSignsDate", strDate);

return ret;
}

protected void FromParcel(Parcel source)
{
    _id = source.readLong();
    _strLastSynError = source.readString();
    _intStatus = source.readInt();
    _intChanged = source.readInt();
    _datCreateDate = (Date)source.readSerializable();
  _idParent = source.readLong();
  _idfsFormTemplate = source.readLong();
  _idfObservation = source.readLong();
  _idfsSpeciesType = source.readLong();
  _intTotalAnimalQty = source.readInt();
  _intDeadAnimalQty = source.readInt();
  _intSickAnimalQty = source.readInt();
  _strNote = source.readString();
  _intAverageAge = source.readInt();
  _datStartOfSignsDate = (Date)source.readSerializable();
    bChanged = source.readInt() == 1;
}
protected void ToParcel(Parcel dest, int flag)
{
  dest.writeLong(_id);
  dest.writeString(_strLastSynError);
  dest.writeInt(_intStatus);
  dest.writeInt(_intChanged);
  dest.writeSerializable(_datCreateDate);
  dest.writeLong(_idParent);
  dest.writeLong(_idfsFormTemplate);
  dest.writeLong(_idfObservation);
  dest.writeLong(_idfsSpeciesType);
  dest.writeInt(_intTotalAnimalQty);
  dest.writeInt(_intDeadAnimalQty);
  dest.writeInt(_intSickAnimalQty);
  dest.writeString(_strNote);
  dest.writeInt(_intAverageAge);
  dest.writeSerializable(_datStartOfSignsDate);
  dest.writeInt(bChanged ? 1 : 0);
}

protected void ToXml(XmlSerializer serializer) throws IllegalArgumentException, IllegalStateException, IOException
{
serializer.attribute("", "lang", EidssUtils.getCurrentLanguage());
serializer.attribute("", "intChanged", String.valueOf(_intChanged));
  if (_idParent != 0)
      serializer.attribute("", "idParent", String.valueOf(_idParent));
  if (_idfsFormTemplate != 0)
      serializer.attribute("", "idfsFormTemplate", String.valueOf(_idfsFormTemplate));
  if (_idfObservation != 0)
      serializer.attribute("", "idfObservation", String.valueOf(_idfObservation));
  if (_idfsSpeciesType != 0)
      serializer.attribute("", "idfsSpeciesType", String.valueOf(_idfsSpeciesType));
  if (_intTotalAnimalQty != 0)
      serializer.attribute("", "intTotalAnimalQty", String.valueOf(_intTotalAnimalQty));
  if (_intDeadAnimalQty != 0)
      serializer.attribute("", "intDeadAnimalQty", String.valueOf(_intDeadAnimalQty));
  if (_intSickAnimalQty != 0)
      serializer.attribute("", "intSickAnimalQty", String.valueOf(_intSickAnimalQty));
  if (_strNote != null)
      serializer.attribute("", "strNote", _strNote);
  if (_intAverageAge != 0)
      serializer.attribute("", "intAverageAge", String.valueOf(_intAverageAge));
  if (_datStartOfSignsDate != null)
      serializer.attribute("", "datStartOfSignsDate", DateHelpers.FormatWithT(_datStartOfSignsDate));
}

public JSONObject ToJson() throws JSONException
{
JSONObject ret = new JSONObject();
EidssUtils.putToJson(ret, "lang", EidssUtils.getCurrentLanguage());
EidssUtils.putToJson(ret, "intChanged", _intChanged);
  EidssUtils.putToJson(ret, "idParent", _idParent);
  EidssUtils.putToJson(ret, "idfsFormTemplate", _idfsFormTemplate);
  EidssUtils.putToJson(ret, "idfObservation", _idfObservation);
  EidssUtils.putToJson(ret, "idfsSpeciesType", _idfsSpeciesType);
  EidssUtils.putToJson(ret, "intTotalAnimalQty", _intTotalAnimalQty);
  EidssUtils.putToJson(ret, "intDeadAnimalQty", _intDeadAnimalQty);
  EidssUtils.putToJson(ret, "intSickAnimalQty", _intSickAnimalQty);
  EidssUtils.putToJson(ret, "strNote", _strNote);
  EidssUtils.putToJson(ret, "intAverageAge", _intAverageAge);
  EidssUtils.putToJson(ret, "datStartOfSignsDate", _datStartOfSignsDate);
return ret;
}

public void FromJson(JSONObject json) throws JSONException, ParseException
{
  _idParent = json.getLong("idParent");
  _idfsFormTemplate = json.getLong("idfsFormTemplate");
  _idfObservation = json.getLong("idfObservation");
  _idfsSpeciesType = json.getLong("idfsSpeciesType");
  _intTotalAnimalQty = json.getInt("intTotalAnimalQty");
  _intDeadAnimalQty = json.getInt("intDeadAnimalQty");
  _intSickAnimalQty = json.getInt("intSickAnimalQty");
  _strNote = json.getString("strNote");
  _intAverageAge = json.getInt("intAverageAge");
  _datStartOfSignsDate = DateHelpers.ParseWithT(json.getString("datStartOfSignsDate"));
}
public void FromXml(XmlPullParser parser) throws ParseException
{
  _idParent = parser.getAttributeValue("", "idParent") == null ? 0 : Long.getLong(parser.getAttributeValue("", "idParent"));
  _idfsFormTemplate = parser.getAttributeValue("", "idfsFormTemplate") == null ? 0 : Long.getLong(parser.getAttributeValue("", "idfsFormTemplate"));
  _idfObservation = parser.getAttributeValue("", "idfObservation") == null ? 0 : Long.getLong(parser.getAttributeValue("", "idfObservation"));
  _idfsSpeciesType = parser.getAttributeValue("", "idfsSpeciesType") == null ? 0 : Long.getLong(parser.getAttributeValue("", "idfsSpeciesType"));
  _intTotalAnimalQty = parser.getAttributeValue("", "intTotalAnimalQty") == null ? 0 : Integer.getInteger(parser.getAttributeValue("", "intTotalAnimalQty"));
  _intDeadAnimalQty = parser.getAttributeValue("", "intDeadAnimalQty") == null ? 0 : Integer.getInteger(parser.getAttributeValue("", "intDeadAnimalQty"));
  _intSickAnimalQty = parser.getAttributeValue("", "intSickAnimalQty") == null ? 0 : Integer.getInteger(parser.getAttributeValue("", "intSickAnimalQty"));
  _strNote = parser.getAttributeValue("", "strNote");
  _intAverageAge = parser.getAttributeValue("", "intAverageAge") == null ? 0 : Integer.getInteger(parser.getAttributeValue("", "intAverageAge"));
  _datStartOfSignsDate = DateHelpers.ParseWithT(parser.getAttributeValue("", "datStartOfSignsDate"));
}
}


text:
/* Author: Ryan Luna */

#define BOOST_TEST_MODULE "PlannerDataControl"
#include <boost/test/unit_test.hpp>
#include <boost/serialization/export.hpp>
#include <iostream>
#include <vector>

#include "ompl/control/PlannerData.h"
#include "ompl/control/PlannerDataStorage.h"
#include "ompl/base/spaces/RealVectorStateSpace.h"
#include "ompl/control/spaces/RealVectorControlSpace.h"
#include "../BoostTestTeamCityReporter.h"

using namespace ompl;

// define a convenience macro
#define BOOST_OMPL_EXPECT_NEAR(a, b, diff) BOOST_CHECK_SMALL((a) - (b), diff)

// Define the state and control spaces used throughout the testing
#define SETUP_STATE_CONTROL_SPACES \
base::StateSpacePtr space(new base::RealVectorStateSpace(1)); \
control::ControlSpacePtr cspace (new control::RealVectorControlSpace(space, 2)); \
base::RealVectorBounds spacebounds(1); \
spacebounds.setLow(-10); \
spacebounds.setHigh(10); \
base::RealVectorBounds ctrlbounds(2); \
ctrlbounds.setLow(-1); \
ctrlbounds.setHigh(1); \
space->as<base::RealVectorStateSpace>()->setBounds(spacebounds); \
cspace->as<control::RealVectorControlSpace>()->setBounds(ctrlbounds); \
control::SpaceInformationPtr si(new control::SpaceInformation(space, cspace)); \
si->setStateValidityChecker(isValid); \
si->setStatePropagator(propagate); \
si->setMinMaxControlDuration(1, 10); \
si->setPropagationStepSize(1); \
si->setup();

class PlannerDataTestVertex : public ompl::base::PlannerDataVertex
{
public:
    PlannerDataTestVertex (base::State* st, int tag = 0, int tag2 = 0) : ompl::base::PlannerDataVertex(st, tag), tag2_(tag2) {}
    PlannerDataTestVertex (const PlannerDataTestVertex &rhs) : ompl::base::PlannerDataVertex(rhs.state_, rhs.tag_), tag2_(rhs.tag2_) {}

    virtual ompl::base::PlannerDataVertex* clone (void) const
    {
        return static_cast<ompl::base::PlannerDataVertex*>(new PlannerDataTestVertex(*this));
    }

    int tag2_;

protected:
    PlannerDataTestVertex(void) {}

    friend class boost::serialization::access;
    template <class Archive>
    void serialize(Archive & ar, const unsigned int /*version*/)
    {
        ar & boost::serialization::base_object<ompl::base::PlannerDataVertex>(*this);
        ar & tag2_;
    }
};

class PlannerDataTestEdge : public ompl::control::PlannerDataEdgeControl
{
public:
    PlannerDataTestEdge(const control::Control *c, double duration, int id) : PlannerDataEdgeControl(c, duration), id_(id) {}

    PlannerDataTestEdge (const PlannerDataTestEdge &rhs) : PlannerDataEdgeControl(rhs.c_, rhs.duration_), id_(rhs.id_)  {}

    virtual ~PlannerDataTestEdge (void) {}

    virtual ompl::base::PlannerDataEdge* clone () const
    {
        return static_cast<base::PlannerDataEdge*>(new PlannerDataTestEdge(*this));
    }

    virtual bool operator == (const ompl::base::PlannerDataEdge &rhs) const
    {
        const PlannerDataTestEdge *rhst = static_cast<const PlannerDataTestEdge*> (&rhs);
        if (rhst)
        {
            if (id_ == rhst->id_)
                return static_cast<const ompl::control::PlannerDataEdgeControl>(*this) == rhs;
        }

        return false;
    }

    int id_;

protected:
    PlannerDataTestEdge() : PlannerDataEdgeControl() {};
    friend class boost::serialization::access;

    template <class Archive>
    void serialize(Archive & ar, const unsigned int /*version*/)
    {
        ar & boost::serialization::base_object<ompl::control::PlannerDataEdgeControl>(*this);
        ar & id_;
    }
};

// This allows us to serialize the derived vertex and edge classes
BOOST_CLASS_EXPORT(PlannerDataTestVertex);
BOOST_CLASS_EXPORT(PlannerDataTestEdge);

void propagate(const base::State *, const control::Control *, const double, base::State *){}
bool isValid (const base::State*){ return true; }

BOOST_AUTO_TEST_CASE(SimpleConstruction)
{
    SETUP_STATE_CONTROL_SPACES

    control::PlannerData data(si);
    std::vector<base::State*> states;
    std::vector<control::Control*> controls;
    base::StateSamplerPtr stsamp = space->allocDefaultStateSampler();
    control::ControlSamplerPtr csamp = cspace->allocDefaultControlSampler();

    // Creating 1000 states and controls
    for (unsigned int i = 0; i < 1000; ++i)
    {
        states.push_back(space->allocState());
        stsamp->sampleUniform(states[i]);
        controls.push_back(cspace->allocControl());
        csamp->sample(controls[i]);
    }

    // Adding vertices
    for (unsigned int i = 0; i < states.size(); ++i)
    {
        unsigned int vtx = data.addVertex(PlannerDataTestVertex(states[i], (signed)i, (signed)i+1));

        BOOST_CHECK_NE( vtx, base::PlannerData::INVALID_INDEX );
        BOOST_CHECK_EQUAL( data.addVertex(PlannerDataTestVertex(states[i])), vtx );

        BOOST_CHECK_EQUAL( data.vertexIndex(PlannerDataTestVertex(states[i])), i );
        BOOST_CHECK( data.vertexExists(PlannerDataTestVertex(states[i])) );
    }

    // We should have #states vertices and 0 edges
    BOOST_CHECK_EQUAL( data.numVertices(), states.size() );
    BOOST_CHECK_EQUAL( data.numEdges(), 0u );

    // Adding edges
    for (unsigned int i = 0; i < states.size()-1; ++i)
    {
        BOOST_CHECK( data.addEdge(i, i+1, PlannerDataTestEdge(controls[i], (double)i, (double)i)) );
        BOOST_CHECK_EQUAL( data.addEdge(i, states.size()), false ); // vertex #states.size() does not exist

        BOOST_CHECK( data.edgeExists(i, i+1) );
    }

    for (unsigned int i = 1; i < states.size(); ++i)
    {
        std::vector<unsigned int> neighbors;
        BOOST_REQUIRE_EQUAL( data.getIncomingEdges(i, neighbors), 1u );
        BOOST_CHECK_EQUAL( neighbors[0], i-1 );
    }

    // We should have #states vertices and #states-1 edges at this point
    BOOST_CHECK_EQUAL( data.numVertices(), states.size() );
    BOOST_CHECK_EQUAL( data.numEdges(), states.size()-1);

    // Make sure our edges are where we think they are
    for (unsigned int i = 0; i < states.size()-1; ++i)
    {
        std::vector<unsigned int> neighbors;
        BOOST_REQUIRE_EQUAL( data.getEdges(i, neighbors), 1u );
        BOOST_CHECK_EQUAL( neighbors[0], i+1 );
    }

    std::vector<unsigned int> neighbors;
    BOOST_CHECK_EQUAL( data.getEdges(states.size()-1, neighbors), 0u );

    // Make sure that the vertices can be retrived properly
    for (unsigned int i = 0; i < states.size(); ++i)
    {
        BOOST_CHECK_EQUAL( data.getVertex(i).getState(), states[i] );
        BOOST_CHECK_EQUAL( data.getVertex(i).getTag(), (signed)i );
    }

    for (size_t i = 0; i < states.size(); ++i)
    {
        space->freeState(states[i]);
        cspace->freeControl(controls[i]);
    }
}

BOOST_AUTO_TEST_CASE(AdvancedConstruction)
{
    SETUP_STATE_CONTROL_SPACES

    control::PlannerData data(si);
    std::vector<base::State*> states;
    std::vector<control::Control*> controls;
    base::StateSamplerPtr stsamp = space->allocDefaultStateSampler();
    control::ControlSamplerPtr csamp = cspace->allocDefaultControlSampler();

    // Creating 1000 states
    for (unsigned int i = 0; i < 1000; ++i)
    {
        states.push_back(space->allocState());
        stsamp->sampleUniform(states[i]);
        controls.push_back(cspace->allocControl());
        csamp->sample(controls[i]);
    }

    // Adding vertices and edges simultaneously
    for (unsigned int i = 0; i < states.size()-1; ++i)
    {
        BOOST_CHECK( data.addEdge (PlannerDataTestVertex(states[i], (signed)i),
                                   PlannerDataTestVertex(states[i+1], (signed)i+1),
                                   PlannerDataTestEdge(controls[i], (double)i, (double)i)) );

        // Duplicates are not allowed
        BOOST_CHECK_EQUAL( data.addEdge (PlannerDataTestVertex(states[i], (signed)i),
                                         PlannerDataTestVertex(states[i+1], (signed)i+1),
                                         PlannerDataTestEdge(controls[i], (double)i, (double)i)), false );

        BOOST_CHECK( data.edgeExists (i, i+1) );

        BOOST_CHECK_EQUAL( data.vertexIndex(PlannerDataTestVertex(states[i])), i );
        BOOST_CHECK( data.vertexExists(PlannerDataTestVertex(states[i])) );
    }

    // Adding two start states and two goal states
    BOOST_CHECK_EQUAL( data.addStartVertex (PlannerDataTestVertex(states[states.size()-4])), states.size()-4 );
    BOOST_CHECK_EQUAL( data.addGoalVertex (PlannerDataTestVertex(states[states.size()-3])),  states.size()-3 );
    BOOST_CHECK_EQUAL( data.addStartVertex (PlannerDataTestVertex(states[states.size()-2])), states.size()-2 );
    BOOST_CHECK_EQUAL( data.addGoalVertex (PlannerDataTestVertex(states[states.size()-1])),  states.size()-1 );

    BOOST_CHECK_EQUAL( data.numStartVertices(), 2u );
    BOOST_CHECK_EQUAL( data.numGoalVertices (), 2u );
    BOOST_CHECK_EQUAL( data.getStartIndex(0), states.size()-4 );
    BOOST_CHECK_EQUAL( data.getStartIndex(1), states.size()-2 );
    BOOST_CHECK_EQUAL( data.getStartIndex(2), base::PlannerData::INVALID_INDEX );
    BOOST_CHECK_EQUAL( data.getGoalIndex(0), states.size()-3 );
    BOOST_CHECK_EQUAL( data.getGoalIndex(1), states.size()-1 );
    BOOST_CHECK_EQUAL( data.getGoalIndex(2), base::PlannerData::INVALID_INDEX );

    // Make sure that the start and goal indices are where we think they are
    for (unsigned int i = 0; i < states.size(); ++i)
    {
        if (i < states.size()-4)
        {
            BOOST_CHECK_EQUAL( data.isStartVertex(i), false );
            BOOST_CHECK_EQUAL( data.isGoalVertex(i), false );
        }
        else if (i == states.size()-4 || i == states.size()-2)
        {
            BOOST_CHECK_EQUAL( data.isStartVertex(i), true );
            BOOST_CHECK_EQUAL( data.isGoalVertex(i), false );
        }
        else if (i == states.size()-3 || i == states.size()-1)
        {
            BOOST_CHECK_EQUAL( data.isStartVertex(i), false );
            BOOST_CHECK_EQUAL( data.isGoalVertex(i), true );
        }
    }

    // We should have #states vertices and #states-1 edges
    BOOST_CHECK_EQUAL( data.numVertices(), states.size() );
    BOOST_CHECK_EQUAL( data.numEdges(), states.size()-1 );

    // Make sure our edges are where we think they are
    for (unsigned int i = 0; i < states.size()-1; ++i)
    {
        std::vector<unsigned int> nbrs;
        BOOST_CHECK_EQUAL( data.getEdges(i, nbrs), 1u );
        BOOST_CHECK_EQUAL( nbrs[0], i+1 );
    }

    for (unsigned int i = 1; i < states.size(); ++i)
    {
        std::vector<unsigned int> neighbors;
        BOOST_REQUIRE_EQUAL( data.getIncomingEdges(i, neighbors), 1u );
        BOOST_CHECK_EQUAL( neighbors[0], i-1 );
    }

    std::vector<unsigned int> nbrs;
    BOOST_CHECK_EQUAL( data.getEdges(states.size()-1, nbrs), 0u );

    // Make sure that the vertices can be retrived properly
    for (unsigned int i = 0; i < states.size(); ++i)
    {
        BOOST_CHECK_EQUAL(data.getVertex(i).getState(), states[i]);
        BOOST_CHECK_EQUAL(data.getVertex(i).getTag(), (signed)i);
    }

    for (size_t i = 0; i < states.size(); ++i)
    {
        space->freeState(states[i]);
        cspace->freeControl(controls[i]);
    }
}

BOOST_AUTO_TEST_CASE(DataIntegrity)
{
    SETUP_STATE_CONTROL_SPACES

    control::PlannerData data(si);
    std::vector<base::State*> states;
    std::vector<control::Control*> controls;
    base::StateSamplerPtr stsamp = space->allocDefaultStateSampler();
    control::ControlSamplerPtr csamp = cspace->allocDefaultControlSampler();

    // Creating 1000 states
    for (unsigned int i = 0; i < 1000; ++i)
    {
        states.push_back(space->allocState());
        stsamp->sampleUniform(states[i]);
        controls.push_back(cspace->allocControl());
        csamp->sample(controls[i]);
    }

    // Adding vertices and edges simultaneously
    for (unsigned int i = 1; i < states.size(); ++i)
    {
        BOOST_CHECK( data.addEdge (PlannerDataTestVertex(states[i-1], i, i+1),
                                   PlannerDataTestVertex(states[i], i+1, i+2),
                                   PlannerDataTestEdge(controls[i], i, i+1)) );
    }

    // We should have #states vertices and #states-1 edges
    BOOST_CHECK_EQUAL( data.numVertices(), states.size() );
    BOOST_CHECK_EQUAL( data.numEdges(), states.size()-1 );

    // Attempt to retrieve some vertices
    BOOST_CHECK_NE( &data.getVertex(0), &base::PlannerData::NO_VERTEX );
    BOOST_CHECK_NE( &data.getVertex(3), &base::PlannerData::NO_VERTEX );
    BOOST_CHECK_EQUAL( &data.getVertex(states.size()), &base::PlannerData::NO_VERTEX ); // vertex #states.size() does not exist

    // Attempt to retrieve some edges
    BOOST_CHECK_NE( &data.getEdge(0, 1), &base::PlannerData::NO_EDGE );
    BOOST_CHECK_NE( &data.getEdge(4, 5), &base::PlannerData::NO_EDGE );
    BOOST_CHECK_EQUAL( &data.getEdge(0, states.size()), &base::PlannerData::NO_EDGE ); // edge does not exist

    // Ensure vertex data integrity
    for (unsigned int i = 0; i < states.size(); ++i)
        BOOST_CHECK_EQUAL( data.getVertex(i).getState()->as<base::RealVectorStateSpace::StateType>()->values[0], states[i]->as<base::RealVectorStateSpace::StateType>()->values[0] );

    // Ensure edge data integrity
    for (unsigned int i = 1; i < states.size(); ++i)
    {
        //TestEdge& edge = static_cast<TestEdge&>(data.getEdge(i-1, i));
        PlannerDataTestEdge &edge = static_cast<PlannerDataTestEdge&>(data.getEdge(i-1, i));
        BOOST_REQUIRE_NE ( &edge, &base::PlannerData::NO_EDGE );
        BOOST_CHECK_EQUAL( edge.getControl(), controls[i] );
        BOOST_OMPL_EXPECT_NEAR ( edge.getDuration(), i, 1e-9 );
        BOOST_CHECK_EQUAL ( edge.id_, i+1 );
    }

    // Reset the tag for state #0
    BOOST_CHECK( data.tagState(states[0], 10000) );
    BOOST_CHECK_EQUAL( data.getVertex(0).getTag(), 10000 );
    BOOST_CHECK_EQUAL( data.tagState(0, 1000), false ); // state doesn't exist

    // Reset the edge weight for 0->1
    BOOST_CHECK( data.setEdgeWeight(0, 1, base::Cost(1.234)) );

    base::Cost w;
    BOOST_CHECK(data.getEdgeWeight(0, 1, &w));
    BOOST_OMPL_EXPECT_NEAR(w.value(), 1.234, 1e-4);

    BOOST_CHECK_EQUAL( data.getEdgeWeight(0, 5, &w), false ); // edge does not exist
    BOOST_CHECK_EQUAL( data.setEdgeWeight(0, 5, base::Cost(2.345)), false );

    // Try to tag an invalid state
    BOOST_CHECK_EQUAL( data.tagState(0, 100), false );

    for (size_t i = 0; i < states.size(); ++i)
    {
        space->freeState(states[i]);
        cspace->freeControl(controls[i]);
    }
}

BOOST_AUTO_TEST_CASE(AddRemoveVerticesAndEdges)
{
    SETUP_STATE_CONTROL_SPACES

    control::PlannerData data(si);
    std::vector<base::State*> states;
    std::vector<control::Control*> controls;
    base::StateSamplerPtr stsamp = space->allocDefaultStateSampler();
    control::ControlSamplerPtr csamp = cspace->allocDefaultControlSampler();

    // Creating 1000 states
    for (unsigned int i = 0; i < 1000; ++i)
    {
        states.push_back(space->allocState());
        stsamp->sampleUniform(states[i]);
        controls.push_back(cspace->allocControl());
        csamp->sample(controls[i]);
    }

    // Adding vertices and edges
    for (unsigned int i = 1; i < states.size(); ++i)
    {
        BOOST_CHECK( data.addEdge (PlannerDataTestVertex(states[i-1], i, i+1),
                                   PlannerDataTestVertex(states[i], i+1, i+2),
                                   PlannerDataTestEdge(controls[i], i, i+1)) );
    }

    BOOST_CHECK_EQUAL( data.numVertices(), states.size() );
    BOOST_CHECK_EQUAL( data.numEdges(), states.size()-1 );

    BOOST_CHECK( data.removeVertex(PlannerDataTestVertex(states[states.size()-1], states.size()-1, states.size())) );
    BOOST_CHECK_EQUAL( data.numVertices(), states.size()-1 );
    BOOST_CHECK_EQUAL( data.numEdges(), states.size()-2 );

    BOOST_CHECK_EQUAL( data.removeVertex(PlannerDataTestVertex(states[states.size()-1], states.size()-1, states.size())), false ); // we already removed this vertex
    BOOST_CHECK_EQUAL( data.numVertices(), states.size()-1 );
    BOOST_CHECK_EQUAL( data.numEdges(), states.size()-2 );

    BOOST_CHECK_EQUAL( data.removeVertex(states.size()), false ); // vertex does not exist
    BOOST_CHECK_EQUAL( data.numVertices(), states.size()-1 );
    BOOST_CHECK_EQUAL( data.numEdges(), states.size()-2 );

    BOOST_CHECK( data.removeVertex(6) );
    BOOST_CHECK_EQUAL( data.numVertices(), states.size()-2 );
    BOOST_CHECK_EQUAL( data.numEdges(), states.size()-4 );  // incoming edge and outgoing edge should be removed

    BOOST_CHECK( data.removeEdge(PlannerDataTestVertex(states[1], 1, 2), PlannerDataTestVertex(states[2], 2, 3)) );
    BOOST_CHECK_EQUAL( data.numVertices(), states.size()-2 );
    BOOST_CHECK_EQUAL( data.numEdges(), states.size()-5 );

    BOOST_CHECK_EQUAL( data.removeEdge(PlannerDataTestVertex(states[1], 1, 2), PlannerDataTestVertex(states[2], 2, 3)), false ); // we just removed this edge
    BOOST_CHECK_EQUAL( data.numVertices(), states.size()-2  );
    BOOST_CHECK_EQUAL( data.numEdges(), states.size()-5 );

    BOOST_CHECK_EQUAL( data.removeEdge(5, 6), false ); // edge does not exist (we removed vertex 6)
    BOOST_CHECK_EQUAL( data.numVertices(), states.size()-2 );
    BOOST_CHECK_EQUAL( data.numEdges(), states.size()-5 );

    BOOST_CHECK( data.removeEdge(4, 5) );
    BOOST_CHECK_EQUAL( data.numVertices(), states.size()-2 );
    BOOST_CHECK_EQUAL( data.numEdges(), states.size()-6 );

    // Make sure the final graph looks the way we think:
    for (size_t i = 0; i < states.size(); ++i)
    {
        if (i == 6 || i == states.size()-1)
            BOOST_CHECK_EQUAL( data.vertexExists(PlannerDataTestVertex(states[i], i, i+1)), false );
        else
            BOOST_CHECK( data.vertexExists(PlannerDataTestVertex(states[i], i, i+1)) );
    }

    for (size_t i = 0; i < states.size()-2; ++i) // we removed two vertices
    {
        std::vector<unsigned int> nbrs;
        if (i == 1 || i == 4 || i == 5 || i == states.size()-3)
            BOOST_CHECK_EQUAL ( data.getEdges(i, nbrs), 0u );
        else
        {
            BOOST_CHECK_EQUAL ( data.getEdges(i, nbrs), 1u );
            BOOST_CHECK_EQUAL ( nbrs[0], i+1 );
            BOOST_CHECK( data.edgeExists(i, i+1) );
         }
    }

    for (size_t i = 0; i < states.size(); ++i)
    {
        space->freeState(states[i]);
        cspace->freeControl(controls[i]);
    }
}

BOOST_AUTO_TEST_CASE(Serialization)
{
    SETUP_STATE_CONTROL_SPACES

    control::PlannerData data(si);
    std::vector<base::State*> states;
    std::vector<control::Control*> controls;
    base::StateSamplerPtr stsamp = space->allocDefaultStateSampler();
    control::ControlSamplerPtr csamp = cspace->allocDefaultControlSampler();

    // Creating 1000 states, and adding them to PlannerData
    for (unsigned int i = 0; i < 1000; ++i)
    {
        states.push_back(space->allocState());
        stsamp->sampleUniform(states[i]);

        data.addVertex(PlannerDataTestVertex(states[i], i, i+1));
    }

    // Add a whole bunch of random edges
    unsigned int num_edges_to_add = 10000;
    ompl::RNG rng;

    for (unsigned int i = 0; i < num_edges_to_add; ++i)
    {
        unsigned int v2, v1 = rng.uniformInt(0, states.size()-1);
        do v2 = rng.uniformInt(0, states.size()-1); while (v2 == v1 || data.edgeExists(v1, v2));

        // allocate a random control
        controls.push_back(cspace->allocControl());
        csamp->sample(controls[i]);

        BOOST_CHECK( data.addEdge(v1, v2, PlannerDataTestEdge(controls[i], (double)i, i)) );
    }

    BOOST_CHECK_EQUAL ( data.numVertices(), states.size() );
    BOOST_CHECK_EQUAL ( data.numEdges(), num_edges_to_add );

    control::PlannerData data2(si);
    control::PlannerDataStorage storage;
    storage.store(data, "testdata");
    storage.load("testdata", data2);

    // Verify that data == data2
    BOOST_CHECK_EQUAL ( data2.numVertices(), states.size() );
    BOOST_CHECK_EQUAL ( data2.numEdges(), num_edges_to_add );

    // Checking vertices
    for (size_t i = 0; i < states.size(); ++i)
    {
        BOOST_CHECK ( space->equalStates(data2.getVertex(i).getState(), data.getVertex(i).getState()) );
        BOOST_CHECK ( data2.getVertex(i).getTag() == data.getVertex(i).getTag() );
        BOOST_CHECK ( static_cast<PlannerDataTestVertex&>(data2.getVertex(i)).tag2_ == static_cast<PlannerDataTestVertex&>(data.getVertex(i)).tag2_ );
    }

    // Checking edges
    for (size_t i = 0; i < states.size(); ++i)
    {
        std::vector<unsigned int> neighbors, neighbors2;
        data.getEdges(i, neighbors);
        data2.getEdges(i, neighbors2);

        std::sort (neighbors.begin(), neighbors.end());
        std::sort (neighbors2.begin(), neighbors2.end());
        BOOST_REQUIRE_EQUAL( neighbors.size(), neighbors2.size() );

        for (size_t j = 0; j < neighbors.size(); ++j)
        {
            BOOST_CHECK_EQUAL( neighbors[j], neighbors2[j] );

            PlannerDataTestEdge &edge  = static_cast<PlannerDataTestEdge&>(data.getEdge(i, neighbors[j]));
            PlannerDataTestEdge &edge2 = static_cast<PlannerDataTestEdge&>(data2.getEdge(i, neighbors[j]));
            BOOST_CHECK ( cspace->equalControls (edge.getControl(), edge2.getControl()) );
            BOOST_CHECK ( fabs(edge.getDuration() - edge2.getDuration()) < std::numeric_limits<double>::epsilon());
            BOOST_CHECK ( edge.id_ == edge2.id_ );
        }
    }

    for (size_t i = 0; i < states.size(); ++i)
        space->freeState(states[i]);

    for (size_t i = 0; i < controls.size(); ++i)
        cspace->freeControl(controls[i]);
}


text:
from collections import defaultdict
from typing import (
    TYPE_CHECKING,
    Any,
    Dict,
    Iterable,
    List,
    NamedTuple,
    NoReturn,
    Optional,
    Tuple,
)

from django.core.exceptions import ValidationError
from django.db.models import F, QuerySet, Sum
from django.db.models.functions import Coalesce

from ..checkout.error_codes import CheckoutErrorCode
from ..checkout.fetch import DeliveryMethodBase
from ..core.exceptions import InsufficientStock, InsufficientStockData
from ..product.models import ProductVariantChannelListing
from .models import Reservation, Stock, StockQuerySet
from .reservations import get_listings_reservations

if TYPE_CHECKING:
    from ..checkout.fetch import CheckoutLineInfo
    from ..checkout.models import CheckoutLine
    from ..product.models import Product, ProductVariant

class ChannelListingPreorderAvailbilityInfo(NamedTuple):
    preorder_quantity: int
    preorder_quantity_threshold: int
    listing_id: int

class VariantsChannelAvailbilityInfo(NamedTuple):
    variants_channel_availability: Dict[int, ChannelListingPreorderAvailbilityInfo]
    variants_global_allocations: Dict[int, int]
    all_variants_channel_listings: QuerySet[ProductVariantChannelListing]
    variant_channels: Dict[int, List[ProductVariantChannelListing]]

def _get_available_quantity(
    stocks: StockQuerySet,
    checkout_lines: Optional[List["CheckoutLine"]] = None,
    check_reservations: bool = False,
) -> int:
    results = stocks.aggregate(
        total_quantity=Coalesce(Sum("quantity", distinct=True), 0),
        quantity_allocated=Coalesce(Sum("allocations__quantity_allocated"), 0),
    )
    total_quantity = results["total_quantity"]
    quantity_allocated = results["quantity_allocated"]

    if check_reservations:
        quantity_reserved = get_reserved_stock_quantity(stocks, checkout_lines)
    else:
        quantity_reserved = 0

    return max(total_quantity - quantity_allocated - quantity_reserved, 0)

def check_stock_and_preorder_quantity(
    variant: "ProductVariant",
    country_code: str,
    channel_slug: str,
    quantity: int,
    checkout_lines: Optional[List["CheckoutLine"]] = None,
    check_reservations: bool = False,
):
    """Validate if there is stock/preorder available for given variant.

    :raises InsufficientStock: when there is not enough items in stock for a variant
    or there is not enough available preorder items for a variant.
    """
    if variant.is_preorder_active():
        check_preorder_threshold_in_orders(
            variant, quantity, channel_slug, checkout_lines, check_reservations
        )
    else:
        check_stock_quantity(
            variant,
            country_code,
            channel_slug,
            quantity,
            checkout_lines,
            check_reservations,
        )

def check_stock_quantity(
    variant: "ProductVariant",
    country_code: str,
    channel_slug: str,
    quantity: int,
    checkout_lines: Optional[List["CheckoutLine"]] = None,
    check_reservations: bool = False,
):
    """Validate if there is stock available for given variant in given country.

    If so - returns None. If there is less stock then required raise InsufficientStock
    exception.
    """
    if variant.track_inventory:
        stocks = Stock.objects.get_variant_stocks_for_country(
            country_code, channel_slug, variant
        )
        if not stocks:
            raise InsufficientStock([InsufficientStockData(variant=variant)])

        available_quantity = _get_available_quantity(
            stocks, checkout_lines, check_reservations
        )
        if quantity > available_quantity:
            raise InsufficientStock([InsufficientStockData(variant=variant)])

def check_stock_and_preorder_quantity_bulk(
    variants: Iterable["ProductVariant"],
    country_code: str,
    quantities: Iterable[int],
    channel_slug: str,
    global_quantity_limit: Optional[int],
    delivery_method_info: Optional["DeliveryMethodBase"] = None,
    additional_filter_lookup: Optional[Dict[str, Any]] = None,
    existing_lines: Optional[Iterable["CheckoutLineInfo"]] = None,
    replace: bool = False,
    check_reservations: bool = False,
):
    """Validate if products are available for stocks/preorder.

    :raises InsufficientStock: when there is not enough items in stock for a variant
    or there is not enough available preorder items for a variant.
    """
    (
        stock_variants,
        stock_quantities,
        preorder_variants,
        preorder_quantities,
    ) = _split_lines_for_trackable_and_preorder(variants, quantities)
    if stock_variants:
        check_stock_quantity_bulk(
            stock_variants,
            country_code,
            stock_quantities,
            channel_slug,
            global_quantity_limit,
            delivery_method_info,
            additional_filter_lookup,
            existing_lines,
            replace,
            check_reservations,
        )
    if preorder_variants:
        check_preorder_threshold_bulk(
            preorder_variants,
            preorder_quantities,
            channel_slug,
            global_quantity_limit,
            existing_lines,
            replace,
            check_reservations,
        )

def _split_lines_for_trackable_and_preorder(
    variants: Iterable["ProductVariant"], quantities: Iterable[int]
) -> Tuple[
    Iterable["ProductVariant"], Iterable[int], Iterable["ProductVariant"], Iterable[int]
]:
    """Return variants and quantities splitted by "is_preorder_active"."""
    stock_variants, stock_quantities = [], []
    preorder_variants, preorder_quantities = [], []

    for variant, quantity in zip(variants, quantities):
        if variant.is_preorder_active():
            preorder_variants.append(variant)
            preorder_quantities.append(quantity)
        else:
            stock_variants.append(variant)
            stock_quantities.append(quantity)
    return (
        stock_variants,
        stock_quantities,
        preorder_variants,
        preorder_quantities,
    )

def _check_quantity_limits(
    variant: "ProductVariant", quantity: int, global_quantity_limit: Optional[int]
) -> Optional[NoReturn]:
    quantity_limit = variant.quantity_limit_per_customer or global_quantity_limit

    if quantity_limit is not None and quantity > quantity_limit:
        raise ValidationError(
            {
                "quantity": ValidationError(
                    (
                        f"Cannot add more than {quantity_limit} "
                        f"times this item: {variant}."
                    ),
                    code=CheckoutErrorCode.QUANTITY_GREATER_THAN_LIMIT.value,
                )
            }
        )
    return None

def check_stock_quantity_bulk(
    variants: Iterable["ProductVariant"],
    country_code: str,
    quantities: Iterable[int],
    channel_slug: str,
    global_quantity_limit: Optional[int],
    delivery_method_info: Optional["DeliveryMethodBase"] = None,
    additional_filter_lookup: Optional[Dict[str, Any]] = None,
    existing_lines: Iterable["CheckoutLineInfo"] = None,
    replace=False,
    check_reservations: bool = False,
):
    """Validate if there is stock available for given variants in given country.

    :raises InsufficientStock: when there is not enough items in stock for a variant.
    """
    filter_lookup = {"product_variant__in": variants}
    if additional_filter_lookup is not None:
        filter_lookup.update(additional_filter_lookup)

    # in case when the delivery method is not set yet, we should check the stock
    # quantity in standard warehouses available in a given channel and country, and
    # in the collection point warehouses for the channel
    include_cc_warehouses = (
        not delivery_method_info.delivery_method if delivery_method_info else True
    )
    # in case of click and collect order, we need to check local or global stock
    # regardless of the country code
    collection_point = (
        delivery_method_info.warehouse_pk if delivery_method_info else None
    )
    stocks = (
        Stock.objects.for_channel_and_click_and_collect(channel_slug)
        if collection_point
        else Stock.objects.for_channel_and_country(
            channel_slug, country_code, include_cc_warehouses
        )
    )

    all_variants_stocks = stocks.filter(**filter_lookup).annotate_available_quantity()

    variant_stocks: Dict[int, List[Stock]] = defaultdict(list)
    for stock in all_variants_stocks:
        variant_stocks[stock.product_variant_id].append(stock)

    if check_reservations:
        variant_reservations = get_reserved_stock_quantity_bulk(
            all_variants_stocks,
            [line.line for line in existing_lines] if existing_lines else [],
        )
    else:
        variant_reservations = defaultdict(int)

    insufficient_stocks: List[InsufficientStockData] = []
    variants_quantities = {
        line.variant.pk: line.line.quantity for line in existing_lines or []
    }
    for variant, quantity in zip(variants, quantities):

        if not replace:
            quantity += variants_quantities.get(variant.pk, 0)

        stocks = variant_stocks.get(variant.pk, [])
        available_quantity = sum(
            [stock.available_quantity for stock in stocks]  # type: ignore
        )
        available_quantity = max(
            available_quantity - variant_reservations[variant.pk], 0
        )

        if quantity > 0:
            _check_quantity_limits(variant, quantity, global_quantity_limit)

            if not stocks:
                insufficient_stocks.append(
                    InsufficientStockData(
                        variant=variant, available_quantity=available_quantity
                    )
                )
            elif variant.track_inventory and quantity > available_quantity:
                insufficient_stocks.append(
                    InsufficientStockData(
                        variant=variant,
                        available_quantity=available_quantity,
                    )
                )

    if insufficient_stocks:
        raise InsufficientStock(insufficient_stocks)

def _get_variants_channel_availbility_info(
    variants: Iterable["ProductVariant"],
    channel_slug: str,
) -> VariantsChannelAvailbilityInfo:
    all_variants_channel_listings = (
        ProductVariantChannelListing.objects.filter(variant__in=variants)
        .annotate_preorder_quantity_allocated()
        .annotate(
            available_preorder_quantity=F("preorder_quantity_threshold")
            - Coalesce(Sum("preorder_allocations__quantity"), 0),
        )
        .select_related("channel")
    )
    variants_channel_availability = {
        channel_listing.variant_id: ChannelListingPreorderAvailbilityInfo(
            channel_listing.available_preorder_quantity,
            channel_listing.preorder_quantity_threshold,
            channel_listing.id,
        )
        for channel_listing in all_variants_channel_listings
        if channel_listing.channel.slug == channel_slug
    }

    variant_channels: Dict[int, List[ProductVariantChannelListing]] = defaultdict(list)
    for channel_listing in all_variants_channel_listings:
        variant_channels[channel_listing.variant_id].append(channel_listing)

    variants_global_allocations = {
        variant_id: sum(
            channel_listing.preorder_quantity_allocated  # type: ignore
            for channel_listing in channel_listings
        )
        for variant_id, channel_listings in variant_channels.items()
    }
    return VariantsChannelAvailbilityInfo(
        variants_channel_availability,
        variants_global_allocations,
        all_variants_channel_listings,
        variant_channels,
    )

def check_preorder_threshold_in_orders(
    variant: "ProductVariant",
    quantity: int,
    channel_slug: str,
    checkout_lines: Optional[Iterable["CheckoutLine"]],
    check_reservations: bool,
):
    """Validate if there is preorder available for given variants in given country.

    It is used in orders, since it does not need additional logic related to limits.
    :raises InsufficientStock: when there is not enough items in stock for a variant.
    """
    (
        variants_channel_availability,
        variants_global_allocations,
        all_variants_channel_listings,
        variant_channels,
    ) = _get_variants_channel_availbility_info([variant], channel_slug)

    if check_reservations:
        listings_reservations = get_listings_reservations(
            checkout_lines, all_variants_channel_listings
        )
    else:
        listings_reservations = defaultdict(int)

    insufficient_stocks: List[InsufficientStockData] = []

    if (
        variants_channel_availability[variant.id].preorder_quantity_threshold
        is not None
    ):
        channel_listing_id = variants_channel_availability[variant.id].listing_id
        available_channel_quantity = variants_channel_availability[
            variant.id
        ].preorder_quantity
        available_channel_quantity -= listings_reservations[channel_listing_id]
        available_channel_quantity = max(available_channel_quantity, 0)

        if quantity > available_channel_quantity:
            insufficient_stocks.append(
                InsufficientStockData(
                    variant=variant, available_quantity=available_channel_quantity
                )
            )

        if variant.preorder_global_threshold is not None:
            global_availability = variant.preorder_global_threshold
            global_availability -= variants_global_allocations[variant.id]

            for channel_listing in variant_channels[variant.id]:
                global_availability -= listings_reservations[channel_listing.id]

            global_availability = max(global_availability, 0)

            if quantity > global_availability:
                insufficient_stocks.append(
                    InsufficientStockData(
                        variant=variant,
                        available_quantity=global_availability,
                    )
                )

    if insufficient_stocks:
        raise InsufficientStock(insufficient_stocks)

def check_preorder_threshold_bulk(
    variants: Iterable["ProductVariant"],
    quantities: Iterable[int],
    channel_slug: str,
    global_quantity_limit: Optional[int],
    existing_lines: Optional[Iterable["CheckoutLineInfo"]] = None,
    replace: bool = False,
    check_reservations: bool = False,
):
    """Validate if there is enough preordered variants according to thresholds.

    :raises InsufficientStock: when there is not enough available items for a variant.
    """
    (
        variants_channel_availability,
        variants_global_allocations,
        all_variants_channel_listings,
        variant_channels,
    ) = _get_variants_channel_availbility_info(variants, channel_slug)

    if check_reservations:
        listings_reservations = get_listings_reservations(
            [line.line for line in existing_lines or []], all_variants_channel_listings
        )
    else:
        listings_reservations = defaultdict(int)

    insufficient_stocks: List[InsufficientStockData] = []
    variants_quantities = {
        line.variant.pk: line.line.quantity for line in existing_lines or []
    }
    for variant, quantity in zip(variants, quantities):

        cumulative_quantity = quantity
        if not replace:
            cumulative_quantity = quantity + variants_quantities.get(variant.pk, 0)

        if quantity > 0:
            _check_quantity_limits(variant, cumulative_quantity, global_quantity_limit)

        if (
            variants_channel_availability[variant.id].preorder_quantity_threshold
            is not None
        ):
            channel_listing_id = variants_channel_availability[variant.id].listing_id
            available_channel_quantity = variants_channel_availability[
                variant.id
            ].preorder_quantity
            available_channel_quantity -= listings_reservations[channel_listing_id]
            available_channel_quantity = max(available_channel_quantity, 0)
            if quantity > available_channel_quantity:
                insufficient_stocks.append(
                    InsufficientStockData(
                        variant=variant,
                        available_quantity=available_channel_quantity,
                    )
                )

        if variant.preorder_global_threshold is not None:
            global_availability = variant.preorder_global_threshold
            global_availability -= variants_global_allocations[variant.id]

            for channel_listing in variant_channels[variant.id]:
                global_availability -= listings_reservations[channel_listing.id]

            global_availability = max(global_availability, 0)

            if quantity > global_availability:
                insufficient_stocks.append(
                    InsufficientStockData(
                        variant=variant,
                        available_quantity=global_availability,
                    )
                )

    if insufficient_stocks:
        raise InsufficientStock(insufficient_stocks)

def get_available_quantity(
    variant: "ProductVariant",
    country_code: str,
    channel_slug: str,
    checkout_lines: Optional[List["CheckoutLine"]] = None,
    check_reservations: bool = False,
) -> int:
    """Return available quantity for given product in given country."""
    stocks = Stock.objects.get_variant_stocks_for_country(
        country_code, channel_slug, variant
    )
    if not stocks:
        return 0
    return _get_available_quantity(stocks, checkout_lines, check_reservations)

def is_product_in_stock(
    product: "Product", country_code: str, channel_slug: str
) -> bool:
    """Check if there is any variant of given product available in given country."""
    stocks = Stock.objects.get_product_stocks_for_country_and_channel(
        country_code, channel_slug, product
    ).annotate_available_quantity()
    return any(stocks.values_list("available_quantity", flat=True))

def get_reserved_stock_quantity(
    stocks: StockQuerySet, lines: Optional[List["CheckoutLine"]] = None
) -> int:
    result = (
        Reservation.objects.filter(
            stock__in=stocks,
        )
        .not_expired()
        .exclude_checkout_lines(lines)
        .aggregate(
            quantity_reserved=Coalesce(Sum("quantity_reserved"), 0),
        )
    )  # type: ignore

    return result["quantity_reserved"]

def get_reserved_stock_quantity_bulk(
    stocks: Iterable[Stock],
    checkout_lines: Iterable["CheckoutLine"],
) -> Dict[int, int]:
    reservations: Dict[int, int] = defaultdict(int)
    if not stocks:
        return reservations

    result = (
        Reservation.objects.filter(
            stock__in=stocks,
        )
        .not_expired()
        .exclude_checkout_lines(checkout_lines)
        .values("stock_id")
        .annotate(
            quantity_reserved=Coalesce(Sum("quantity_reserved"), 0),
        )
    )  # type: ignore

    stocks_variants = {stock.id: stock.product_variant_id for stock in stocks}
    for stock_reservations in result:
        variant_id = stocks_variants.get(stock_reservations["stock_id"])
        if variant_id:
            reservations[variant_id] += stock_reservations["quantity_reserved"]

    return reservations


text:
package com.cpacm;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.os.Build;

import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.view.ViewCompat;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.OvershootInterpolator;

import com.cpacm.floatingmusicbutton.R;
import com.google.android.material.floatingactionbutton.FloatingActionButton;

/**
 *

 * 浮动音乐菜单,可以显示歌曲封面和旋转动画并随着音乐显示进度。
 *

 *

 * {@link #toggle()} 切换菜单的展开收缩状态

 *

 *

 * {@link #setProgress(float)} 设置进度
 *

 *

 * {@link #setFloatingDirection(int)} 设置展开方向
 *

 *

 * {@link #setMusicCover(Drawable/Bitmap)} 设置封面
 *

 *

 * {@link #start()} 开始旋转动画

 * {@link #stop()} 停止旋转动画
 *

 *

 *

 *

 * 可以通过调用 {@link #addButton(FloatingActionButton)} 和 {@link #removeButton(FloatingActionButton)} 来动态增减按钮数量。
 *
 * @author cpacm
 *

 */
@CoordinatorLayout.DefaultBehavior(FloatingMusicMenu.Behavior.class)
public class FloatingMusicMenu extends ViewGroup {

    public final static int FLOATING_DIRECTION_UP = 0;
    public final static int FLOATING_DIRECTION_LEFT = 1;
    public final static int FLOATING_DIRECTION_DOWN = 2;
    public final static int FLOATING_DIRECTION_RIGHT = 3;

    private static final int SHADOW_OFFSET = 20;

    private FloatingMusicButton floatingMusicButton;
    private AnimatorSet showAnimation;
    private AnimatorSet hideAnimation;

    private int progressWidthPercent;
    private int progressColor;
    private float progress;
    private float buttonInterval;
    private ColorStateList backgroundTint;
    private Drawable cover;
    private boolean isExpanded;
    private boolean isHided;
    private int floatingDirection;

    public FloatingMusicMenu(Context context) {
        this(context, null);
    }

    public FloatingMusicMenu(Context context, AttributeSet attrs) {
        super(context, attrs);
        initMenu(context, attrs);
    }

    public FloatingMusicMenu(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initMenu(context, attrs);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public FloatingMusicMenu(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initMenu(context, attrs);
    }

    private void initMenu(Context context, AttributeSet attrs) {
        TypedArray attr = context.obtainStyledAttributes(attrs, R.styleable.FloatingMusicMenu, 0, 0);
        progressWidthPercent = attr.getInteger(R.styleable.FloatingMusicMenu_fmm_progress_percent, 3);
        progressColor = attr.getColor(R.styleable.FloatingMusicMenu_fmm_progress_color, getResources().getColor(android.R.color.holo_blue_dark));
        progress = attr.getFloat(R.styleable.FloatingMusicMenu_fmm_progress, 0);
        buttonInterval = attr.getDimension(R.styleable.FloatingMusicMenu_fmm_button_interval, 4);
        buttonInterval = dp2px(buttonInterval);
 /*       if (Build.VERSION.SDK_INT < 21) {
            // 版本兼容
            buttonInterval = -BitmapUtils.dp2px(16);
        }*/
        cover = attr.getDrawable(R.styleable.FloatingMusicMenu_fmm_cover);
        backgroundTint = attr.getColorStateList(R.styleable.FloatingMusicMenu_fmm_backgroundTint);
        floatingDirection = attr.getInteger(R.styleable.FloatingMusicMenu_fmm_floating_direction, 0);
        attr.recycle();
        createRootButton(context);
        addScrollAnimation();
    }

    private void addScrollAnimation() {
        showAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION);
        showAnimation.play(ObjectAnimator.ofFloat(this, View.ALPHA, 0f, 1f));
        showAnimation.setInterpolator(alphaExpandInterpolator);
        showAnimation.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                setVisibility(VISIBLE);
            }

            @Override
            public void onAnimationStart(Animator animation) {
                super.onAnimationStart(animation);
                setVisibility(VISIBLE);
            }
        });

        hideAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION);
        hideAnimation.play(ObjectAnimator.ofFloat(this, View.ALPHA, 1f, 0f));
        hideAnimation.setInterpolator(alphaExpandInterpolator);
        hideAnimation.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                setVisibility(INVISIBLE);
            }
        });
    }

    private void createRootButton(Context context) {
        floatingMusicButton = new FloatingMusicButton(context);
        floatingMusicButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                toggle();
            }
        });
        floatingMusicButton.config(progressWidthPercent, progressColor, backgroundTint);
        floatingMusicButton.setProgress(progress);
        if (cover != null) {
            floatingMusicButton.setCoverDrawable(cover);
        }
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        addView(floatingMusicButton, super.generateDefaultLayoutParams());
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        measureChildren(widthMeasureSpec, heightMeasureSpec);
        switch (floatingDirection) {
            case FLOATING_DIRECTION_UP:
            case FLOATING_DIRECTION_DOWN:
                onMeasureVerticalDirection();
                break;
            case FLOATING_DIRECTION_LEFT:
            case FLOATING_DIRECTION_RIGHT:
                onMeasureHorizontalDirection();
                break;
        }
    }

    /**
     * 计算竖向排列时需要的大小
     */
    private void onMeasureVerticalDirection() {
        int width = 0;
        int height = 0;
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            if (child.getVisibility() == GONE)
                continue;
            width = Math.max(child.getMeasuredWidth(), width);
            height += child.getMeasuredHeight();
        }
        width += SHADOW_OFFSET * 2;
        height += SHADOW_OFFSET * 2;
        height += buttonInterval * (getChildCount() - 1);
        height = adjustShootLength(height);
        setMeasuredDimension(width, height);
    }

    /**
     * 计算横向排列时需要的大小
     */
    private void onMeasureHorizontalDirection() {
        int width = 0;
        int height = 0;
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            if (child.getVisibility() == GONE)
                continue;
            height = Math.max(child.getMeasuredHeight(), height);
            width += child.getMeasuredWidth();
        }
        width += SHADOW_OFFSET * 2;
        height += SHADOW_OFFSET * 2;
        width += buttonInterval * (getChildCount() - 1);
        width = adjustShootLength(width);
        setMeasuredDimension(width, height);
    }

    private int adjustShootLength(int length) {
        return length * 12 / 10;
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        switch (floatingDirection) {
            case FLOATING_DIRECTION_UP:
                onUpDirectionLayout(l, t, r, b);
                break;
            case FLOATING_DIRECTION_DOWN:
                onDownDirectionLayout(l, t, r, b);
                break;
            case FLOATING_DIRECTION_LEFT:
                onLeftDirectionLayout(l, t, r, b);
                break;
            case FLOATING_DIRECTION_RIGHT:
                onRightDirectionLayout(l, t, r, b);
                break;
        }
    }

    /**
     * 摆放朝上展开方向的子控件位置
     */
    private void onUpDirectionLayout(int l, int t, int r, int b) {
        int centerX = (r - l) / 2;
        int offsetY = b - t - SHADOW_OFFSET;

        for (int i = getChildCount() - 1; i >= 0; i--) {
            View child = getChildAt(i);
            if (child.getVisibility() == GONE)
                continue;
            int width = child.getMeasuredWidth();
            int height = child.getMeasuredHeight();
            child.layout(centerX - width / 2, offsetY - height, centerX + width / 2, offsetY);

            //排除根按钮,添加动画
            if (i != getChildCount() - 1) {
                float collapsedTranslation = b - t - SHADOW_OFFSET - offsetY;
                float expandedTranslation = 0f;
                child.setTranslationY(isExpanded ? expandedTranslation : collapsedTranslation);
                child.setAlpha(isExpanded ? 1f : 0f);

                MenuLayoutParams params = (MenuLayoutParams) child.getLayoutParams();
                params.collapseDirAnim.setFloatValues(expandedTranslation, collapsedTranslation);
                params.expandDirAnim.setFloatValues(collapsedTranslation, expandedTranslation);
                params.collapseDirAnim.setProperty(View.TRANSLATION_Y);
                params.expandDirAnim.setProperty(View.TRANSLATION_Y);
                params.setAnimationsTarget(child);
            }
            offsetY -= height + buttonInterval;
        }
    }

    /**
     * 摆放朝下展开方向的子控件位置
     */
    private void onDownDirectionLayout(int l, int t, int r, int b) {
        int centerX = (r - l) / 2;
        int offsetY = SHADOW_OFFSET;
        View rootView = getChildAt(getChildCount() - 1);
        rootView.layout(centerX - rootView.getMeasuredWidth() / 2, offsetY, centerX + rootView.getMeasuredWidth() / 2, offsetY + rootView.getMeasuredHeight());
        offsetY += rootView.getMeasuredHeight() + buttonInterval;

        for (int i = 0; i < getChildCount() - 1; i++) {
            View child = getChildAt(i);
            if (child.getVisibility() == GONE)
                continue;
            int width = child.getMeasuredWidth();
            int height = child.getMeasuredHeight();
            child.layout(centerX - width / 2, offsetY, centerX + width / 2, offsetY + height);

            float collapsedTranslation = -offsetY;
            float expandedTranslation = 0f;
            child.setTranslationY(isExpanded ? expandedTranslation : collapsedTranslation);
            child.setAlpha(isExpanded ? 1f : 0f);

            MenuLayoutParams params = (MenuLayoutParams) child.getLayoutParams();
            params.collapseDirAnim.setFloatValues(expandedTranslation, collapsedTranslation);
            params.expandDirAnim.setFloatValues(collapsedTranslation, expandedTranslation);
            params.collapseDirAnim.setProperty(View.TRANSLATION_Y);
            params.expandDirAnim.setProperty(View.TRANSLATION_Y);
            params.setAnimationsTarget(child);

            offsetY += height + buttonInterval;
        }
    }

    /**
     * 摆放朝左展开方向的子控件位置
     */
    private void onLeftDirectionLayout(int l, int t, int r, int b) {
        int centerY = (b - t) / 2;
        int offsetX = r - l - SHADOW_OFFSET;

        for (int i = getChildCount() - 1; i >= 0; i--) {
            View child = getChildAt(i);
            if (child.getVisibility() == GONE)
                continue;
            int width = child.getMeasuredWidth();
            int height = child.getMeasuredHeight();
            child.layout(offsetX - width, centerY - height / 2, offsetX, centerY + height / 2);

            //排除根按钮,添加动画
            if (i != getChildCount() - 1) {
                float collapsedTranslation = r - l - SHADOW_OFFSET - offsetX;
                float expandedTranslation = 0f;
                child.setTranslationX(isExpanded ? expandedTranslation : collapsedTranslation);
                child.setAlpha(isExpanded ? 1f : 0f);

                MenuLayoutParams params = (MenuLayoutParams) child.getLayoutParams();
                params.collapseDirAnim.setFloatValues(expandedTranslation, collapsedTranslation);
                params.expandDirAnim.setFloatValues(collapsedTranslation, expandedTranslation);
                params.collapseDirAnim.setProperty(View.TRANSLATION_X);
                params.expandDirAnim.setProperty(View.TRANSLATION_X);
                params.setAnimationsTarget(child);
            }
            offsetX -= width + buttonInterval;
        }
    }

    /**
     * 摆放朝右展开方向的子控件位置
     */
    private void onRightDirectionLayout(int l, int t, int r, int b) {
        int centerY = (b - t) / 2;
        int offsetX = SHADOW_OFFSET;
        View rootView = getChildAt(getChildCount() - 1);
        rootView.layout(offsetX, centerY - rootView.getMeasuredHeight() / 2, offsetX + rootView.getMeasuredWidth(), centerY + rootView.getMeasuredHeight() / 2);
        offsetX += rootView.getMeasuredWidth() + buttonInterval;

        for (int i = 0; i < getChildCount() - 1; i++) {
            View child = getChildAt(i);
            if (child.getVisibility() == GONE)
                continue;
            int width = child.getMeasuredWidth();
            int height = child.getMeasuredHeight();
            child.layout(offsetX, centerY - height / 2, offsetX + width, centerY + height / 2);

            float collapsedTranslation = -offsetX;
            float expandedTranslation = 0f;
            child.setTranslationX(isExpanded ? expandedTranslation : collapsedTranslation);
            child.setAlpha(isExpanded ? 1f : 0f);

            MenuLayoutParams params = (MenuLayoutParams) child.getLayoutParams();
            params.collapseDirAnim.setFloatValues(expandedTranslation, collapsedTranslation);
            params.expandDirAnim.setFloatValues(collapsedTranslation, expandedTranslation);
            params.collapseDirAnim.setProperty(View.TRANSLATION_X);
            params.expandDirAnim.setProperty(View.TRANSLATION_X);
            params.setAnimationsTarget(child);

            offsetX += width + buttonInterval;
        }
    }

    public void setButtonInterval(float buttonInterval) {
        this.buttonInterval = buttonInterval;
        requestLayout();
    }

    public void addButton(FloatingActionButton button) {
        addView(button, 0);
        requestLayout();
    }

    public void addButtonAtLast(FloatingActionButton button) {
        addView(button, getChildCount() - 1);
        requestLayout();
    }

    public void removeButton(FloatingActionButton button) {
        removeView(button);
        requestLayout();
    }

    public void setMusicCover(Drawable drawable) {
        floatingMusicButton.setCoverDrawable(drawable);
    }

    public void setMusicCover(Bitmap bitmap) {
        floatingMusicButton.setCover(bitmap);
    }

    public void setProgress(float progress) {
        if (floatingMusicButton != null) {
            floatingMusicButton.setProgress(progress);
        }
    }

    public void start() {
        floatingMusicButton.rotate(true);
    }

    public void stop() {
        floatingMusicButton.rotate(false);
    }

    public void setFloatingDirection(int floatingDirection) {
        this.floatingDirection = floatingDirection;
        postInvalidate();
    }

    @Override
    protected LayoutParams generateDefaultLayoutParams() {
        return new MenuLayoutParams(super.generateDefaultLayoutParams());
    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MenuLayoutParams(super.generateLayoutParams(attrs));
    }

    @Override
    protected LayoutParams generateLayoutParams(LayoutParams p) {
        return new MenuLayoutParams(super.generateLayoutParams(p));
    }

    private static final int ANIMATION_DURATION = 300;
    private static final float COLLAPSED_PLUS_ROTATION = 0f;
    private static final float EXPANDED_PLUS_ROTATION = 90f + 45f;

    private AnimatorSet mExpandAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION);
    private AnimatorSet mCollapseAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION);

    private static Interpolator expandInterpolator = new OvershootInterpolator();
    private static Interpolator collapseInterpolator = new DecelerateInterpolator(3f);
    private static Interpolator alphaExpandInterpolator = new DecelerateInterpolator();

    private class MenuLayoutParams extends LayoutParams {

        private ObjectAnimator expandDirAnim = new ObjectAnimator();
        private ObjectAnimator expandAlphaAnim = new ObjectAnimator();
        private ObjectAnimator collapseDirAnim = new ObjectAnimator();
        private ObjectAnimator collapseAlphaAnim = new ObjectAnimator();

        private boolean animationsSetToPlay;

        public MenuLayoutParams(LayoutParams source) {
            super(source);

            expandDirAnim.setInterpolator(expandInterpolator);
            expandAlphaAnim.setInterpolator(alphaExpandInterpolator);
            collapseDirAnim.setInterpolator(collapseInterpolator);
            collapseAlphaAnim.setInterpolator(collapseInterpolator);

            collapseAlphaAnim.setProperty(View.ALPHA);
            collapseAlphaAnim.setFloatValues(1f, 0f);

            expandAlphaAnim.setProperty(View.ALPHA);
            expandAlphaAnim.setFloatValues(0f, 1f);
        }

        public void setAnimationsTarget(View view) {
            collapseAlphaAnim.setTarget(view);
            collapseDirAnim.setTarget(view);
            expandDirAnim.setTarget(view);
            expandAlphaAnim.setTarget(view);

            // Now that the animations have targets, set them to be played
            if (!animationsSetToPlay) {
                addLayerTypeListener(expandDirAnim, view);
                addLayerTypeListener(collapseDirAnim, view);

                mCollapseAnimation.play(collapseAlphaAnim);
                mCollapseAnimation.play(collapseDirAnim);
                mExpandAnimation.play(expandAlphaAnim);
                mExpandAnimation.play(expandDirAnim);
                animationsSetToPlay = true;
            }
        }

        private void addLayerTypeListener(Animator animator, final View view) {
            animator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    view.setLayerType(LAYER_TYPE_NONE, null);
                }

                @Override
                public void onAnimationStart(Animator animation) {
                    view.setLayerType(LAYER_TYPE_HARDWARE, null);
                }
            });
        }
    }

    public void collapse() {
        collapse(false);
    }

    public void collapseImmediately() {
        collapse(true);
    }

    private void collapse(boolean immediately) {
        if (isExpanded) {
            isExpanded = false;
            mCollapseAnimation.setDuration(immediately ? 0 : ANIMATION_DURATION);
            mCollapseAnimation.start();
            mExpandAnimation.cancel();
        }
    }

    public void toggle() {
        if (isExpanded) {
            collapse();
        } else {
            expand();
        }
    }

    public void expand() {
        if (!isExpanded) {
            isExpanded = true;
            mCollapseAnimation.cancel();
            mExpandAnimation.start();
        }
    }

    public boolean isExpanded() {
        return isExpanded;
    }

    public void hide() {
        if (!isHided) {
            isHided = true;
            hideAnimation.start();
            showAnimation.cancel();
        }
    }

    public void show() {
        if (isHided) {
            isHided = false;
            showAnimation.start();
            hideAnimation.cancel();
        }
    }

    public float dp2px(float dp) {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
                getResources().getDisplayMetrics());
    }

    /**
     *

     * 上拉隐藏,下拉显示的动作行为,配合 {@link FloatingMusicMenu} 使用更佳
     *

     */
    public static class Behavior extends CoordinatorLayout.Behavior<FloatingMusicMenu> {

        public Behavior() {
            super();
        }

        public Behavior(Context context, AttributeSet attributeSet) {
            super(context, attributeSet);
        }

        @Override
        public boolean onTouchEvent(CoordinatorLayout parent, FloatingMusicMenu child, MotionEvent ev) {
            return super.onTouchEvent(parent, child, ev);
        }

        @Override
        public void onNestedScroll(CoordinatorLayout coordinatorLayout, FloatingMusicMenu child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
            super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
            if (dyConsumed > 30 && child.getVisibility() == VISIBLE) {
                child.hide();
            } else if (dyConsumed < -30 && child.getVisibility() == INVISIBLE) {
                child.show();
            }
        }

        @Override
        public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, FloatingMusicMenu child, View directTargetChild, View target, int nestedScrollAxes) {
            return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL;
        }
    }
}


text:
package no.digipost.api.client.representations;

import no.digipost.api.client.errorhandling.DigipostClientException;
import no.digipost.api.client.errorhandling.ErrorCode;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "message-recipient", propOrder = {
        "nameAndAddress",
        "digipostAddress",
        "peppolAddresses",
        "personalIdentificationNumber",
        "organisationNumber",
        "printDetails",
        "bankAccountNumber",
        "emailDetails"
})
public class MessageRecipient {

    @XmlElement(name = "name-and-address", nillable = false)
    protected NameAndAddress nameAndAddress;
    @XmlElement(name = "digipost-address", nillable = false)
    protected String digipostAddress;
    @XmlElement(name = "peppol-addresses", nillable = false)
    protected PeppolAddresses peppolAddresses;
    @XmlElement(name = "personal-identification-number", nillable = false)
    protected String personalIdentificationNumber;
    @XmlElement(name = "organisation-number", nillable = false)
    protected String organisationNumber;
    @XmlElement(name = "print-details", nillable = false)
    protected PrintDetails printDetails;
    @XmlElement(name = "bank-account-number", nillable = false)
    protected String bankAccountNumber;
    @XmlElement(name = "email-details", nillable = false)
    protected EmailDetails emailDetails;

    public MessageRecipient() {
    }

    MessageRecipient(
            NameAndAddress nameAndAddress
            , String digipostAddress
            , PeppolAddresses peppolAddresses
            , String personalIdentificationNumber
            , String organisationNumber
            , PrintDetails printDetails
            , String bankAccountNumber
            , EmailDetails emailDetails
    ) {
        this.nameAndAddress = nameAndAddress;
        this.digipostAddress = digipostAddress;
        this.peppolAddresses = peppolAddresses;
        this.personalIdentificationNumber = personalIdentificationNumber;
        this.organisationNumber = organisationNumber;
        this.printDetails = printDetails;
        this.bankAccountNumber = bankAccountNumber;
        this.emailDetails = emailDetails;
    }

    public MessageRecipient(final PersonalIdentificationNumber id) {
        this.personalIdentificationNumber = id.asString();
    }

    public MessageRecipient(final BankAccountNumber bankAccountNumber) {
        this.bankAccountNumber = bankAccountNumber.asString();
    }

    public MessageRecipient(final DigipostAddress digipostAddress) {
        this.digipostAddress = digipostAddress.asString();
    }

    public MessageRecipient(final PeppolAddresses peppolAddresses) {
        this.peppolAddresses = peppolAddresses;
    }

    public MessageRecipient(final OrganisationNumber organisationNumber) {
        this.organisationNumber = organisationNumber.asString();
    }

    public MessageRecipient(final NameAndAddress nameAndAddress) {
        this.nameAndAddress = nameAndAddress;
    }

    public MessageRecipient(final PersonalIdentificationNumber id, final PrintDetails printDetails) {
        this(id);
        this.printDetails = printDetails;
    }

    public MessageRecipient(final DigipostAddress digipostAddress, final PrintDetails printDetails) {
        this(digipostAddress);
        this.printDetails = printDetails;
    }

    public MessageRecipient(final NameAndAddress nameAndAddress, final PrintDetails printDetails) {
        this(nameAndAddress);
        this.printDetails = printDetails;
    }

    public MessageRecipient(final OrganisationNumber organisationNumber, final PrintDetails printDetails) {
        this(organisationNumber);
        this.printDetails = printDetails;
    }

    public MessageRecipient(final EmailDetails emailDetails) {
        this.emailDetails = emailDetails;
    }

    public MessageRecipient(final PrintDetails printDetails) {
        this.printDetails = printDetails;
    }

    public NameAndAddress getNameAndAddress() {
        return nameAndAddress;
    }

    public String getDigipostAddress() {
        return digipostAddress;
    }

    public String getPersonalIdentificationNumber() {
        return personalIdentificationNumber;
    }

    public PeppolAddresses getPeppolAddresses() {
        return peppolAddresses;
    }

    public String getBankAccountNumber() {
        return bankAccountNumber;
    }

    public String getOrganisationNumber() {
        return organisationNumber;
    }

    public PrintDetails getPrintDetails() {
        return printDetails;
    }

    public boolean isDirectPrint() {
        return hasPrintDetails() && !hasDigipostIdentification();
    }

    public boolean hasPrintDetails() {
        return printDetails != null;
    }

    public boolean hasDigipostIdentification() {
        return digipostAddress != null || personalIdentificationNumber != null || nameAndAddress != null || organisationNumber != null;
    }

    public Identification toIdentification() {
        if (isDirectPrint()) {
            throw new IllegalStateException("MessageRecipient mangler identifikasjonsdetaljer.");
        }

        if (digipostAddress != null) {
            return new Identification(new DigipostAddress(digipostAddress));
        } else if (nameAndAddress != null) {
            return new Identification(nameAndAddress);
        } else if (organisationNumber != null) {
            return new Identification(new OrganisationNumber(organisationNumber));
        } else if (personalIdentificationNumber != null) {
            return new Identification(new PersonalIdentificationNumber(personalIdentificationNumber));
        } else {
            throw new DigipostClientException(ErrorCode.CLIENT_ERROR, "Ukjent identifikationstype.");
        }
    }
}