text:
/* apps/dsaparam.c */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
 * All rights reserved.
 *
 * This package is an SSL implementation written
 * by Eric Young (eay@cryptsoft.com).
 * The implementation was written so as to conform with Netscapes SSL.
 *
 * This library is free for commercial and non-commercial use as long as
 * the following conditions are aheared to.  The following conditions
 * apply to all code found in this distribution, be it the RC4, RSA,
 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
 * included with this distribution is covered by the same copyright terms
 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
 *
 * Copyright remains Eric Young's, and as such any Copyright notices in
 * the code are not to be removed.
 * If this package is used in a product, Eric Young should be given attribution
 * as the author of the parts of the library used.
 * This can be in the form of a textual message at program startup or
 * in documentation (online or textual) provided with the package.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    "This product includes cryptographic software written by
 *     Eric Young (eay@cryptsoft.com)"
 *    The word 'cryptographic' can be left out if the rouines from the library
 *    being used are not cryptographic related :-).
 * 4. If you include any Windows specific code (or a derivative thereof) from
 *    the apps directory (application code) you must include an acknowledgement:
 *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
 *
 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * The licence and distribution terms for any publically available version or
 * derivative of this code cannot be changed.  i.e. this code cannot simply be
 * copied and put under another distribution licence
 * [including the GNU Public Licence.]
 */

#include <openssl/opensslconf.h>	/* for OPENSSL_NO_DSA */
/* Until the key-gen callbacks are modified to use newer prototypes, we allow
 * deprecated functions for openssl-internal code */
#ifdef OPENSSL_NO_DEPRECATED
#undef OPENSSL_NO_DEPRECATED
#endif

#ifndef OPENSSL_NO_DSA
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include "apps.h"
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/bn.h>
#include <openssl/dsa.h>
#include <openssl/x509.h>
#include <openssl/pem.h>

#undef PROG
#define PROG	dsaparam_main

/* -inform arg	- input format - default PEM (DER or PEM)
 * -outform arg - output format - default PEM
 * -in arg	- input file - default stdin
 * -out arg	- output file - default stdout
 * -noout
 * -text
 * -C
 * -noout
 * -genkey
 *  #ifdef GENCB_TEST
 * -timebomb n  - interrupt keygen after <n> seconds
 *  #endif
 */

#ifdef GENCB_TEST

static int stop_keygen_flag = 0;

static void timebomb_sigalarm(int foo)
	{
	stop_keygen_flag = 1;
	}

#endif

static int MS_CALLBACK dsa_cb(int p, int n, BN_GENCB *cb);

int MAIN(int, char **);

int MAIN(int argc, char **argv)
	{
	DSA *dsa=NULL;
	int i,badops=0,text=0;
	BIO *in=NULL,*out=NULL;
	int informat,outformat,noout=0,C=0,ret=1;
	char *infile,*outfile,*prog,*inrand=NULL;
	int numbits= -1,num,genkey=0;
	int need_rand=0;
#ifndef OPENSSL_NO_ENGINE
	char *engine=NULL;
#endif
#ifdef GENCB_TEST
	int timebomb=0;
#endif

	apps_startup();

	if (bio_err == NULL)
		if ((bio_err=BIO_new(BIO_s_file())) != NULL)
			BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT);

	if (!load_config(bio_err, NULL))
		goto end;

	infile=NULL;
	outfile=NULL;
	informat=FORMAT_PEM;
	outformat=FORMAT_PEM;

	prog=argv[0];
	argc--;
	argv++;
	while (argc >= 1)
		{
		if 	(strcmp(*argv,"-inform") == 0)
			{
			if (--argc < 1) goto bad;
			informat=str2fmt(*(++argv));
			}
		else if (strcmp(*argv,"-outform") == 0)
			{
			if (--argc < 1) goto bad;
			outformat=str2fmt(*(++argv));
			}
		else if (strcmp(*argv,"-in") == 0)
			{
			if (--argc < 1) goto bad;
			infile= *(++argv);
			}
		else if (strcmp(*argv,"-out") == 0)
			{
			if (--argc < 1) goto bad;
			outfile= *(++argv);
			}
#ifndef OPENSSL_NO_ENGINE
		else if(strcmp(*argv, "-engine") == 0)
			{
			if (--argc < 1) goto bad;
			engine = *(++argv);
			}
#endif
#ifdef GENCB_TEST
		else if(strcmp(*argv, "-timebomb") == 0)
			{
			if (--argc < 1) goto bad;
			timebomb = atoi(*(++argv));
			}
#endif
		else if (strcmp(*argv,"-text") == 0)
			text=1;
		else if (strcmp(*argv,"-C") == 0)
			C=1;
		else if (strcmp(*argv,"-genkey") == 0)
			{
			genkey=1;
			need_rand=1;
			}
		else if (strcmp(*argv,"-rand") == 0)
			{
			if (--argc < 1) goto bad;
			inrand= *(++argv);
			need_rand=1;
			}
		else if (strcmp(*argv,"-noout") == 0)
			noout=1;
		else if (sscanf(*argv,"%d",&num) == 1)
			{
			/* generate a key */
			numbits=num;
			need_rand=1;
			}
		else
			{
			BIO_printf(bio_err,"unknown option %s\n",*argv);
			badops=1;
			break;
			}
		argc--;
		argv++;
		}

	if (badops)
		{
bad:
		BIO_printf(bio_err,"%s [options] [bits] <infile >outfile\n",prog);
		BIO_printf(bio_err,"where options are\n");
		BIO_printf(bio_err," -inform arg   input format - DER or PEM\n");
		BIO_printf(bio_err," -outform arg  output format - DER or PEM\n");
		BIO_printf(bio_err," -in arg       input file\n");
		BIO_printf(bio_err," -out arg      output file\n");
		BIO_printf(bio_err," -text         print as text\n");
		BIO_printf(bio_err," -C            Output C code\n");
		BIO_printf(bio_err," -noout        no output\n");
		BIO_printf(bio_err," -genkey       generate a DSA key\n");
		BIO_printf(bio_err," -rand         files to use for random number input\n");
#ifndef OPENSSL_NO_ENGINE
		BIO_printf(bio_err," -engine e     use engine e, possibly a hardware device.\n");
#endif
#ifdef GENCB_TEST
		BIO_printf(bio_err," -timebomb n   interrupt keygen after <n> seconds\n");
#endif
		BIO_printf(bio_err," number        number of bits to use for generating private key\n");
		goto end;
		}

	ERR_load_crypto_strings();

	in=BIO_new(BIO_s_file());
	out=BIO_new(BIO_s_file());
	if ((in == NULL) || (out == NULL))
		{
		ERR_print_errors(bio_err);
		goto end;
		}

	if (infile == NULL)
		BIO_set_fp(in,stdin,BIO_NOCLOSE);
	else
		{
		if (BIO_read_filename(in,infile) <= 0)
			{
			perror(infile);
			goto end;
			}
		}
	if (outfile == NULL)
		{
		BIO_set_fp(out,stdout,BIO_NOCLOSE);
#ifdef OPENSSL_SYS_VMS
		{
		BIO *tmpbio = BIO_new(BIO_f_linebuffer());
		out = BIO_push(tmpbio, out);
		}
#endif
		}
	else
		{
		if (BIO_write_filename(out,outfile) <= 0)
			{
			perror(outfile);
			goto end;
			}
		}

#ifndef OPENSSL_NO_ENGINE
        setup_engine(bio_err, engine, 0);
#endif

	if (need_rand)
		{
		app_RAND_load_file(NULL, bio_err, (inrand != NULL));
		if (inrand != NULL)
			BIO_printf(bio_err,"%ld semi-random bytes loaded\n",
				app_RAND_load_files(inrand));
		}

	if (numbits > 0)
		{
		BN_GENCB cb;
		BN_GENCB_set(&cb, dsa_cb, bio_err);
		assert(need_rand);
		dsa = DSA_new();
		if(!dsa)
			{
			BIO_printf(bio_err,"Error allocating DSA object\n");
			goto end;
			}
		BIO_printf(bio_err,"Generating DSA parameters, %d bit long prime\n",num);
	        BIO_printf(bio_err,"This could take some time\n");
#ifdef GENCB_TEST
		if(timebomb > 0)
	{
		struct sigaction act;
		act.sa_handler = timebomb_sigalarm;
		act.sa_flags = 0;
		BIO_printf(bio_err,"(though I'll stop it if not done within %d secs)\n",
				timebomb);
		if(sigaction(SIGALRM, &act, NULL) != 0)
			{
			BIO_printf(bio_err,"Error, couldn't set SIGALRM handler\n");
			goto end;
			}
		alarm(timebomb);
	}
#endif
	        if(!DSA_generate_parameters_ex(dsa,num,NULL,0,NULL,NULL, &cb))
			{
#ifdef GENCB_TEST
			if(stop_keygen_flag)
				{
				BIO_printf(bio_err,"DSA key generation time-stopped\n");
				/* This is an asked-for behaviour! */
				ret = 0;
				goto end;
				}
#endif
			ERR_print_errors(bio_err);
			BIO_printf(bio_err,"Error, DSA key generation failed\n");
			goto end;
			}
		}
	else if	(informat == FORMAT_ASN1)
		dsa=d2i_DSAparams_bio(in,NULL);
	else if (informat == FORMAT_PEM)
		dsa=PEM_read_bio_DSAparams(in,NULL,NULL,NULL);
	else
		{
		BIO_printf(bio_err,"bad input format specified\n");
		goto end;
		}
	if (dsa == NULL)
		{
		BIO_printf(bio_err,"unable to load DSA parameters\n");
		ERR_print_errors(bio_err);
		goto end;
		}

	if (text)
		{
		DSAparams_print(out,dsa);
		}

	if (C)
		{
		unsigned char *data;
		int l,len,bits_p;

		len=BN_num_bytes(dsa->p);
		bits_p=BN_num_bits(dsa->p);
		data=(unsigned char *)OPENSSL_malloc(len+20);
		if (data == NULL)
			{
			perror("OPENSSL_malloc");
			goto end;
			}
		l=BN_bn2bin(dsa->p,data);
		printf("static unsigned char dsa%d_p[]={",bits_p);
		for (i=0; i<l; i++)
			{
			if ((i%12) == 0) printf("\n\t");
			printf("0x%02X,",data[i]);
			}
		printf("\n\t};\n");

		l=BN_bn2bin(dsa->q,data);
		printf("static unsigned char dsa%d_q[]={",bits_p);
		for (i=0; i<l; i++)
			{
			if ((i%12) == 0) printf("\n\t");
			printf("0x%02X,",data[i]);
			}
		printf("\n\t};\n");

		l=BN_bn2bin(dsa->g,data);
		printf("static unsigned char dsa%d_g[]={",bits_p);
		for (i=0; i<l; i++)
			{
			if ((i%12) == 0) printf("\n\t");
			printf("0x%02X,",data[i]);
			}
		printf("\n\t};\n\n");

		printf("DSA *get_dsa%d()\n\t{\n",bits_p);
		printf("\tDSA *dsa;\n\n");
		printf("\tif ((dsa=DSA_new()) == NULL) return(NULL);\n");
		printf("\tdsa->p=BN_bin2bn(dsa%d_p,sizeof(dsa%d_p),NULL);\n",
			bits_p,bits_p);
		printf("\tdsa->q=BN_bin2bn(dsa%d_q,sizeof(dsa%d_q),NULL);\n",
			bits_p,bits_p);
		printf("\tdsa->g=BN_bin2bn(dsa%d_g,sizeof(dsa%d_g),NULL);\n",
			bits_p,bits_p);
		printf("\tif ((dsa->p == NULL) || (dsa->q == NULL) || (dsa->g == NULL))\n");
		printf("\t\t{ DSA_free(dsa); return(NULL); }\n");
		printf("\treturn(dsa);\n\t}\n");
		}

	if (!noout)
		{
		if 	(outformat == FORMAT_ASN1)
			i=i2d_DSAparams_bio(out,dsa);
		else if (outformat == FORMAT_PEM)
			i=PEM_write_bio_DSAparams(out,dsa);
		else	{
			BIO_printf(bio_err,"bad output format specified for outfile\n");
			goto end;
			}
		if (!i)
			{
			BIO_printf(bio_err,"unable to write DSA parameters\n");
			ERR_print_errors(bio_err);
			goto end;
			}
		}
	if (genkey)
		{
		DSA *dsakey;

		assert(need_rand);
		if ((dsakey=DSAparams_dup(dsa)) == NULL) goto end;
		if (!DSA_generate_key(dsakey))
			{
			ERR_print_errors(bio_err);
			DSA_free(dsakey);
			goto end;
			}
		if 	(outformat == FORMAT_ASN1)
			i=i2d_DSAPrivateKey_bio(out,dsakey);
		else if (outformat == FORMAT_PEM)
			i=PEM_write_bio_DSAPrivateKey(out,dsakey,NULL,NULL,0,NULL,NULL);
		else	{
			BIO_printf(bio_err,"bad output format specified for outfile\n");
			DSA_free(dsakey);
			goto end;
			}
		DSA_free(dsakey);
		}
	if (need_rand)
		app_RAND_write_file(NULL, bio_err);
	ret=0;
end:
	if (in != NULL) BIO_free(in);
	if (out != NULL) BIO_free_all(out);
	if (dsa != NULL) DSA_free(dsa);
	apps_shutdown();
	OPENSSL_EXIT(ret);
	}

static int MS_CALLBACK dsa_cb(int p, int n, BN_GENCB *cb)
	{
	char c='*';

	if (p == 0) c='.';
	if (p == 1) c='+';
	if (p == 2) c='*';
	if (p == 3) c='\n';
	BIO_write(cb->arg,&c,1);
	(void)BIO_flush(cb->arg);
#ifdef LINT
	p=n;
#endif
#ifdef GENCB_TEST
	if(stop_keygen_flag)
		return 0;
#endif
	return 1;
	}
#else /* !OPENSSL_NO_DSA */

# if PEDANTIC
static void *dummy=&dummy;
# endif

#endif


text:
package kafka.server

import java.util.{Optional, Properties}
import java.util.concurrent.ExecutionException

import kafka.api.KAFKA_2_7_IV0
import kafka.utils.TestUtils
import kafka.zk.{FeatureZNode, FeatureZNodeStatus, ZkVersion}
import kafka.utils.TestUtils.waitUntilTrue
import org.apache.kafka.clients.admin.{Admin, FeatureUpdate, UpdateFeaturesOptions, UpdateFeaturesResult}
import org.apache.kafka.common.errors.InvalidRequestException
import org.apache.kafka.common.feature.FinalizedVersionRange
import org.apache.kafka.common.feature.{Features, SupportedVersionRange}
import org.apache.kafka.common.message.UpdateFeaturesRequestData
import org.apache.kafka.common.message.UpdateFeaturesRequestData.FeatureUpdateKeyCollection
import org.apache.kafka.common.protocol.Errors
import org.apache.kafka.common.requests.{UpdateFeaturesRequest, UpdateFeaturesResponse}
import org.apache.kafka.common.utils.Utils
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.Assertions.{assertEquals, assertFalse, assertNotEquals, assertNotNull, assertTrue, assertThrows}

import scala.jdk.CollectionConverters._
import scala.reflect.ClassTag
import scala.util.matching.Regex

class UpdateFeaturesTest extends BaseRequestTest {

  override def brokerCount = 3

  override def brokerPropertyOverrides(props: Properties): Unit = {
    props.put(KafkaConfig.InterBrokerProtocolVersionProp, KAFKA_2_7_IV0.toString)
  }

  private def defaultSupportedFeatures(): Features[SupportedVersionRange] = {
    Features.supportedFeatures(Utils.mkMap(Utils.mkEntry("feature_1", new SupportedVersionRange(1, 3))))
  }

  private def defaultFinalizedFeatures(): Features[FinalizedVersionRange] = {
    Features.finalizedFeatures(Utils.mkMap(Utils.mkEntry("feature_1", new FinalizedVersionRange(1, 2))))
  }

  private def updateSupportedFeatures(
    features: Features[SupportedVersionRange], targetServers: Set[KafkaServer]): Unit = {
    targetServers.foreach(s => {
      s.brokerFeatures.setSupportedFeatures(features)
      s.zkClient.updateBrokerInfo(s.createBrokerInfo)
    })

    // Wait until updates to all BrokerZNode supported features propagate to the controller.
    val brokerIds = targetServers.map(s => s.config.brokerId)
    waitUntilTrue(
      () => servers.exists(s => {
        if (s.kafkaController.isActive) {
          s.kafkaController.controllerContext.liveOrShuttingDownBrokers
            .filter(b => brokerIds.contains(b.id))
            .forall(b => {
              b.features.equals(features)
            })
        } else {
          false
        }
      }),
      "Controller did not get broker updates")
  }

  private def updateSupportedFeaturesInAllBrokers(features: Features[SupportedVersionRange]): Unit = {
    updateSupportedFeatures(features, Set[KafkaServer]() ++ servers)
  }

  private def updateFeatureZNode(features: Features[FinalizedVersionRange]): Int = {
    val server = serverForId(0).get
    val newNode = new FeatureZNode(FeatureZNodeStatus.Enabled, features)
    val newVersion = server.zkClient.updateFeatureZNode(newNode)
    servers.foreach(s => {
      s.featureCache.waitUntilEpochOrThrow(newVersion, s.config.zkConnectionTimeoutMs)
    })
    newVersion
  }

  private def getFeatureZNode(): FeatureZNode = {
    val (mayBeFeatureZNodeBytes, version) = serverForId(0).get.zkClient.getDataAndVersion(FeatureZNode.path)
    assertNotEquals(version, ZkVersion.UnknownVersion)
    FeatureZNode.decode(mayBeFeatureZNodeBytes.get)
  }

  private def finalizedFeatures(features: java.util.Map[String, org.apache.kafka.clients.admin.FinalizedVersionRange]): Features[FinalizedVersionRange] = {
    Features.finalizedFeatures(features.asScala.map {
      case(name, versionRange) =>
        (name, new FinalizedVersionRange(versionRange.minVersionLevel(), versionRange.maxVersionLevel()))
    }.asJava)
  }

  private def supportedFeatures(features: java.util.Map[String, org.apache.kafka.clients.admin.SupportedVersionRange]): Features[SupportedVersionRange] = {
    Features.supportedFeatures(features.asScala.map {
      case(name, versionRange) =>
        (name, new SupportedVersionRange(versionRange.minVersion(), versionRange.maxVersion()))
    }.asJava)
  }

  private def checkFeatures(client: Admin,
                            expectedNode: FeatureZNode,
                            expectedFinalizedFeatures: Features[FinalizedVersionRange],
                            expectedFinalizedFeaturesEpoch: Long,
                            expectedSupportedFeatures: Features[SupportedVersionRange]): Unit = {
    assertEquals(expectedNode, getFeatureZNode())
    val featureMetadata = client.describeFeatures.featureMetadata.get
    assertEquals(expectedFinalizedFeatures, finalizedFeatures(featureMetadata.finalizedFeatures))
    assertEquals(expectedSupportedFeatures, supportedFeatures(featureMetadata.supportedFeatures))
    assertEquals(Optional.of(expectedFinalizedFeaturesEpoch), featureMetadata.finalizedFeaturesEpoch)
  }

  private def checkException[ExceptionType <: Throwable](result: UpdateFeaturesResult,
                                                         featureExceptionMsgPatterns: Map[String, Regex])
                                                        (implicit tag: ClassTag[ExceptionType]): Unit = {
    featureExceptionMsgPatterns.foreach {
      case (feature, exceptionMsgPattern) =>
        val exception = assertThrows(classOf[ExecutionException], () => result.values().get(feature).get())
        val cause = exception.getCause
        assertNotNull(cause)
        assertEquals(cause.getClass, tag.runtimeClass)
        assertTrue(exceptionMsgPattern.findFirstIn(cause.getMessage).isDefined,
                   s"Received unexpected error message: ${cause.getMessage}")
    }
  }

  /**
   * Tests whether an invalid feature update does not get processed on the server as expected,
   * and raises the ExceptionType on the client side as expected.
   *
   * @param feature               the feature to be updated
   * @param invalidUpdate         the invalid feature update to be sent in the
   *                              updateFeatures request to the server
   * @param exceptionMsgPattern   a pattern for the expected exception message
   */
  private def testWithInvalidFeatureUpdate[ExceptionType <: Throwable](feature: String,
                                                                       invalidUpdate: FeatureUpdate,
                                                                       exceptionMsgPattern: Regex)
                                                                      (implicit tag: ClassTag[ExceptionType]): Unit = {
    TestUtils.waitUntilControllerElected(zkClient)

    updateSupportedFeaturesInAllBrokers(defaultSupportedFeatures())
    val versionBefore = updateFeatureZNode(defaultFinalizedFeatures())
    val adminClient = createAdminClient()
    val nodeBefore = getFeatureZNode()

    val result = adminClient.updateFeatures(Utils.mkMap(Utils.mkEntry(feature, invalidUpdate)), new UpdateFeaturesOptions())

    checkException[ExceptionType](result, Map(feature -> exceptionMsgPattern))
    checkFeatures(
      adminClient,
      nodeBefore,
      defaultFinalizedFeatures(),
      versionBefore,
      defaultSupportedFeatures())
  }

  /**
   * Tests that an UpdateFeatures request sent to a non-Controller node fails as expected.
   */
  @Test
  def testShouldFailRequestIfNotController(): Unit = {
    TestUtils.waitUntilControllerElected(zkClient)

    updateSupportedFeaturesInAllBrokers(defaultSupportedFeatures())
    val versionBefore = updateFeatureZNode(defaultFinalizedFeatures())

    val nodeBefore = getFeatureZNode()
    val validUpdates = new FeatureUpdateKeyCollection()
    val validUpdate = new UpdateFeaturesRequestData.FeatureUpdateKey();
    validUpdate.setFeature("feature_1");
    validUpdate.setMaxVersionLevel(defaultSupportedFeatures().get("feature_1").max())
    validUpdate.setAllowDowngrade(false)
    validUpdates.add(validUpdate)

    val response = connectAndReceive[UpdateFeaturesResponse](
      new UpdateFeaturesRequest.Builder(new UpdateFeaturesRequestData().setFeatureUpdates(validUpdates)).build(),
      notControllerSocketServer)

    assertEquals(Errors.NOT_CONTROLLER, Errors.forCode(response.data.errorCode))
    assertNotNull(response.data.errorMessage())
    assertEquals(0, response.data.results.size)
    checkFeatures(
      createAdminClient(),
      nodeBefore,
      defaultFinalizedFeatures(),
      versionBefore,
      defaultSupportedFeatures())
  }

  /**
   * Tests that an UpdateFeatures request fails in the Controller, when, for a feature the
   * allowDowngrade flag is not set during a downgrade request.
   */
  @Test
  def testShouldFailRequestWhenDowngradeFlagIsNotSetDuringDowngrade(): Unit = {
    val targetMaxVersionLevel = (defaultFinalizedFeatures().get("feature_1").max() - 1).asInstanceOf[Short]
    testWithInvalidFeatureUpdate[InvalidRequestException](
      "feature_1",
      new FeatureUpdate(targetMaxVersionLevel,false),
      ".*Can not downgrade finalized feature.*allowDowngrade.*".r)
  }

  /**
   * Tests that an UpdateFeatures request fails in the Controller, when, for a feature the downgrade
   * is attempted to a max version level higher than the existing max version level.
   */
  @Test
  def testShouldFailRequestWhenDowngradeToHigherVersionLevelIsAttempted(): Unit = {
    val targetMaxVersionLevel = (defaultFinalizedFeatures().get("feature_1").max() + 1).asInstanceOf[Short]
    testWithInvalidFeatureUpdate[InvalidRequestException](
      "feature_1",
      new FeatureUpdate(targetMaxVersionLevel, true),
      ".*When the allowDowngrade flag set in the request, the provided maxVersionLevel:3.*existing maxVersionLevel:2.*".r)
  }

  /**
   * Tests that an UpdateFeatures request fails in the Controller, when, a feature deletion is
   * attempted without setting the allowDowngrade flag.
   */
  @Test
  def testShouldFailRequestInServerWhenDowngradeFlagIsNotSetDuringDeletion(): Unit = {
    TestUtils.waitUntilControllerElected(zkClient)

    updateSupportedFeaturesInAllBrokers(defaultSupportedFeatures())
    val versionBefore = updateFeatureZNode(defaultFinalizedFeatures())

    val adminClient = createAdminClient()
    val nodeBefore = getFeatureZNode()

    val invalidUpdates
      = new UpdateFeaturesRequestData.FeatureUpdateKeyCollection();
    val invalidUpdate = new UpdateFeaturesRequestData.FeatureUpdateKey();
    invalidUpdate.setFeature("feature_1")
    invalidUpdate.setMaxVersionLevel(0)
    invalidUpdate.setAllowDowngrade(false)
    invalidUpdates.add(invalidUpdate);
    val requestData = new UpdateFeaturesRequestData()
    requestData.setFeatureUpdates(invalidUpdates);

    val response = connectAndReceive[UpdateFeaturesResponse](
      new UpdateFeaturesRequest.Builder(new UpdateFeaturesRequestData().setFeatureUpdates(invalidUpdates)).build(),
      controllerSocketServer)

    assertEquals(1, response.data().results().size())
    val result = response.data.results.asScala.head
    assertEquals("feature_1", result.feature)
    assertEquals(Errors.INVALID_REQUEST, Errors.forCode(result.errorCode))
    assertNotNull(result.errorMessage)
    assertFalse(result.errorMessage.isEmpty)
    val exceptionMsgPattern = ".*Can not provide maxVersionLevel: 0 less than 1.*allowDowngrade.*".r
    assertTrue(exceptionMsgPattern.findFirstIn(result.errorMessage).isDefined, result.errorMessage)
    checkFeatures(
      adminClient,
      nodeBefore,
      defaultFinalizedFeatures(),
      versionBefore,
      defaultSupportedFeatures())
  }

  /**
   * Tests that an UpdateFeatures request fails in the Controller, when, a feature version level
   * upgrade is attempted for a non-existing feature.
   */
  @Test
  def testShouldFailRequestDuringDeletionOfNonExistingFeature(): Unit = {
    testWithInvalidFeatureUpdate[InvalidRequestException](
      "feature_non_existing",
      new FeatureUpdate(3, true),
      ".*Could not apply finalized feature update because the provided feature is not supported.*".r)
  }

  /**
   * Tests that an UpdateFeatures request fails in the Controller, when, a feature version level
   * upgrade is attempted to a version level same as the existing max version level.
   */
  @Test
  def testShouldFailRequestWhenUpgradingToSameVersionLevel(): Unit = {
    val targetMaxVersionLevel = defaultFinalizedFeatures().get("feature_1").max()
    testWithInvalidFeatureUpdate[InvalidRequestException](
      "feature_1",
      new FeatureUpdate(targetMaxVersionLevel, false),
      ".*Can not upgrade a finalized feature.*to the same value.*".r)
  }

  private def testShouldFailRequestDuringBrokerMaxVersionLevelIncompatibility(
    featureName: String,
    supportedVersionRange: SupportedVersionRange,
    initialFinalizedVersionRange: Option[FinalizedVersionRange]
  ): Unit = {
    TestUtils.waitUntilControllerElected(zkClient)

    val controller = servers.filter { server => server.kafkaController.isActive}.head
    val nonControllerServers = servers.filter { server => !server.kafkaController.isActive}
    // We setup the supported features on the broker such that 1/3 of the brokers does not
    // support an expected feature version, while 2/3 brokers support the expected feature
    // version.
    val brokersWithVersionIncompatibility = Set[KafkaServer](nonControllerServers.head)
    val versionCompatibleBrokers = Set[KafkaServer](nonControllerServers(1), controller)

    val supportedFeatures = Features.supportedFeatures(Utils.mkMap(Utils.mkEntry(featureName, supportedVersionRange)))
    updateSupportedFeatures(supportedFeatures, versionCompatibleBrokers)

    val unsupportedMaxVersion = (supportedVersionRange.max() - 1).asInstanceOf[Short]
    val supportedFeaturesWithVersionIncompatibility = Features.supportedFeatures(
      Utils.mkMap(
        Utils.mkEntry("feature_1",
          new SupportedVersionRange(
            supportedVersionRange.min(),
            unsupportedMaxVersion))))
    updateSupportedFeatures(supportedFeaturesWithVersionIncompatibility, brokersWithVersionIncompatibility)

    val initialFinalizedFeatures = initialFinalizedVersionRange.map(
      versionRange => Features.finalizedFeatures(Utils.mkMap(Utils.mkEntry(featureName, versionRange)))
    ).getOrElse(Features.emptyFinalizedFeatures())
    val versionBefore = updateFeatureZNode(initialFinalizedFeatures)

    val invalidUpdate = new FeatureUpdate(supportedVersionRange.max(), false)
    val nodeBefore = getFeatureZNode()
    val adminClient = createAdminClient()
    val result = adminClient.updateFeatures(
      Utils.mkMap(Utils.mkEntry("feature_1", invalidUpdate)),
      new UpdateFeaturesOptions())

    checkException[InvalidRequestException](result, Map("feature_1" -> ".*brokers.*incompatible.*".r))
    checkFeatures(
      adminClient,
      nodeBefore,
      initialFinalizedFeatures,
      versionBefore,
      supportedFeatures)
  }

  /**
   * Tests that an UpdateFeatures request fails in the Controller, when for an existing finalized
   * feature, a version level upgrade introduces a version incompatibility with existing supported
   * features.
   */
  @Test
  def testShouldFailRequestDuringBrokerMaxVersionLevelIncompatibilityForExistingFinalizedFeature(): Unit = {
    val feature = "feature_1"
    testShouldFailRequestDuringBrokerMaxVersionLevelIncompatibility(
      feature,
      defaultSupportedFeatures().get(feature),
      Some(defaultFinalizedFeatures().get(feature)))
  }

  /**
   * Tests that an UpdateFeatures request fails in the Controller, when for a non-existing finalized
   * feature, a version level upgrade introduces a version incompatibility with existing supported
   * features.
   */
  @Test
  def testShouldFailRequestDuringBrokerMaxVersionLevelIncompatibilityWithNoExistingFinalizedFeature(): Unit = {
    val feature = "feature_1"
    testShouldFailRequestDuringBrokerMaxVersionLevelIncompatibility(
      feature,
      defaultSupportedFeatures().get(feature),
      Option.empty)
  }

  /**
   * Tests that an UpdateFeatures request succeeds in the Controller, when, there are no existing
   * finalized features in FeatureZNode when the test starts.
   */
  @Test
  def testSuccessfulFeatureUpgradeAndWithNoExistingFinalizedFeatures(): Unit = {
    TestUtils.waitUntilControllerElected(zkClient)

    val supportedFeatures =
      Features.supportedFeatures(
        Utils.mkMap(
          Utils.mkEntry("feature_1", new SupportedVersionRange(1, 3)),
          Utils.mkEntry("feature_2", new SupportedVersionRange(2, 5))))
    updateSupportedFeaturesInAllBrokers(supportedFeatures)
    val versionBefore = updateFeatureZNode(Features.emptyFinalizedFeatures())

    val targetFinalizedFeatures = Features.finalizedFeatures(
      Utils.mkMap(
        Utils.mkEntry("feature_1", new FinalizedVersionRange(1, 3)),
        Utils.mkEntry("feature_2", new FinalizedVersionRange(2, 3))))
    val update1 = new FeatureUpdate(targetFinalizedFeatures.get("feature_1").max(), false)
    val update2 = new FeatureUpdate(targetFinalizedFeatures.get("feature_2").max(), false)

    val adminClient = createAdminClient()
    adminClient.updateFeatures(
      Utils.mkMap(Utils.mkEntry("feature_1", update1), Utils.mkEntry("feature_2", update2)),
      new UpdateFeaturesOptions()
    ).all().get()

    checkFeatures(
      adminClient,
      new FeatureZNode(FeatureZNodeStatus.Enabled, targetFinalizedFeatures),
      targetFinalizedFeatures,
      versionBefore + 1,
      supportedFeatures)
  }

  /**
   * Tests that an UpdateFeatures request succeeds in the Controller, when, the request contains
   * both a valid feature version level upgrade as well as a downgrade request.
   */
  @Test
  def testSuccessfulFeatureUpgradeAndDowngrade(): Unit = {
    TestUtils.waitUntilControllerElected(zkClient)

    val supportedFeatures = Features.supportedFeatures(
      Utils.mkMap(
        Utils.mkEntry("feature_1", new SupportedVersionRange(1, 3)),
        Utils.mkEntry("feature_2", new SupportedVersionRange(2, 5))))
    updateSupportedFeaturesInAllBrokers(supportedFeatures)
    val initialFinalizedFeatures = Features.finalizedFeatures(
      Utils.mkMap(
        Utils.mkEntry("feature_1", new FinalizedVersionRange(1, 2)),
        Utils.mkEntry("feature_2", new FinalizedVersionRange(2, 4))))
    val versionBefore = updateFeatureZNode(initialFinalizedFeatures)

    // Below we aim to do the following:
    // - Valid upgrade of feature_1 maxVersionLevel from 2 to 3
    // - Valid downgrade of feature_2 maxVersionLevel from 4 to 3
    val targetFinalizedFeatures = Features.finalizedFeatures(
      Utils.mkMap(
        Utils.mkEntry("feature_1", new FinalizedVersionRange(1, 3)),
        Utils.mkEntry("feature_2", new FinalizedVersionRange(2, 3))))
    val update1 = new FeatureUpdate(targetFinalizedFeatures.get("feature_1").max(), false)
    val update2 = new FeatureUpdate(targetFinalizedFeatures.get("feature_2").max(), true)

    val adminClient = createAdminClient()
    adminClient.updateFeatures(
      Utils.mkMap(Utils.mkEntry("feature_1", update1), Utils.mkEntry("feature_2", update2)),
      new UpdateFeaturesOptions()
    ).all().get()

    checkFeatures(
      adminClient,
      new FeatureZNode(FeatureZNodeStatus.Enabled, targetFinalizedFeatures),
      targetFinalizedFeatures,
      versionBefore + 1,
      supportedFeatures)
  }

  /**
   * Tests that an UpdateFeatures request succeeds partially in the Controller, when, the request
   * contains a valid feature version level upgrade and an invalid version level downgrade.
   * i.e. expect the upgrade operation to succeed, and the downgrade operation to fail.
   */
  @Test
  def testPartialSuccessDuringValidFeatureUpgradeAndInvalidDowngrade(): Unit = {
    TestUtils.waitUntilControllerElected(zkClient)

    val supportedFeatures = Features.supportedFeatures(
      Utils.mkMap(
        Utils.mkEntry("feature_1", new SupportedVersionRange(1, 3)),
        Utils.mkEntry("feature_2", new SupportedVersionRange(2, 5))))
    updateSupportedFeaturesInAllBrokers(supportedFeatures)
    val initialFinalizedFeatures = Features.finalizedFeatures(
      Utils.mkMap(
        Utils.mkEntry("feature_1", new FinalizedVersionRange(1, 2)),
        Utils.mkEntry("feature_2", new FinalizedVersionRange(2, 4))))
    val versionBefore = updateFeatureZNode(initialFinalizedFeatures)

    // Below we aim to do the following:
    // - Valid upgrade of feature_1 maxVersionLevel from 2 to 3
    // - Invalid downgrade of feature_2 maxVersionLevel from 4 to 3
    //   (because we intentionally do not set the allowDowngrade flag)
    val targetFinalizedFeatures = Features.finalizedFeatures(
      Utils.mkMap(
        Utils.mkEntry("feature_1", new FinalizedVersionRange(1, 3)),
        Utils.mkEntry("feature_2", new FinalizedVersionRange(2, 3))))
    val validUpdate = new FeatureUpdate(targetFinalizedFeatures.get("feature_1").max(), false)
    val invalidUpdate = new FeatureUpdate(targetFinalizedFeatures.get("feature_2").max(), false)

    val adminClient = createAdminClient()
    val result = adminClient.updateFeatures(
      Utils.mkMap(Utils.mkEntry("feature_1", validUpdate), Utils.mkEntry("feature_2", invalidUpdate)),
      new UpdateFeaturesOptions())

    // Expect update for "feature_1" to have succeeded.
    result.values().get("feature_1").get()
    // Expect update for "feature_2" to have failed.
    checkException[InvalidRequestException](
      result, Map("feature_2" -> ".*Can not downgrade finalized feature.*allowDowngrade.*".r))
    val expectedFeatures = Features.finalizedFeatures(
      Utils.mkMap(
        Utils.mkEntry("feature_1", targetFinalizedFeatures.get("feature_1")),
        Utils.mkEntry("feature_2", initialFinalizedFeatures.get("feature_2"))))
    checkFeatures(
      adminClient,
      FeatureZNode(FeatureZNodeStatus.Enabled, expectedFeatures),
      expectedFeatures,
      versionBefore + 1,
      supportedFeatures)
  }

  /**
   * Tests that an UpdateFeatures request succeeds partially in the Controller, when, the request
   * contains an invalid feature version level upgrade and a valid version level downgrade.
   * i.e. expect the downgrade operation to succeed, and the upgrade operation to fail.
   */
  @Test
  def testPartialSuccessDuringInvalidFeatureUpgradeAndValidDowngrade(): Unit = {
    TestUtils.waitUntilControllerElected(zkClient)

    val controller = servers.filter { server => server.kafkaController.isActive}.head
    val nonControllerServers = servers.filter { server => !server.kafkaController.isActive}
    // We setup the supported features on the broker such that 1/3 of the brokers does not
    // support an expected feature version, while 2/3 brokers support the expected feature
    // version.
    val brokersWithVersionIncompatibility = Set[KafkaServer](nonControllerServers.head)
    val versionCompatibleBrokers = Set[KafkaServer](nonControllerServers(1), controller)

    val supportedFeatures = Features.supportedFeatures(
      Utils.mkMap(
        Utils.mkEntry("feature_1", new SupportedVersionRange(1, 3)),
        Utils.mkEntry("feature_2", new SupportedVersionRange(2, 5))))
    updateSupportedFeatures(supportedFeatures, versionCompatibleBrokers)

    val supportedFeaturesWithVersionIncompatibility = Features.supportedFeatures(
      Utils.mkMap(
        Utils.mkEntry("feature_1", new SupportedVersionRange(1, 2)),
        Utils.mkEntry("feature_2", supportedFeatures.get("feature_2"))))
    updateSupportedFeatures(supportedFeaturesWithVersionIncompatibility, brokersWithVersionIncompatibility)

    val initialFinalizedFeatures = Features.finalizedFeatures(
      Utils.mkMap(
        Utils.mkEntry("feature_1", new FinalizedVersionRange(1, 2)),
        Utils.mkEntry("feature_2", new FinalizedVersionRange(2, 4))))
    val versionBefore = updateFeatureZNode(initialFinalizedFeatures)

    // Below we aim to do the following:
    // - Invalid upgrade of feature_1 maxVersionLevel from 2 to 3
    //   (because one of the brokers does not support the max version: 3)
    // - Valid downgrade of feature_2 maxVersionLevel from 4 to 3
    val targetFinalizedFeatures = Features.finalizedFeatures(
      Utils.mkMap(
        Utils.mkEntry("feature_1", new FinalizedVersionRange(1, 3)),
        Utils.mkEntry("feature_2", new FinalizedVersionRange(2, 3))))
    val invalidUpdate = new FeatureUpdate(targetFinalizedFeatures.get("feature_1").max(), false)
    val validUpdate = new FeatureUpdate(targetFinalizedFeatures.get("feature_2").max(), true)

    val adminClient = createAdminClient()
    val result = adminClient.updateFeatures(
      Utils.mkMap(Utils.mkEntry("feature_1", invalidUpdate), Utils.mkEntry("feature_2", validUpdate)),
      new UpdateFeaturesOptions())

    // Expect update for "feature_2" to have succeeded.
    result.values().get("feature_2").get()
    // Expect update for "feature_1" to have failed.
    checkException[InvalidRequestException](result, Map("feature_1" -> ".*brokers.*incompatible.*".r))
    val expectedFeatures = Features.finalizedFeatures(
      Utils.mkMap(
        Utils.mkEntry("feature_1", initialFinalizedFeatures.get("feature_1")),
        Utils.mkEntry("feature_2", targetFinalizedFeatures.get("feature_2"))))
    checkFeatures(
      adminClient,
      FeatureZNode(FeatureZNodeStatus.Enabled, expectedFeatures),
      expectedFeatures,
      versionBefore + 1,
      supportedFeatures)
  }
}

redpajama_set_name: RedPajamaGithub


text:
<?php

// Disallow direct access to this file
defined('_JEXEC') or die('Restricted access');
?>
<fieldset class="adminform">
	<legend><?php echo JText::_('COM_COMMUNITY_CONFIGURATION_JSNETWORK');?></legend>

					<span class="hasTip" title="::<?php echo JText::_('COM_COMMUNITY_CONFIGURATION_JSNETWORK_ENABLE_TIPS'); ?>">
						<?php echo JText::_( 'COM_COMMUNITY_CONFIGURATION_JSNETWORK_ENABLE' ); ?>

				<?php echo $this->lists['enable']; ?>

					<span class="hasTip" title="::<?php echo JText::_('COM_COMMUNITY_CONFIGURATION_JSNETWORK_DESCRIPTION_TIPS'); ?>">
						<?php echo JText::_( 'COM_COMMUNITY_CONFIGURATION_JSNETWORK_DESCRIPTION' ); ?>

				<input type="text" class="inputbox" name="network_description" id="description" size="80" value="<?php echo $this->JSNInfo['network_description']; ?>">

					<span class="hasTip" title="::<?php echo JText::_('COM_COMMUNITY_CONFIGURATION_JSNETWORK_TAGS_TIPS'); ?>">
						<?php echo JText::_( 'COM_COMMUNITY_CONFIGURATION_JSNETWORK_TAGS' ); ?>

				<input type="text" class="inputbox" name="network_keywords" id="keywords" size="80" value="<?php echo $this->JSNInfo['network_keywords']; ?>">

					<span class="hasTip" title="::<?php echo JText::_('COM_COMMUNITY_CONFIGURATION_JSNETWORK_JOIN_URL_TIPS'); ?>">
						<?php echo JText::_( 'COM_COMMUNITY_CONFIGURATION_JSNETWORK_JOIN_URL' ); ?>

					<input type="text" class="inputbox" name="network_join_url" id="join_url" size="80" value="<?php echo $this->JSNInfo['network_join_url'] ?>">

					<span class="hasTip" title="::<?php echo JText::_('COM_COMMUNITY_CONFIGURATION_JSNETWORK_UPDATE_INTERVAL_TIPS'); ?>">
						<?php echo JText::_( 'COM_COMMUNITY_CONFIGURATION_JSNETWORK_UPDATE_INTERVAL' ); ?>

				<input type="text" class="inputbox" name="network_cron_freq" id="cron_freq" value="<?php echo $this->JSNInfo['network_cron_freq']; ?>"> (<?php echo JText::_('COM_COMMUNITY_HOURS');?>)

					<span class="hasTip" title="::<?php echo JText::_('COM_COMMUNITY_CONFIGURATION_JSNETWORK_UPLOAD_LOGO_TIPS'); ?>">
						<?php echo JText::_( 'COM_COMMUNITY_CONFIGURATION_JSNETWORK_UPLOAD_LOGO' ); ?>

					<input class="inputbox" type="file" id="file-upload" name="network_Filedata" style="color: #666;" />
					<input type="checkbox" class="inputbox" name="network_replace_image" id="replace_image" value="1">
					<?php echo JText::_('COM_COMMUNITY_REPLACE_IMAGE');?>

			<?php if( $this->JSNInfo['network_logo_url'] ) { ?>

					<span class="hasTip" title="::<?php echo JText::_('COM_COMMUNITY_CONFIGURATION_JSNETWORK_CURRENT_LOGO_TIPS'); ?>">
						<?php echo JText::_( 'COM_COMMUNITY_CONFIGURATION_JSNETWORK_CURRENT_LOGO' ); ?>

					<?php echo JHTML::_('image', $this->JSNInfo['network_logo_url'], '', ''); ?>
					<input type="hidden" name="network_logo_url" value="<?php echo $this->JSNInfo['network_logo_url'] ?>" />

			<?php } ?>

	<input type="hidden" name="network_cron_last_run" value="<?php echo $this->JSNInfo['network_cron_last_run'] ?>" />
</fieldset>


text:
layout: post
title: "Gar Shatterkeel"
date: 2017-09-10
tags: [medium, humanoid, cr9, elemental-evil]
---

**Medium humanoid (human), neutral evil**

**Armor Class** 16 (natural armor)

**Hit Points** 30 (15d8+45)

**Speed** 30 ft., swim 30 ft.

|   STR   |   DEX   |   CON   |   INT   |   WIS   |   CHA   |
|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|
| 15 (+2) | 15 (+2) | 16 (+3) | 12 (+1) | 18 (+4) | 13 (+1) |

**Skills** Nature +8, Survival +8

**Damage Resistances** cold

**Languages** Aquan, Common

**Challenge** 9 (5,000 XP)

***Amphibious.*** Gar can breathe air and water.

***Legendary Resistance (2/Day).*** If Gar fails a saving throw, he can choose to succeed instead.

***Spellcasting.*** Gar is a 9th-level spellcaster. His spellcasting ability is Wisdom (spell save DC 16, +8 to hit with spell attacks). He has the following druid spells prepared:

* Cantrips (at will): mending, resistance, shape water

* 1st level (4 slots): create or destroy water, cure wounds, fog cloud, thunderwave

* 2nd level (3 slots): darkvision, hold person, protection from poison

* 3rd level (3 slots): call lightning, sleet storm, tidal wave

* 4th level (3 slots): control water, ice storm

* 5th level (1 slot): scrying

***Water Walk.*** Gar can stand and move on liquid surfaces as if they were solid ground.

***Watery Fall.*** When Gar drops to 0 hit points, his body collapses into a pool of inky water that rapidly disperses. Anything he was wearing or carrying is left behind.

**Actions**

***Multiattack.*** Gar makes two melee attacks, one with his claw and one with Drown.

***Claw.*** Melee Weapon Attack: +6 to hit, reach 5 ft., one target. Hit: 9 (2d6 + 2) bludgeoning damage, and the target is grappled (escape DC 13). Until the grapple ends, Gar can't attack other creatures with his claw.

***Drown.*** Melee or Ranged Weapon Attack: +7 to hit, reach 5 ft. or range 20/60 ft., one target. Hit: 6 (1d6 + 3) piercing damage plus 4 (1d8) cold damage.


text:
import {Component, ViewChild, OnInit} from '@angular/core';
import {WeatherService} from "./weather.service";
import {Weather} from "./weather";
import {ModalDirective} from 'ngx-bootstrap/modal';
import {setCurrentPosition} from "../../common/utils";

@Component({
    selector: 'weather',
    templateUrl: './weather.html',
    styleUrls: ['./weather.scss'],
})
export class WeatherComponent implements OnInit {

    @ViewChild('weatherModal') weatherModal: ModalDirective;

    public weather: Weather;

    constructor(private service: WeatherService) {
    }

    ngOnInit(): void {
        let $weatherModal = jQuery(document.getElementById('weatherModal')).remove();
        jQuery(document.getElementsByClassName('al-content')[0]).append($weatherModal);
        setCurrentPosition();
    }

    showWeatherInfo(): void {
        this.service.getWeatherInfo()
          .subscribe(
            data => {
              this.weather = data as Weather;
              this.showWeatherModal();
            },
            error => {
              console.log('showWeatherInfo error', error);
            },
          );
    }

    showWeatherModal(): void {
        this.weatherModal.show();
    }

    hideWeatherModal(): void {
        this.weatherModal.hide();
    }

}


text:
require "minitest/autorun"
require "pkcs11_protect_server"
require "test/helper"

class TestPkcs11ProtectServerCrypt < Minitest::Test
  include PKCS11
  attr_reader :slots
  attr_reader :slot
  attr_reader :session
  attr_reader :secret_key

  def setup
    $pkcs11 ||= open_ctsw
    @slots = pk.active_slots
    @slot = slots.first

    # Init SO-PIN if not already done.
    if slot.token_info.flags & CKF_TOKEN_INITIALIZED == 0
      slot.init_token('1234', 'test-token')
      assert_match(/^test-token/, slot.token_info.label, "Token label should be set now")
    end
    assert_equal CKF_TOKEN_INITIALIZED, slot.token_info.flags & CKF_TOKEN_INITIALIZED, "Token should be initialized"

    # Init USER-PIN if not already done.
    if slot.token_info.flags & CKF_USER_PIN_INITIALIZED == 0
      s = slot.open(CKF_SERIAL_SESSION | CKF_RW_SESSION)
      assert_equal CKF_RW_SESSION, s.info.flags & CKF_RW_SESSION, "Session should be read/write"
      assert_equal CKS_RW_PUBLIC_SESSION, s.info.state, "Session should be in logoff state"
      s.login(:SO, '1234')
      assert_equal CKS_RW_SO_FUNCTIONS, s.info.state, "Session should be in SO state"
      s.init_pin('1234')
      s.close
    end
    assert_equal CKF_USER_PIN_INITIALIZED, slot.token_info.flags & CKF_USER_PIN_INITIALIZED, "User PIN should be initialized"

    @session = slot.open
    assert_equal CKS_RO_PUBLIC_SESSION, session.info.state, "Session should be in logoff state"
    session.login(:USER, ENV['CRYPTOKI_PIN'] || '1234')
    assert_equal CKS_RO_USER_FUNCTIONS, session.info.state, "Session should be in USER state"

    @secret_key = session.create_object(
      CLASS: CKO_SECRET_KEY,
      KEY_TYPE: CKK_DES2,
      ENCRYPT: true, WRAP: true, DECRYPT: true, UNWRAP: true, TOKEN: false, DERIVE: true,
      USAGE_COUNT: 0, EXPORTABLE: true,
      VALUE: adjust_parity("0123456789abcdef"),
      LABEL: 'test_secret_key')
  end

  def teardown
    @secret_key.destroy
    @session.logout
    @session.close
  end

  def pk
    $pkcs11
  end

  def test_bad_parity
    assert_raises(ProtectServer::CKR_ET_NOT_ODD_PARITY) do
      session.create_object(
        CLASS: CKO_SECRET_KEY,
        KEY_TYPE: CKK_DES2,
        VALUE: "0123456789abcdef",
        LABEL: 'test_secret_key2')
    end
  end

  def test_derive_des_cbc
    pa = ProtectServer::CK_DES3_CBC_PARAMS.new
    pa.data = "1"*16
    pa.iv = "2"*8

    new_key1 = session.derive_key( {ProtectServer::CKM_DES3_DERIVE_CBC => pa}, secret_key,
      CLASS: CKO_SECRET_KEY, KEY_TYPE: CKK_DES2, ENCRYPT: true, DECRYPT: true, SENSITIVE: false )
    refute_equal secret_key[:VALUE], new_key1[:VALUE], 'Derived key shouldn\'t have equal key value'

    new_key2 = session.derive_key( {DES3_DERIVE_CBC:  {data: "1"*16, iv: "2"*16}}, secret_key,
      CLASS: CKO_SECRET_KEY, KEY_TYPE: CKK_DES2, ENCRYPT: true, DECRYPT: true, SENSITIVE: false )
    assert_equal new_key1[:VALUE], new_key2[:VALUE], 'Both derived key should be equal'

    encrypted_key_value = session.encrypt( {DES3_CBC:  "2"*8}, secret_key, "1"*16)
    encrypted_key_value = adjust_parity(encrypted_key_value)
    assert_equal new_key1[:VALUE], encrypted_key_value, 'Encrypted data should equal derived key value'

    assert_equal 3, secret_key[:USAGE_COUNT], 'The secret key should be used 3 times'
  end

  def test_attributes
    assert_equal true, secret_key[:EXPORTABLE], 'CKA_EXTRACTABLE should be usable'
    secret_key[:EXPORTABLE] = false
    assert_equal false, secret_key[:EXPORTABLE], 'CKA_EXTRACTABLE should be usable'

    assert_equal 0, secret_key[:USAGE_COUNT], 'CKA_USAGE_COUNT should be usable'
    secret_key[:USAGE_COUNT] = 5
    assert_equal 5, secret_key[:USAGE_COUNT], 'CKA_USAGE_COUNT should be usable'

    assert_equal false, secret_key[:IMPORT], 'CKA_IMPORT should default to false'
    refute_nil secret_key.attributes.find{|a| a.type==ProtectServer::CKA_EXPORT}, 'CKA_EXPORT should be returned for Object#attributes'
  end
end


text:
using std::string;

static void
utf16ncpy(prUTF16Char *dest, const char *src, int max_len)
{
	prUTF16Char *d = dest;
	const char *c = src;

	do{
		*d++ = *c;
	}while(*c++ != '\0' && --max_len);
}

prMALError
exSDKQueryOutputSettings(
	exportStdParms				*stdParmsP,
	exQueryOutputSettingsRec	*outputSettingsP)
{
	prMALError result = malNoError;

	ExportSettings *privateData	= reinterpret_cast<ExportSettings *>(outputSettingsP->privateData);

	PrSDKExportParamSuite *paramSuite = privateData->exportParamSuite;

	const csSDK_uint32 exID = outputSettingsP->exporterPluginID;
	const csSDK_int32 mgroupIndex = 0;

	csSDK_uint32 videoBitrate = 0;

	if(outputSettingsP->inExportVideo)
	{
		PrTime ticksPerSecond = 0;
		privateData->timeSuite->GetTicksPerSecond(&ticksPerSecond);

		exParamValues width, height, alpha, frameRate, pixelAspectRatio, fieldType;

		paramSuite->GetParamValue(exID, mgroupIndex, ADBEVideoWidth, &width);
		paramSuite->GetParamValue(exID, mgroupIndex, ADBEVideoHeight, &height);
		paramSuite->GetParamValue(exID, mgroupIndex, ADBEVideoAlpha, &alpha);
		paramSuite->GetParamValue(exID, mgroupIndex, ADBEVideoFPS, &frameRate);
		paramSuite->GetParamValue(exID, mgroupIndex, ADBEVideoAspect, &pixelAspectRatio);
		paramSuite->GetParamValue(exID, mgroupIndex, ADBEVideoFieldType, &fieldType);

		outputSettingsP->outVideoWidth = width.value.intValue;
		outputSettingsP->outVideoHeight = height.value.intValue;
		outputSettingsP->outVideoFrameRate = frameRate.value.timeValue;
		outputSettingsP->outVideoAspectNum = pixelAspectRatio.value.ratioValue.numerator;
		outputSettingsP->outVideoAspectDen = pixelAspectRatio.value.ratioValue.denominator;
		outputSettingsP->outVideoFieldType = fieldType.value.intValue;

		exParamValues bitDepth, codec;

		paramSuite->GetParamValue(exID, mgroupIndex, MOXVideoBitDepth, &bitDepth);
		paramSuite->GetParamValue(exID, mgroupIndex, MOXVideoCodec, &codec);

		const MOX_VideoBitDepth depthVal = (MOX_VideoBitDepth)bitDepth.value.intValue;
		const size_t bits_per_sample = (depthVal == VideoBitDepth_8bit ? 8 :
										depthVal == VideoBitDepth_10bit ? 10 :
										depthVal == VideoBitDepth_12bit ? 12 :
										depthVal == VideoBitDepth_16bit ? 16 :
										depthVal == VideoBitDepth_16bit_Float ? 16 :
										depthVal == VideoBitDepth_32bit_Float ? 32 :
										8);

		const size_t channels = (alpha.value.intValue ? 4 : 3);
		const size_t bits_per_frame = width.value.intValue * height.value.intValue * channels * bits_per_sample;
		const float fps = (double)ticksPerSecond / (double)frameRate.value.timeValue;
		const size_t kbits_per_second = (double)bits_per_frame * fps / 1024.0;

		const float multiplier = (codec.value.intValue == VideoCodec_Uncompressed ? 1.0 : 0.5);

		videoBitrate += (double)kbits_per_second * multiplier;
	}

	if(outputSettingsP->inExportAudio)
	{
		exParamValues sampleRate, channelType;
		paramSuite->GetParamValue(exID, mgroupIndex, ADBEAudioRatePerSecond, &sampleRate);
		paramSuite->GetParamValue(exID, mgroupIndex, ADBEAudioNumChannels, &channelType);

		PrAudioChannelType audioFormat = (PrAudioChannelType)channelType.value.intValue;

		if(audioFormat < kPrAudioChannelType_Mono || audioFormat > kPrAudioChannelType_51)
			audioFormat = kPrAudioChannelType_Stereo;

		const int audioChannels = (audioFormat == kPrAudioChannelType_51 ? 6 :
									audioFormat == kPrAudioChannelType_Stereo ? 2 :
									audioFormat == kPrAudioChannelType_Mono ? 1 :
									2);

		outputSettingsP->outAudioSampleRate = sampleRate.value.floatValue;
		outputSettingsP->outAudioChannelType = audioFormat;
		outputSettingsP->outAudioSampleType = kPrAudioSampleType_Compressed;

		exParamValues bitDepth;
		paramSuite->GetParamValue(exID, mgroupIndex, MOXAudioBitDepth, &bitDepth);

		const MOX_AudioBitDepth depthVal = (MOX_AudioBitDepth)bitDepth.value.intValue;
		const size_t bits_per_sample = (depthVal == AudioBitDepth_8bit ? 8 :
										depthVal == AudioBitDepth_16bit ? 16 :
										depthVal == AudioBitDepth_24bit ? 24 :
										depthVal == AudioBitDepth_32bit ? 32 :
										depthVal == AudioBitDepth_32bit_Float ? 32 :
										24);

		videoBitrate += (sampleRate.value.floatValue * audioChannels * bits_per_sample / 1024);
	}

	// outBitratePerSecond in kbps
	outputSettingsP->outBitratePerSecond = videoBitrate;

#if EXPORTMOD_VERSION >= 5
	// always doing maximum precision
	outputSettingsP->outUseMaximumRenderPrecision = kPrTrue;
#endif

	return result;
}

prMALError
exSDKGenerateDefaultParams(
	exportStdParms				*stdParms,
	exGenerateDefaultParamRec	*generateDefaultParamRec)
{
	prMALError				result				= malNoError;

	ExportSettings			*lRec				= reinterpret_cast<ExportSettings *>(generateDefaultParamRec->privateData);
	PrSDKExportParamSuite	*exportParamSuite	= lRec->exportParamSuite;
	PrSDKExportInfoSuite	*exportInfoSuite	= lRec->exportInfoSuite;
	PrSDKTimeSuite			*timeSuite			= lRec->timeSuite;

	csSDK_int32 exID = generateDefaultParamRec->exporterPluginID;
	csSDK_int32 gIdx = 0;

	// get current settings
	PrParam widthP, heightP, parN, parD, fieldTypeP, frameRateP, channelsTypeP, sampleRateP;

	exportInfoSuite->GetExportSourceInfo(exID, kExportInfo_VideoWidth, &widthP);
	exportInfoSuite->GetExportSourceInfo(exID, kExportInfo_VideoHeight, &heightP);
	exportInfoSuite->GetExportSourceInfo(exID, kExportInfo_PixelAspectNumerator, &parN);
	exportInfoSuite->GetExportSourceInfo(exID, kExportInfo_PixelAspectDenominator, &parD);
	exportInfoSuite->GetExportSourceInfo(exID, kExportInfo_VideoFieldType, &fieldTypeP);
	exportInfoSuite->GetExportSourceInfo(exID, kExportInfo_VideoFrameRate, &frameRateP);
	exportInfoSuite->GetExportSourceInfo(exID, kExportInfo_AudioChannelsType, &channelsTypeP);
	exportInfoSuite->GetExportSourceInfo(exID, kExportInfo_AudioSampleRate, &sampleRateP);

	if(widthP.mInt32 == 0)
	{
		widthP.mInt32 = 1920;
	}

	if(heightP.mInt32 == 0)
	{
		heightP.mInt32 = 1080;
	}

	prUTF16Char groupString[256];

	// Video Tab
	exportParamSuite->AddMultiGroup(exID, &gIdx);

	utf16ncpy(groupString, "Video Tab", 255);
	exportParamSuite->AddParamGroup(exID, gIdx,
									ADBETopParamGroup, ADBEVideoTabGroup, groupString,
									kPrFalse, kPrFalse, kPrFalse);

	// Image Settings group
	utf16ncpy(groupString, "Video Settings", 255);
	exportParamSuite->AddParamGroup(exID, gIdx,
									ADBEVideoTabGroup, ADBEBasicVideoGroup, groupString,
									kPrFalse, kPrFalse, kPrFalse);

	// width
	exParamValues widthValues;
	widthValues.structVersion = 1;
	widthValues.rangeMin.intValue = 16;
	widthValues.rangeMax.intValue = 8192;
	widthValues.value.intValue = widthP.mInt32;
	widthValues.disabled = kPrFalse;
	widthValues.hidden = kPrFalse;

	exNewParamInfo widthParam;
	widthParam.structVersion = 1;
	strncpy(widthParam.identifier, ADBEVideoWidth, 255);
	widthParam.paramType = exParamType_int;
	widthParam.flags = exParamFlag_none;
	widthParam.paramValues = widthValues;

	exportParamSuite->AddParam(exID, gIdx, ADBEBasicVideoGroup, &widthParam);

	// height
	exParamValues heightValues;
	heightValues.structVersion = 1;
	heightValues.rangeMin.intValue = 16;
	heightValues.rangeMax.intValue = 8192;
	heightValues.value.intValue = heightP.mInt32;
	heightValues.disabled = kPrFalse;
	heightValues.hidden = kPrFalse;

	exNewParamInfo heightParam;
	heightParam.structVersion = 1;
	strncpy(heightParam.identifier, ADBEVideoHeight, 255);
	heightParam.paramType = exParamType_int;
	heightParam.flags = exParamFlag_none;
	heightParam.paramValues = heightValues;

	exportParamSuite->AddParam(exID, gIdx, ADBEBasicVideoGroup, &heightParam);

	// pixel aspect ratio
	exParamValues parValues;
	parValues.structVersion = 1;
	parValues.rangeMin.ratioValue.numerator = 10;
	parValues.rangeMin.ratioValue.denominator = 11;
	parValues.rangeMax.ratioValue.numerator = 2;
	parValues.rangeMax.ratioValue.denominator = 1;
	parValues.value.ratioValue.numerator = parN.mInt32;
	parValues.value.ratioValue.denominator = parD.mInt32;
	parValues.disabled = kPrFalse;
	parValues.hidden = kPrFalse;

	exNewParamInfo parParam;
	parParam.structVersion = 1;
	strncpy(parParam.identifier, ADBEVideoAspect, 255);
	parParam.paramType = exParamType_ratio;
	parParam.flags = exParamFlag_none;
	parParam.paramValues = parValues;

	exportParamSuite->AddParam(exID, gIdx, ADBEBasicVideoGroup, &parParam);

	// field order
	if(fieldTypeP.mInt32 == prFieldsUnknown)
		fieldTypeP.mInt32 = prFieldsNone;

	exParamValues fieldOrderValues;
	fieldOrderValues.structVersion = 1;
	fieldOrderValues.value.intValue = fieldTypeP.mInt32;
	fieldOrderValues.disabled = kPrFalse;
	fieldOrderValues.hidden = kPrFalse;

	exNewParamInfo fieldOrderParam;
	fieldOrderParam.structVersion = 1;
	strncpy(fieldOrderParam.identifier, ADBEVideoFieldType, 255);
	fieldOrderParam.paramType = exParamType_int;
	fieldOrderParam.flags = exParamFlag_none;
	fieldOrderParam.paramValues = fieldOrderValues;

	exportParamSuite->AddParam(exID, gIdx, ADBEBasicVideoGroup, &fieldOrderParam);

	// frame rate
	exParamValues fpsValues;
	fpsValues.structVersion = 1;
	fpsValues.rangeMin.timeValue = 1;
	timeSuite->GetTicksPerSecond(&fpsValues.rangeMax.timeValue);
	fpsValues.value.timeValue = frameRateP.mInt64;
	fpsValues.disabled = kPrFalse;
	fpsValues.hidden = kPrFalse;

	exNewParamInfo fpsParam;
	fpsParam.structVersion = 1;
	strncpy(fpsParam.identifier, ADBEVideoFPS, 255);
	fpsParam.paramType = exParamType_ticksFrameRate;
	fpsParam.flags = exParamFlag_none;
	fpsParam.paramValues = fpsValues;

	exportParamSuite->AddParam(exID, gIdx, ADBEBasicVideoGroup, &fpsParam);

	// Alpha channel
	exParamValues alphaValues;
	alphaValues.structVersion = 1;
	alphaValues.value.intValue = kPrFalse;
	alphaValues.disabled = kPrFalse;
	alphaValues.hidden = kPrFalse;

	exNewParamInfo alphaParam;
	alphaParam.structVersion = 1;
	strncpy(alphaParam.identifier, ADBEVideoAlpha, 255);
	alphaParam.paramType = exParamType_bool;
	alphaParam.flags = exParamFlag_none;
	alphaParam.paramValues = alphaValues;

	exportParamSuite->AddParam(exID, gIdx, ADBEBasicVideoGroup, &alphaParam);

	// Video Codec Settings Group
	utf16ncpy(groupString, "Codec settings", 255);
	exportParamSuite->AddParamGroup(exID, gIdx,
									ADBEVideoTabGroup, ADBEVideoCodecGroup, groupString,
									kPrFalse, kPrFalse, kPrFalse);

	// Bit depth
	exParamValues videoBitDepthValues;
	videoBitDepthValues.structVersion = 1;
	videoBitDepthValues.rangeMin.intValue = VideoBitDepth_8bit;
	videoBitDepthValues.rangeMax.intValue = VideoBitDepth_32bit_Float;
	videoBitDepthValues.value.intValue = VideoBitDepth_8bit;
	videoBitDepthValues.disabled = kPrFalse;
	videoBitDepthValues.hidden = kPrFalse;

	exNewParamInfo videoBitDepthParam;
	videoBitDepthParam.structVersion = 1;
	strncpy(videoBitDepthParam.identifier, MOXVideoBitDepth, 255);
	videoBitDepthParam.paramType = exParamType_int;
	videoBitDepthParam.flags = exParamFlag_none;
	videoBitDepthParam.paramValues = videoBitDepthValues;

	exportParamSuite->AddParam(exID, gIdx, ADBEVideoCodecGroup, &videoBitDepthParam);

	// Lossless
	exParamValues losslessValues;
	losslessValues.structVersion = 1;
	losslessValues.value.intValue = kPrTrue;
	losslessValues.disabled = kPrFalse;
	losslessValues.hidden = kPrFalse;

	exNewParamInfo losslessParam;
	losslessParam.structVersion = 1;
	strncpy(losslessParam.identifier, MOXLossless, 255);
	losslessParam.paramType = exParamType_bool;
	losslessParam.flags = exParamFlag_none;
	losslessParam.paramValues = losslessValues;

	exportParamSuite->AddParam(exID, gIdx, ADBEVideoCodecGroup, &losslessParam);

	// Quality
	exParamValues qualityValues;
	qualityValues.structVersion = 1;
	qualityValues.rangeMin.intValue = 1;
	qualityValues.rangeMax.intValue = 100;
	qualityValues.value.intValue = 80;
	qualityValues.disabled = kPrTrue;
	qualityValues.hidden = kPrFalse;

	exNewParamInfo qualityParam;
	qualityParam.structVersion = 1;
	strncpy(qualityParam.identifier, MOXQuality, 255);
	qualityParam.paramType = exParamType_int;
	qualityParam.flags = exParamFlag_slider;
	qualityParam.paramValues = qualityValues;

	exportParamSuite->AddParam(exID, gIdx, ADBEVideoCodecGroup, &qualityParam);

	// Codec
	exParamValues codecValues;
	codecValues.structVersion = 1;
	codecValues.rangeMin.intValue = VideoCodec_Auto;
	codecValues.rangeMax.intValue = VideoCodec_Uncompressed;
	codecValues.value.intValue = VideoCodec_Auto;
	codecValues.disabled = kPrFalse;
	codecValues.hidden = kPrFalse;

	exNewParamInfo codecParam;
	codecParam.structVersion = 1;
	strncpy(codecParam.identifier, MOXVideoCodec, 255);
	codecParam.paramType = exParamType_int;
	codecParam.flags = exParamFlag_none;
	codecParam.paramValues = codecValues;

	exportParamSuite->AddParam(exID, gIdx, ADBEVideoCodecGroup, &codecParam);

	// Version
	exParamValues versionValues;
	versionValues.structVersion = 1;
	versionValues.rangeMin.intValue = 0;
	versionValues.rangeMax.intValue = INT_MAX;
	versionValues.value.intValue = MOX_PLUGIN_VERSION_MAJOR << 16 |
									MOX_PLUGIN_VERSION_MINOR << 8 |
									MOX_PLUGIN_VERSION_BUILD;
	versionValues.disabled = kPrTrue;
	versionValues.hidden = kPrTrue;

	exNewParamInfo versionParam;
	versionParam.structVersion = 1;
	strncpy(versionParam.identifier, MOXPluginVersion, 255);
	versionParam.paramType = exParamType_int;
	versionParam.flags = exParamFlag_none;
	versionParam.paramValues = versionValues;

	exportParamSuite->AddParam(exID, gIdx, MOXPluginVersion, &versionParam);

	// Audio Tab
	utf16ncpy(groupString, "Audio Tab", 255);
	exportParamSuite->AddParamGroup(exID, gIdx,
									ADBETopParamGroup, ADBEAudioTabGroup, groupString,
									kPrFalse, kPrFalse, kPrFalse);

	// Audio Settings group
	utf16ncpy(groupString, "Audio Settings", 255);
	exportParamSuite->AddParamGroup(exID, gIdx,
									ADBEAudioTabGroup, ADBEBasicAudioGroup, groupString,
									kPrFalse, kPrFalse, kPrFalse);

	// Sample rate
	exParamValues sampleRateValues;
	sampleRateValues.value.floatValue = sampleRateP.mFloat64;
	sampleRateValues.disabled = kPrFalse;
	sampleRateValues.hidden = kPrFalse;

	exNewParamInfo sampleRateParam;
	sampleRateParam.structVersion = 1;
	strncpy(sampleRateParam.identifier, ADBEAudioRatePerSecond, 255);
	sampleRateParam.paramType = exParamType_float;
	sampleRateParam.flags = exParamFlag_none;
	sampleRateParam.paramValues = sampleRateValues;

	exportParamSuite->AddParam(exID, gIdx, ADBEBasicAudioGroup, &sampleRateParam);

	// Channel type
	exParamValues channelTypeValues;
	channelTypeValues.value.intValue = channelsTypeP.mInt32;
	channelTypeValues.disabled = kPrFalse;
	channelTypeValues.hidden = kPrFalse;

	exNewParamInfo channelTypeParam;
	channelTypeParam.structVersion = 1;
	strncpy(channelTypeParam.identifier, ADBEAudioNumChannels, 255);
	channelTypeParam.paramType = exParamType_int;
	channelTypeParam.flags = exParamFlag_none;
	channelTypeParam.paramValues = channelTypeValues;

	exportParamSuite->AddParam(exID, gIdx, ADBEBasicAudioGroup, &channelTypeParam);

	// Audio Codec Settings Group
	utf16ncpy(groupString, "Codec settings", 255);
	exportParamSuite->AddParamGroup(exID, gIdx,
									ADBEAudioTabGroup, ADBEAudioCodecGroup, groupString,
									kPrFalse, kPrFalse, kPrFalse);

	// Bit depth
	exParamValues audioBitDepthValues;
	audioBitDepthValues.structVersion = 1;
	audioBitDepthValues.rangeMin.intValue = AudioBitDepth_8bit;
	audioBitDepthValues.rangeMax.intValue = AudioBitDepth_32bit_Float;
	audioBitDepthValues.value.intValue = AudioBitDepth_24bit;
	audioBitDepthValues.disabled = kPrFalse;
	audioBitDepthValues.hidden = kPrFalse;

	exNewParamInfo audioBitDepthParam;
	audioBitDepthParam.structVersion = 1;
	strncpy(audioBitDepthParam.identifier, MOXAudioBitDepth, 255);
	audioBitDepthParam.paramType = exParamType_int;
	audioBitDepthParam.flags = exParamFlag_none;
	audioBitDepthParam.paramValues = audioBitDepthValues;

	exportParamSuite->AddParam(exID, gIdx, ADBEAudioCodecGroup, &audioBitDepthParam);

	exportParamSuite->SetParamsVersion(exID, 1);

	return result;
}

prMALError
exSDKPostProcessParams(
	exportStdParms			*stdParmsP,
	exPostProcessParamsRec	*postProcessParamsRecP)
{
	prMALError		result	= malNoError;

	ExportSettings			*lRec				= reinterpret_cast<ExportSettings *>(postProcessParamsRecP->privateData);
	PrSDKExportParamSuite	*exportParamSuite	= lRec->exportParamSuite;
	//PrSDKExportInfoSuite	*exportInfoSuite	= lRec->exportInfoSuite;
	PrSDKTimeSuite			*timeSuite			= lRec->timeSuite;

	csSDK_int32 exID = postProcessParamsRecP->exporterPluginID;
	csSDK_int32 gIdx = 0;

	prUTF16Char paramString[256];

	// Image Settings group
	utf16ncpy(paramString, "Image Settings", 255);
	exportParamSuite->SetParamName(exID, gIdx, ADBEBasicVideoGroup, paramString);

	// width
	utf16ncpy(paramString, "Width", 255);
	exportParamSuite->SetParamName(exID, gIdx, ADBEVideoWidth, paramString);

	exParamValues widthValues;
	exportParamSuite->GetParamValue(exID, gIdx, ADBEVideoWidth, &widthValues);

	widthValues.rangeMin.intValue = 16;
	widthValues.rangeMax.intValue = 8192;

	exportParamSuite->ChangeParam(exID, gIdx, ADBEVideoWidth, &widthValues);

	// height
	utf16ncpy(paramString, "Height", 255);
	exportParamSuite->SetParamName(exID, gIdx, ADBEVideoHeight, paramString);

	exParamValues heightValues;
	exportParamSuite->GetParamValue(exID, gIdx, ADBEVideoHeight, &heightValues);

	heightValues.rangeMin.intValue = 16;
	heightValues.rangeMax.intValue = 8192;

	exportParamSuite->ChangeParam(exID, gIdx, ADBEVideoHeight, &heightValues);

	// pixel aspect ratio
	utf16ncpy(paramString, "Pixel Aspect Ratio", 255);
	exportParamSuite->SetParamName(exID, gIdx, ADBEVideoAspect, paramString);

	csSDK_int32	PARs[][2] = {{1, 1}, {10, 11}, {40, 33}, {768, 702},
							{1024, 702}, {2, 1}, {4, 3}, {3, 2}};

	const char *PARStrings[] = {"Square pixels (1.0)",
								"D1/DV NTSC (0.9091)",
								"D1/DV NTSC Widescreen 16:9 (1.2121)",
								"D1/DV PAL (1.0940)",
								"D1/DV PAL Widescreen 16:9 (1.4587)",
								"Anamorphic 2:1 (2.0)",
								"HD Anamorphic 1080 (1.3333)",
								"DVCPRO HD (1.5)"};

	exportParamSuite->ClearConstrainedValues(exID, gIdx, ADBEVideoAspect);

	exOneParamValueRec tempPAR;

	for(csSDK_int32 i=0; i < sizeof (PARs) / sizeof(PARs[0]); i++)
	{
		tempPAR.ratioValue.numerator = PARs[i][0];
		tempPAR.ratioValue.denominator = PARs[i][1];
		utf16ncpy(paramString, PARStrings[i], 255);
		exportParamSuite->AddConstrainedValuePair(exID, gIdx, ADBEVideoAspect, &tempPAR, paramString);
	}

	// field type
	utf16ncpy(paramString, "Field Type", 255);
	exportParamSuite->SetParamName(exID, gIdx, ADBEVideoFieldType, paramString);

	csSDK_int32	fieldOrders[] = {	prFieldsUpperFirst,
									prFieldsLowerFirst,
									prFieldsNone};

	const char *fieldOrderStrings[]	= {	"Upper First",
										"Lower First",
										"None"};

	exportParamSuite->ClearConstrainedValues(exID, gIdx, ADBEVideoFieldType);

	exOneParamValueRec tempFieldOrder;
	for(int i=0; i < 3; i++)
	{
		tempFieldOrder.intValue = fieldOrders[i];
		utf16ncpy(paramString, fieldOrderStrings[i], 255);
		exportParamSuite->AddConstrainedValuePair(exID, gIdx, ADBEVideoFieldType, &tempFieldOrder, paramString);
	}

	// frame rate
	utf16ncpy(paramString, "Frame Rate", 255);
	exportParamSuite->SetParamName(exID, gIdx, ADBEVideoFPS, paramString);

	PrTime frameRates[] = {	10, 15, 23,
							24, 25, 29,
							30, 48, 48,
							50, 59, 60};

	static const PrTime frameRateNumDens[][2] = {	{10, 1}, {15, 1}, {24000, 1001},
													{24, 1}, {25, 1}, {30000, 1001},
													{30, 1}, {48000, 1001}, {48, 1},
													{50, 1}, {60000, 1001}, {60, 1}};

	static const char *frameRateStrings[] = {	"10",
												"15",
												"23.976",
												"24",
												"25 (PAL)",
												"29.97 (NTSC)",
												"30",
												"47.952",
												"48",
												"50",
												"59.94",
												"60"};

	PrTime ticksPerSecond = 0;
	timeSuite->GetTicksPerSecond(&ticksPerSecond);

	for(csSDK_int32 i=0; i < sizeof(frameRates) / sizeof (PrTime); i++)
	{
		frameRates[i] = ticksPerSecond / frameRateNumDens[i][0] * frameRateNumDens[i][1];

		// is there overflow potential here?
		assert(frameRates[i] == ticksPerSecond * frameRateNumDens[i][1] / frameRateNumDens[i][0]);
	}

	exportParamSuite->ClearConstrainedValues(exID, gIdx, ADBEVideoFPS);

	exOneParamValueRec tempFrameRate;

	for(csSDK_int32 i=0; i < sizeof(frameRates) / sizeof (PrTime); i++)
	{
		tempFrameRate.timeValue = frameRates[i];
		utf16ncpy(paramString, frameRateStrings[i], 255);
		exportParamSuite->AddConstrainedValuePair(exID, gIdx, ADBEVideoFPS, &tempFrameRate, paramString);
	}

	// Alpha channel
	utf16ncpy(paramString, "Include Alpha Channel", 255);
	exportParamSuite->SetParamName(exID, gIdx, ADBEVideoAlpha, paramString);

	// Video codec settings
	utf16ncpy(paramString, "Codec settings", 255);
	exportParamSuite->SetParamName(exID, gIdx, ADBEVideoCodecGroup, paramString);

	// Video bit depth
	utf16ncpy(paramString, "Bit Depth", 255);
	exportParamSuite->SetParamName(exID, gIdx, MOXVideoBitDepth, paramString);

	const MOX_VideoBitDepth videoBitDepths[] = {	VideoBitDepth_8bit,
													VideoBitDepth_16bit,
													VideoBitDepth_16bit_Float,
													VideoBitDepth_32bit_Float };

	const char *videoBitDepthStrings[] = {	"8-bit",
											"16-bit",
											"16-bit float",
											"32-bit float" };

	exportParamSuite->ClearConstrainedValues(exID, gIdx, MOXVideoBitDepth);

	exOneParamValueRec tempVideoBitDepth;

	for(csSDK_int32 i=0; i < sizeof(videoBitDepths) / sizeof(MOX_VideoBitDepth); i++)
	{
		tempVideoBitDepth.intValue = videoBitDepths[i];
		utf16ncpy(paramString, videoBitDepthStrings[i], 255);
		exportParamSuite->AddConstrainedValuePair(exID, gIdx, MOXVideoBitDepth, &tempVideoBitDepth, paramString);
	}

	// Lossless
	utf16ncpy(paramString, "Lossless", 255);
	exportParamSuite->SetParamName(exID, gIdx, MOXLossless, paramString);

	// Quality
	utf16ncpy(paramString, "Quality", 255);
	exportParamSuite->SetParamName(exID, gIdx, MOXQuality, paramString);

	exParamValues qualityValues;
	exportParamSuite->GetParamValue(exID, gIdx, MOXQuality, &qualityValues);

	qualityValues.rangeMin.intValue = 1;
	qualityValues.rangeMax.intValue = 100;

	exportParamSuite->ChangeParam(exID, gIdx, MOXQuality, &qualityValues);

	// Video codec
	utf16ncpy(paramString, "Codec", 255);
	exportParamSuite->SetParamName(exID, gIdx, MOXVideoCodec, paramString);

	const MOX_VideoCodec videoCodecs[] = {	VideoCodec_Auto,
											VideoCodec_Dirac,
											VideoCodec_OpenEXR,
											VideoCodec_JPEG,
											VideoCodec_JPEG2000,
											VideoCodec_JPEGLS,
											VideoCodec_PNG,
											VideoCodec_DPX,
											VideoCodec_Uncompressed };

	const char *videoCodecStrings[] = { "Auto",
										"Dirac",
										"OpenEXR",
										"JPEG",
										"JPEG 2000",
										"JPEG-LS",
										"PNG",
										"DPX",
										"Uncompressed" };

	exportParamSuite->ClearConstrainedValues(exID, gIdx, MOXVideoCodec);

	exOneParamValueRec tempVideoCodec;

	for(csSDK_int32 i=0; i < sizeof(videoCodecs) / sizeof(MOX_VideoCodec); i++)
	{
		tempVideoCodec.intValue = videoCodecs[i];
		utf16ncpy(paramString, videoCodecStrings[i], 255);
		exportParamSuite->AddConstrainedValuePair(exID, gIdx, MOXVideoCodec, &tempVideoCodec, paramString);
	}

	// Audio Settings group
	utf16ncpy(paramString, "Audio Settings", 255);
	exportParamSuite->SetParamName(exID, gIdx, ADBEBasicAudioGroup, paramString);

	// Sample rate
	utf16ncpy(paramString, "Sample Rate", 255);
	exportParamSuite->SetParamName(exID, gIdx, ADBEAudioRatePerSecond, paramString);

	float sampleRates[] = { 8000.0f, 16000.0f, 32000.0f, 44100.0f, 48000.0f, 96000.0f };

	const char *sampleRateStrings[] = { "8000 Hz", "16000 Hz", "32000 Hz", "44100 Hz", "48000 Hz", "96000 Hz" };

	exportParamSuite->ClearConstrainedValues(exID, gIdx, ADBEAudioRatePerSecond);

	exOneParamValueRec tempSampleRate;

	for(csSDK_int32 i=0; i < sizeof(sampleRates) / sizeof(float); i++)
	{
		tempSampleRate.floatValue = sampleRates[i];
		utf16ncpy(paramString, sampleRateStrings[i], 255);
		exportParamSuite->AddConstrainedValuePair(exID, gIdx, ADBEAudioRatePerSecond, &tempSampleRate, paramString);
	}

	// Channels
	utf16ncpy(paramString, "Channels", 255);
	exportParamSuite->SetParamName(exID, gIdx, ADBEAudioNumChannels, paramString);

	csSDK_int32 channelTypes[] = { kPrAudioChannelType_Mono,
									kPrAudioChannelType_Stereo,
									kPrAudioChannelType_51 };

	const char *channelTypeStrings[] = { "Mono", "Stereo", "Dolby 5.1" };

	exportParamSuite->ClearConstrainedValues(exID, gIdx, ADBEAudioNumChannels);

	exOneParamValueRec tempChannelType;

	for(csSDK_int32 i=0; i < sizeof(channelTypes) / sizeof(csSDK_int32); i++)
	{
		tempChannelType.intValue = channelTypes[i];
		utf16ncpy(paramString, channelTypeStrings[i], 255);
		exportParamSuite->AddConstrainedValuePair(exID, gIdx, ADBEAudioNumChannels, &tempChannelType, paramString);
	}

	// Audio codec settings
	utf16ncpy(paramString, "Codec settings", 255);
	exportParamSuite->SetParamName(exID, gIdx, ADBEAudioCodecGroup, paramString);

	// Audio bit depth
	utf16ncpy(paramString, "Bit Depth", 255);
	exportParamSuite->SetParamName(exID, gIdx, MOXAudioBitDepth, paramString);

	MOX_AudioBitDepth audioBitDepths[] = { AudioBitDepth_8bit, AudioBitDepth_16bit, AudioBitDepth_24bit };

	const char *audioBitDepthStrings[] = { "8-bit", "16-bit", "24-bit" };

	exportParamSuite->ClearConstrainedValues(exID, gIdx, MOXAudioBitDepth);

	exOneParamValueRec tempAudioBitDepth;

	for(csSDK_int32 i=0; i < sizeof(audioBitDepths) / sizeof(MOX_AudioBitDepth); i++)
	{
		tempAudioBitDepth.intValue = audioBitDepths[i];
		utf16ncpy(paramString, audioBitDepthStrings[i], 255);
		exportParamSuite->AddConstrainedValuePair(exID, gIdx, MOXAudioBitDepth, &tempAudioBitDepth, paramString);
	}

	return result;
}

prMALError
exSDKGetParamSummary(
	exportStdParms			*stdParmsP,
	exParamSummaryRec		*summaryRecP)
{
	ExportSettings			*privateData	= reinterpret_cast<ExportSettings*>(summaryRecP->privateData);
	PrSDKExportParamSuite	*paramSuite		= privateData->exportParamSuite;

	std::string summary1, summary2, summary3;

	csSDK_uint32	exID	= summaryRecP->exporterPluginID;
	csSDK_int32		gIdx	= 0;

	// Standard settings
	exParamValues width, height, frameRate;
	paramSuite->GetParamValue(exID, gIdx, ADBEVideoWidth, &width);
	paramSuite->GetParamValue(exID, gIdx, ADBEVideoHeight, &height);
	paramSuite->GetParamValue(exID, gIdx, ADBEVideoFPS, &frameRate);

	exParamValues bitDepth, lossless, quality, codec;
	paramSuite->GetParamValue(exID, gIdx, MOXVideoBitDepth, &bitDepth);
	paramSuite->GetParamValue(exID, gIdx, MOXLossless, &lossless);
	paramSuite->GetParamValue(exID, gIdx, MOXQuality, &quality);
	paramSuite->GetParamValue(exID, gIdx, MOXVideoCodec, &codec);

	exParamValues sampleRateP, channelTypeP, audioBitDepthP;
	paramSuite->GetParamValue(exID, gIdx, ADBEAudioRatePerSecond, &sampleRateP);
	paramSuite->GetParamValue(exID, gIdx, ADBEAudioNumChannels, &channelTypeP);
	paramSuite->GetParamValue(exID, gIdx, MOXAudioBitDepth, &audioBitDepthP);

	// oh boy, figure out frame rate
	PrTime frameRates[] = {	10, 15, 23,
							24, 25, 29,
							30, 48, 48,
							50, 59, 60};

	static const PrTime frameRateNumDens[][2] = {	{10, 1}, {15, 1}, {24000, 1001},
													{24, 1}, {25, 1}, {30000, 1001},
													{30, 1}, {48000, 1001}, {48, 1},
													{50, 1}, {60000, 1001}, {60, 1}};

	static const char *frameRateStrings[] = {	"10",
												"15",
												"23.976",
												"24",
												"25 (PAL)",
												"29.97 (NTSC)",
												"30",
												"47.952",
												"48",
												"50",
												"59.94",
												"60"};

	PrTime ticksPerSecond = 0;
	privateData->timeSuite->GetTicksPerSecond(&ticksPerSecond);

	csSDK_int32 frame_rate_index = -1;

	for(csSDK_int32 i=0; i < sizeof(frameRates) / sizeof (PrTime); i++)
	{
		frameRates[i] = ticksPerSecond / frameRateNumDens[i][0] * frameRateNumDens[i][1];

		if(frameRates[i] == frameRate.value.timeValue)
			frame_rate_index = i;
	}

	std::stringstream stream1;

	stream1 << width.value.intValue << "x" << height.value.intValue;

	if(frame_rate_index >= 0 && frame_rate_index < 12)
		stream1 << ", " << frameRateStrings[frame_rate_index] << " fps";

	summary1 = stream1.str();

	std::stringstream stream2;

	stream2 << (int)sampleRateP.value.floatValue << " Hz";
	stream2 << ", " << (channelTypeP.value.intValue == kPrAudioChannelType_51 ? "Dolby 5.1" :
						channelTypeP.value.intValue == kPrAudioChannelType_Mono ? "Mono" :
						"Stereo");

	const MOX_AudioBitDepth audioDepthVal = (MOX_AudioBitDepth)audioBitDepthP.value.intValue;
	const std::string audioDepth_str = (audioDepthVal == AudioBitDepth_8bit ? "8-bit" :
										audioDepthVal == AudioBitDepth_16bit ? "16-bit" :
										audioDepthVal == AudioBitDepth_24bit ? "24-bit" :
										audioDepthVal == AudioBitDepth_32bit ? "32-bit" :
										audioDepthVal == AudioBitDepth_32bit_Float ? "32-bit float" :
										"Unknown");
	stream2 << ", " << audioDepth_str;

	summary2 = stream2.str();

	const MOX_VideoBitDepth videoDepth = (MOX_VideoBitDepth)bitDepth.value.intValue;
	const bool videoLossless = lossless.value.intValue;
	const int videoQuality = quality.value.intValue;
	const MOX_VideoCodec videoCodec = (MOX_VideoCodec)codec.value.intValue;

	const std::string bitDepth_str = (videoDepth == VideoBitDepth_8bit ? "8-bit" :
								videoDepth == VideoBitDepth_10bit ? "10-bit" :
								videoDepth == VideoBitDepth_12bit ? "12-bit" :
								videoDepth == VideoBitDepth_16bit ? "16-bit" :
								videoDepth == VideoBitDepth_16bit_Float ? "16-bit float" :
								videoDepth == VideoBitDepth_32bit_Float ? "32-bit float" :
								"Unknown");

	std::stringstream quality_str;

	if(videoLossless)
	{
		quality_str << "Lossless";
	}
	else
	{
		quality_str << "Quality " << videoQuality;
	}

	const std::string codec_str = (videoCodec == VideoCodec_Dirac ? "Dirac" :
									videoCodec == VideoCodec_OpenEXR ? "OpenEXR" :
									videoCodec == VideoCodec_JPEG ? "JPEG" :
									videoCodec == VideoCodec_JPEG2000 ? "JPEG 2000" :
									videoCodec == VideoCodec_JPEGLS ? "JPEG-LS" :
									videoCodec == VideoCodec_PNG ? "PNG" :
									videoCodec == VideoCodec_DPX ? "DPX" :
									videoCodec == VideoCodec_Uncompressed ? "Uncompressed" :
									"Auto");

	std::stringstream stream3;

	stream3 << bitDepth_str << ", " << quality_str.str() << ", "<< codec_str << " codec";

	summary3 = stream3.str();

	utf16ncpy(summaryRecP->Summary1, summary1.c_str(), 255);
	utf16ncpy(summaryRecP->Summary2, summary2.c_str(), 255);
	utf16ncpy(summaryRecP->Summary3, summary3.c_str(), 255);

	return malNoError;
}

prMALError
exSDKValidateParamChanged (
	exportStdParms		*stdParmsP,
	exParamChangedRec	*validateParamChangedRecP)
{
	ExportSettings			*privateData	= reinterpret_cast<ExportSettings*>(validateParamChangedRecP->privateData);
	PrSDKExportParamSuite	*paramSuite		= privateData->exportParamSuite;

	csSDK_int32 exID = validateParamChangedRecP->exporterPluginID;
	csSDK_int32 gIdx = validateParamChangedRecP->multiGroupIndex;

	std::string param = validateParamChangedRecP->changedParamIdentifier;

	if(param == MOXLossless)
	{
		exParamValues losslessValue, qualityValue;

		paramSuite->GetParamValue(exID, gIdx, MOXLossless, &losslessValue);
		paramSuite->GetParamValue(exID, gIdx, MOXQuality, &qualityValue);

		qualityValue.disabled = !!losslessValue.value.intValue;

		paramSuite->ChangeParam(exID, gIdx, MOXQuality, &qualityValue);
	}

	return malNoError;
}


text:
#region LICENSE

// Copyright (c) 2011, Alex Lyman
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
// - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
// - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
//
// Neither the name of Synapse nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using Synapse.Input;
using Synapse.Parsers;
using Synapse.Results;

namespace Synapse.Tests
{
    public class MockSequenceParser<TToken, TResult> : Queue<IParseResult<TToken, TResult>>, IParser<TToken, TResult>
    {
        #region IParser<TToken,TResult> Members

        public IParseResult<TToken, TResult> Parse(IInput<TToken> input)
        {
            return Dequeue();
        }

        #endregion

        public void Add(IParseResult<TToken, TResult> result)
        {
            Enqueue(result);
        }

        public void Add(Func<MockSequenceParser<TToken, TResult>, IParseResult<TToken, TResult>> result)
        {
            Enqueue(result(this));
        }
    }
}


text:
package android.hcartoon.view;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.GridView;

/**
 * Created by Lenovo on 2015/11/18.
 */
public class RecomGridView extends GridView{

    public RecomGridView(Context context) {
        super(context);
    }

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

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
                MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, expandSpec);
    }
}


text:
package com.nirigo.mobile.calendar;

import android.content.Context;
import android.graphics.Color;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.nirigo.mobile.view.calendar.CalendarBaseAdapter;
import com.nirigo.mobile.view.calendar.models.CalendarDate;
import com.nirigo.mobile.view.calendar.models.CalendarDateHeader;

import java.util.Calendar;
import java.util.Date;

/**
 * Created by Sicz-Mesziár János on 2015.04.06..
 * Example for custom adapter.
 */
public class CustomCalendarAdapter extends CalendarBaseAdapter {

    private SparseArray<Integer> weather = new SparseArray<>();
    private ViewHolder holder;
    private int defaultBackground, prevnextBackground, todayBackground, activeText, inactiveText;

    public CustomCalendarAdapter(Context context) {
        super(context);
        defaultBackground = Color.parseColor("#E4F5E5");
        prevnextBackground = Color.parseColor("#C4D1B8");
        todayBackground = Color.parseColor("#F1E9B1");
        activeText = Color.parseColor("#338C38");
        inactiveText = Color.parseColor("#aaaaaa");
    }

    // Weather logic ---------------------
    public void addWeather(Date date, int value){
        weather.put(hash(date), value);
    }

    public int getWeather(Date date){
        int key = hash(date);
        return weather.indexOfKey(key) >= 0 ? weather.get(key) : Integer.MIN_VALUE;
    }

    public static int hash(Date date){
        if(date == null) return 0;
        Calendar c = Calendar.getInstance();
                 c.setTime(date);
        return   c.get(Calendar.YEAR) * 365 +
                 c.get(Calendar.MONTH)*  31 +
                 c.get(Calendar.DAY_OF_MONTH);
    }

    // Design pattern implementation ------------
    @Override
    public View getDateHeaderView(int position, View convertView, ViewGroup parent, CalendarDateHeader calendarDate) {

        if(convertView == null)
            convertView = View.inflate(parent.getContext(), R.layout.listheader_calendar, null);

        TextView headerTextView = (TextView) convertView;
                 headerTextView.setText(calendarDate.getName()); // Set the day of week

        return convertView;

    }

    @Override
    public View getDateView(int position, View convertView, ViewGroup parent, CalendarDate calendarDate, int monthType) {

        // Just the usual...
        if(convertView == null){
            convertView = View.inflate(parent.getContext(), R.layout.listitem_calendar, null);
            holder = new ViewHolder();
            holder.dayTextView = (TextView) convertView.findViewById(R.id.day);
            holder.valueTextView = (TextView) convertView.findViewById(R.id.value);
            convertView.setTag(holder);
        }else {
            holder = (ViewHolder) convertView.getTag();
        }

        // How should be handling the day appearance
        Date currentDay = calendarDate.getDate();
        Calendar currentDayCalendar = Calendar.getInstance();
        currentDayCalendar.setTime(currentDay);

        int weatherValue = getWeather(currentDay);

        holder.dayTextView.setText(String.valueOf(currentDayCalendar.get(Calendar.DAY_OF_MONTH)));
        holder.valueTextView.setText(weatherValue == Integer.MIN_VALUE ? "-" : String.valueOf(weatherValue) + "°");

        // Coloring by month
        if(monthType == MONTH_TYPE_CURRENT) {

            // Coloring today using isToday() method
            if(isToday(currentDayCalendar)){
                convertView.setBackgroundColor(todayBackground);
            }else{
                convertView.setBackgroundColor(defaultBackground);
            }
            holder.dayTextView.setTextColor(activeText);

        }else if(monthType == MONTH_TYPE_PREVIOUSLY || monthType == MONTH_TYPE_NEXT) {
            convertView.setBackgroundColor(prevnextBackground);
            holder.dayTextView.setTextColor(inactiveText);
        }

        return convertView;
    }

    public class ViewHolder{
        TextView dayTextView, valueTextView;
    }

}