decompileAction(int n, SWF_ACTION *actions, int maxn)
{

#ifdef DEBUG
	fprintf(stderr,"%d:\tACTION[%3.3d]: %s\n",
	        actions[n].SWF_ACTIONRECORD.Offset, n,
	        actionName(actions[n].SWF_ACTIONRECORD.ActionCode));
#endif

	switch(OpCode(actions, n, maxn))
	{
	case SWFACTION_END:
		return 0;

	case SWFACTION_CONSTANTPOOL:
		decompileCONSTANTPOOL(&actions[n]);
		return 0;

	case SWFACTION_GOTOLABEL:
		return decompileGOTOFRAME(n, actions, maxn,1);

	case SWFACTION_GOTOFRAME:
		return decompileGOTOFRAME(n, actions, maxn,0);

	case SWFACTION_GOTOFRAME2:
		return decompileGOTOFRAME2(n, actions, maxn);

	case SWFACTION_WAITFORFRAME:
		decompileWAITFORFRAME(&actions[n]);
		return 0;

	case SWFACTION_GETURL2:
		decompileGETURL2(&actions[n]);
		return 0;

	case SWFACTION_GETURL:
		decompileGETURL(&actions[n]);
		return 0;

	case SWFACTION_PUSH:
		decompilePUSH(&actions[n]);
		return 0;

	case SWFACTION_PUSHDUP:
		decompilePUSHDUP(&actions[n]);
		return 0;

	case SWFACTION_STACKSWAP:
		decompileSTACKSWAP(&actions[n]);
		return 0;

	case SWFACTION_SETPROPERTY:
		decompileSETPROPERTY(n, actions, maxn);
		return 0;

	case SWFACTION_GETPROPERTY:
		decompileGETPROPERTY(n, actions, maxn);
		return 0;

	case SWFACTION_GETTIME:
		return decompileGETTIME(n, actions, maxn);

	case SWFACTION_TRACE:
		decompileTRACE(n, actions, maxn);
		return 0;

	case SWFACTION_CALLFRAME:
		decompileCALLFRAME(n, actions, maxn);
		return 0;

	case SWFACTION_EXTENDS:
		decompileEXTENDS(n, actions, maxn);
		return 0;

	case SWFACTION_INITOBJECT:
		decompileINITOBJECT(n, actions, maxn);
		return 0;

	case SWFACTION_NEWOBJECT:
		decompileNEWOBJECT(n, actions, maxn);
		return 0;

	case SWFACTION_NEWMETHOD:
		decompileNEWMETHOD(n, actions, maxn);
		return 0;

	case SWFACTION_GETMEMBER:
		decompileGETMEMBER(n, actions, maxn);
		return 0;

	case SWFACTION_SETMEMBER:
		decompileSETMEMBER(n, actions, maxn);
		return 0;

	case SWFACTION_GETVARIABLE:
		decompileGETVARIABLE(n, actions, maxn);
		return 0;

	case SWFACTION_SETVARIABLE:
		decompileSETVARIABLE(n, actions, maxn, 0);
		return 0;

	case SWFACTION_DEFINELOCAL:
		decompileSETVARIABLE(n, actions, maxn, 1);
		return 0;

	case SWFACTION_DEFINELOCAL2:
		decompileDEFINELOCAL2(n, actions, maxn);
		return 0;

	case SWFACTION_DECREMENT:
		return decompileINCR_DECR(n, actions, maxn, 0);

	case SWFACTION_INCREMENT:
		return decompileINCR_DECR(n, actions, maxn,1);

	case SWFACTION_STOREREGISTER:
		decompileSTOREREGISTER(n, actions, maxn);
		return 0;

	case SWFACTION_JUMP:
		return decompileJUMP(n, actions, maxn);

	case SWFACTION_RETURN:
		decompileRETURN(n, actions, maxn);
		return 0;

	case SWFACTION_LOGICALNOT:
		return decompileLogicalNot(n, actions, maxn);

	case SWFACTION_IF:
		return decompileIF(n, actions, maxn);

	case SWFACTION_WITH:
		decompileWITH(n, actions, maxn);
		return 0;

	case SWFACTION_ENUMERATE:
		return decompileENUMERATE(n, actions, maxn, 0);

	case SWFACTION_ENUMERATE2 :
		return decompileENUMERATE(n, actions, maxn,1);

	case SWFACTION_INITARRAY:
		return decompileINITARRAY(n, actions, maxn);

	case SWFACTION_DEFINEFUNCTION:
		return decompileDEFINEFUNCTION(n, actions, maxn,0);

	case SWFACTION_DEFINEFUNCTION2:
		return decompileDEFINEFUNCTION(n, actions, maxn,1);

	case SWFACTION_CALLFUNCTION:
		return decompileCALLFUNCTION(n, actions, maxn);

	case SWFACTION_CALLMETHOD:
		return decompileCALLMETHOD(n, actions, maxn);

	case SWFACTION_INSTANCEOF:
	case SWFACTION_SHIFTLEFT:
	case SWFACTION_SHIFTRIGHT:
	case SWFACTION_SHIFTRIGHT2:
	case SWFACTION_ADD:
	case SWFACTION_ADD2:
	case SWFACTION_SUBTRACT:
	case SWFACTION_MULTIPLY:
	case SWFACTION_DIVIDE:
	case SWFACTION_MODULO:
	case SWFACTION_BITWISEAND:
	case SWFACTION_BITWISEOR:
	case SWFACTION_BITWISEXOR:
	case SWFACTION_EQUAL:
	case SWFACTION_EQUALS2:
	case SWFACTION_LESS2:
	case SWFACTION_LOGICALAND:
	case SWFACTION_LOGICALOR:
	case SWFACTION_GREATER:
	case SWFACTION_LESSTHAN:
	case SWFACTION_STRINGEQ:
	case SWFACTION_STRINGCOMPARE:
	case SWFACTION_STRICTEQUALS:
		return decompileArithmeticOp(n, actions, maxn);

	case SWFACTION_POP:
		pop();
		return 0;

	case SWFACTION_STARTDRAG:
		return decompileSTARTDRAG(n, actions, maxn);

	case SWFACTION_DELETE:
		return decompileDELETE(n, actions, maxn,0);

	case SWFACTION_DELETE2:
		return decompileDELETE(n, actions, maxn,1);

	case SWFACTION_TARGETPATH:
		return decompileSingleArgBuiltInFunctionCall(n, actions, maxn,"targetPath");

	case SWFACTION_TYPEOF:
		return decompileSingleArgBuiltInFunctionCall(n, actions, maxn,"typeof");

	case SWFACTION_ORD:
		return decompileSingleArgBuiltInFunctionCall(n, actions, maxn,"ord");

	case SWFACTION_CHR:
		return decompileSingleArgBuiltInFunctionCall(n, actions, maxn,"chr");

	case SWFACTION_INT:
		return decompileSingleArgBuiltInFunctionCall(n, actions, maxn,"int");

	case SWFACTION_TOSTRING:
		return decompileSingleArgBuiltInFunctionCall(n, actions, maxn,"String");

	case SWFACTION_TONUMBER:
		return decompileSingleArgBuiltInFunctionCall(n, actions, maxn,"Number");

	case SWFACTION_RANDOMNUMBER:
		return decompileSingleArgBuiltInFunctionCall(n, actions, maxn,"random");

	case SWFACTION_STRINGLENGTH:
		return decompileSingleArgBuiltInFunctionCall(n, actions, maxn,"length");

	case SWFACTION_PLAY:
		return decompile_Null_ArgBuiltInFunctionCall(n, actions, maxn,"play");

	case SWFACTION_STOP:
		return decompile_Null_ArgBuiltInFunctionCall(n, actions, maxn,"stop");

	case SWFACTION_NEXTFRAME:
		return decompile_Null_ArgBuiltInFunctionCall(n, actions, maxn,"nextFrame");

	case SWFACTION_PREVFRAME:
		return decompile_Null_ArgBuiltInFunctionCall(n, actions, maxn,"prevFrame");

	case SWFACTION_ENDDRAG:
		return decompile_Null_ArgBuiltInFunctionCall(n, actions, maxn,"stopDrag");

	case SWFACTION_STOPSOUNDS:
		return decompile_Null_ArgBuiltInFunctionCall(n, actions, maxn,"stopAllSounds");

	case SWFACTION_TOGGLEQUALITY:
		return decompile_Null_ArgBuiltInFunctionCall(n, actions, maxn,"toggleHighQuality");

	case SWFACTION_MBSUBSTRING:
	case SWFACTION_SUBSTRING:
		return decompileSUBSTRING(n, actions, maxn);

	case SWFACTION_STRINGCONCAT:
		return decompileSTRINGCONCAT(n, actions, maxn);

	case SWFACTION_REMOVECLIP:
		return decompileREMOVECLIP(n, actions, maxn);

	case SWFACTION_DUPLICATECLIP:
		return decompileDUPLICATECLIP(n, actions, maxn);

	case SWFACTION_SETTARGET:
		return decompileSETTARGET(n, actions, maxn,0);

	case SWFACTION_SETTARGET2:
		return decompileSETTARGET(n, actions, maxn,1);

	case SWFACTION_IMPLEMENTSOP:
		return decompileIMPLEMENTS(n, actions, maxn);

	case SWFACTION_CASTOP:
		return decompileCAST(n, actions, maxn);

	case SWFACTION_THROW:
		return decompileTHROW(n, actions, maxn);

	case SWFACTION_TRY:
		return decompileTRY(n, actions, maxn);

	default:
		outputSWF_ACTION(n,&actions[n]);
		return 0;
	}
}


newVar2(char *var,char *var2)
{
	struct SWF_ACTIONPUSHPARAM *v;

	v=malloc(sizeof(struct SWF_ACTIONPUSHPARAM));
	v->Type = PUSH_VARIABLE;
	v->p.String = malloc(strlen(var)+strlen(var2)+1);
	strcpy(v->p.String,var);
	strcat(v->p.String,var2);
	return v;
}


decompileDEFINEFUNCTION(int n, SWF_ACTION *actions, int maxn, int is_type2)
{
	int i,j,k,m,r;
	struct SWF_ACTIONPUSHPARAM *myregs[ 256 ];
	struct _stack *StackSave;
	struct SWF_ACTIONDEFINEFUNCTION2 *sactv2;
	struct strbufinfo origbuf;
	OUT_BEGIN2(SWF_ACTIONDEFINEFUNCTION);
	sactv2 = (struct SWF_ACTIONDEFINEFUNCTION2*)sact;

#ifdef DEBUG
	if(n+1 < maxn)
	{
		println("/* function followed by OP %x */",
		        OpCode(actions, n+1, maxn));
	}
#endif
#if USE_LIB
	if (isStoreOp(n+1, actions,maxn)
	    || (  *sact->FunctionName==0 && !is_type2 )
	    || (*sactv2->FunctionName==0 && is_type2  ))
	{
		origbuf=setTempString();	/* switch to a temporary string buffer */
	}
#endif
	puts("function ");
	if (is_type2)
	{
		for(j=1;j<sactv2->RegisterCount;j++)
		{
			myregs[j]=regs[j];
			regs[j]=NULL;
		}
		r=1;
		if (sactv2->PreloadThisFlag)	regs[r++]=newVar("this");
		if (sactv2->PreloadArgumentsFlag)	regs[r++]=newVar("arguments");
		if (sactv2->PreloadSuperFlag)	regs[r++]=newVar("super");
		if (sactv2->PreloadRootFlag)	regs[r++]=newVar("root");
		if (sactv2->PreloadParentFlag)	regs[r++]=newVar("parent");
		if (sactv2->PreloadGlobalFlag)	regs[r++]=newVar("global");

		puts(sactv2->FunctionName);
		puts("(");

		for(i=0,m=0;i<sactv2->NumParams;i++)
		{
			puts(sactv2->Params[i].ParamName);
			if ( sactv2->Params[i].Register)
			{
				 printf(" /*=R%d*/ ",sactv2->Params[i].Register);
				 regs[sactv2->Params[i].Register] = newVar(sactv2->Params[i].ParamName);
				 m++;					// do not count 'void' etc
			}
			if( sactv2->NumParams > i+1 ) puts(",");
		}
		println(") {" );
		if (r+m < sactv2->RegisterCount)
		{
			INDENT
			puts("  var ");
		}
		for(k=r;r<sactv2->RegisterCount;r++)
		{
			if (!regs[r])
			{
				char *t=malloc(5); /* Rddd */
				sprintf(t,"R%d", r );
				puts (t);
				if (k++ < sactv2->RegisterCount- m -1)
					puts(", ");
				else
					println(";" );
				regs[r]=newVar(t);
			}
		}
		StackSave=Stack;
		decompileActions(sactv2->numActions, sactv2->Actions,gIndent+1);
#ifdef DEBUG
		if (Stack!=StackSave)
		{
			println("/* Stack problem in function code above */");
		}
#endif
		Stack=StackSave;
		for(j=1;j<sactv2->RegisterCount;j++)
			regs[j]=myregs[j];
	}
	else
	{
		puts(sact->FunctionName);
		puts("(");
		for(i=0;i<sact->NumParams;i++) {
			puts(sact->Params[i]);
			if( sact->NumParams > i+1 ) puts(",");
		}
		println(") {" );
		k=0;
		if (sact->Actions[0].SWF_ACTIONRECORD.ActionCode == SWFACTION_PUSH)
		{
			struct SWF_ACTIONPUSH *sactPush=(struct SWF_ACTIONPUSH *)sact->Actions;
			for(i=0;i<sactPush->NumParam;i++)
			{
				if ((&(sactPush->Params[i]))->Type == PUSH_REGISTER)
					k++;	/* REGISTER */
			}
			if (k)
			{
				INDENT
				puts("  var ");
				for(i=1;i<=k;i++)
				{
					char *t=malloc(5); /* Rddd */
					sprintf(t,"R%d", i );
					puts (t);
					if (i < k)
						puts(", ");
					else
						println(";" );
					regs[i]=newVar(t);
				}
			}
		}
		for(j=1;j<=k;j++)
			myregs[j]=regs[j];
		StackSave=Stack;
		decompileActions(sact->numActions, sact->Actions,gIndent+1);
#ifdef DEBUG
		if (Stack!=StackSave)
		{
			println("/* Stack problem in function code above */");
		}
#endif
		Stack=StackSave;
		for(j=1;j<=k;j++)
			regs[j]=myregs[j];
	}
	INDENT
	if (isStoreOp(n+1, actions,maxn)
	    || ( *sact->FunctionName==0 && !is_type2 )
	    || (*sactv2->FunctionName==0 && is_type2 ))
	{
		puts("}");
#if USE_LIB
		push (newVar(dcgetstr()));	/* push func body for later assignment */
		setOrigString(origbuf);		/* switch back to orig buffer */
#else
		push (newVar("/* see function code above */"));	/* workaround only if LIB is not in use */
#endif
	}
	else
		println("}" );
	return 0;
}


decompileLogicalNot(int n, SWF_ACTION *actions, int maxn)
{
#ifdef STATEMENT_CLASS
	if(OpCode(actions, n-1, maxn) == SWFACTION_GETVARIABLE &&
	   OpCode(actions, n+1, maxn) == SWFACTION_LOGICALNOT &&
	   OpCode(actions, n+2, maxn) == SWFACTION_IF )
	{
		/* It's a class statement  -- skip over both NOTs */
		return 1;
	}
#endif
	if(OpCode(actions, n+1, maxn) != SWFACTION_IF )
		push(newVar2("!",getString(pop())));
	return 0;
}


newVar_N2(char *var,char *var2, char *var3,char *var4,int pop_counter,char *final)
{
	struct SWF_ACTIONPUSHPARAM *v;
	int psize=PARAM_STRSIZE;
	int i;
	int slen=strlen(var)+strlen(var2)+strlen(var3)+strlen(var4)+strlen(final);

	v=malloc(sizeof(struct SWF_ACTIONPUSHPARAM));
	v->p.String = malloc(psize + slen);
	v->Type = PUSH_VARIABLE;
	strcpy(v->p.String,var);
	strcat(v->p.String,var2);
	strcat(v->p.String,var3);
	strcat(v->p.String,var4);
	for(i=0;i<pop_counter;i++)
	{
		char *pops1=getString(pop());
		char *pops2=getName  (pop());

		while ( strlen(v->p.String)+ 3 + strlen(pops1)+ strlen(pops2) +slen >= psize)
		{
			psize += PARAM_STRSIZE;
			v->p.String = realloc( v->p.String, psize);
		}
		strcat(v->p.String,pops2);
		strcat(v->p.String,":");
		strcat(v->p.String,pops1);
		if( i < pop_counter-1 )
			strcat(v->p.String,",");
	}
	strcat(v->p.String,final);
	return v;
}


decompileWAITFORFRAME (SWF_ACTION *act)
{
	OUT_BEGIN(SWF_ACTIONWAITFORFRAME);

	INDENT
	println("WaitForFrame(%d,%d);", sact->Frame,sact->SkipCount);
}


getAllSwitchActions(union SWF_ACTION *dest, union SWF_ACTION *actions, union SWF_ACTION *pre)
{
#ifdef DEBUGSWITCH
	println("SWCODE: %p %d %s   %s",
	        dest, actions->SWF_ACTIONRECORD.Offset,
	        actionName(actions->SWF_ACTIONRECORD.ActionCode),
	        actionName(pre->SWF_ACTIONRECORD.ActionCode));
#endif

	*dest++=*actions;
	if (actions->SWF_ACTIONRECORD.ActionCode==SWFACTION_IF
	    && pre->SWF_ACTIONRECORD.ActionCode==SWFACTION_STRICTEQUALS )
	{
		int i;
		struct SWF_ACTIONIF *sactv2 = (struct SWF_ACTIONIF*)actions;
		for(i=0; i< sactv2->numActions; i++)
		{
			dest=getAllSwitchActions(dest,&sactv2->Actions[i],pre);
			pre=&((struct SWF_ACTIONIF*)actions)->Actions[i];
		}
	}
	return dest;
}


decompileCAST(int n, SWF_ACTION *actions, int maxn)
{
	struct SWF_ACTIONPUSHPARAM *iparam=pop();
	struct SWF_ACTIONPUSHPARAM *tparam=pop();
	push(newVar_N( getName(tparam),"(",getName(iparam),"", 0,")"));
	return 0;
}


static int precedence(int op1,int op2)
{
	static unsigned char ops[]= { 		// array of opcodes w rising precedence
//	SWFACTION_SETVARIABLE,		// TAKE CARE: array is incomplete
//	SWFACTION_TRACE,
	// missing ops are considered with low precedence
		SWFACTION_LOGICALOR,
		SWFACTION_LOGICALAND,
		SWFACTION_BITWISEOR,
		SWFACTION_BITWISEXOR,
		SWFACTION_BITWISEAND,
		SWFACTION_STRICTEQUALS,
		SWFACTION_EQUALS2,
		SWFACTION_EQUAL,
		SWFACTION_GREATER,
		SWFACTION_LESSTHAN,
		SWFACTION_LESS2,
		SWFACTION_SHIFTRIGHT,
		SWFACTION_SHIFTRIGHT2,
		SWFACTION_SHIFTLEFT,
		SWFACTION_ADD,
		SWFACTION_ADD2,
		SWFACTION_SUBTRACT,
		SWFACTION_MODULO,
		SWFACTION_MULTIPLY,
		SWFACTION_DIVIDE,
		SWFACTION_LOGICALNOT,
		SWFACTION_PUSH			// FIXME: need more analysis on code after PUSH
	};
	unsigned char* f=memchr(ops,op1,sizeof(ops));
	unsigned char* s=memchr(ops,op2,sizeof(ops));
#ifdef DEBUG
	printf("1op=%d 2op=%d  result=%d\n",op1,op2,f>s);
	if (!f) printf("opcode=%d NOT in precedence list\n",op1);
	if (!s) printf("opcode=%d NOT in precedence list\n",op2);
#endif
	return f>s;
}


piv_get_data(sc_card_t * card, int enumtag, u8 **buf, size_t *buf_len)
{
	u8 *p;
	int r = 0;
	u8 tagbuf[8];
	size_t tag_len;

	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
	sc_log(card->ctx, "#%d", enumtag);

	r = sc_lock(card); /* do check len and get data in same transaction */
	if (r != SC_SUCCESS) {
		sc_log(card->ctx, "sc_lock failed");
		return r;
	}

	/* assert(enumtag >= 0 && enumtag < PIV_OBJ_LAST_ENUM); */

	tag_len = piv_objects[enumtag].tag_len;

	p = tagbuf;
	r = sc_asn1_put_tag(0x5c, piv_objects[enumtag].tag_value, tag_len, tagbuf, sizeof(tagbuf), &p);
	if (r != SC_SUCCESS) {
		sc_log(card->ctx, "Failed to encode ASN1 tag");
		goto err;
	}

	if (*buf_len == 1 && *buf == NULL) { /* we need to get the length */
		u8 rbufinitbuf[8]; /* tag of 53 with 82 xx xx  will fit in 4 */
		size_t bodylen;
		unsigned int cla_out, tag_out;
		const u8 *body;

		sc_log(card->ctx, "get len of #%d", enumtag);
		r = piv_general_io(card, 0xCB, 0x3F, 0xFF, tagbuf,  p - tagbuf, rbufinitbuf, sizeof rbufinitbuf);
		if (r > 0) {
			int r_tag;
			body = rbufinitbuf;
			r_tag = sc_asn1_read_tag(&body, r, &cla_out, &tag_out, &bodylen);
			if ((r_tag != SC_SUCCESS && r_tag != SC_ERROR_ASN1_END_OF_CONTENTS)
					|| body == NULL) {
				sc_log(card->ctx, "r_tag:%d body:%p", r_tag, body);
				r = SC_ERROR_FILE_NOT_FOUND;
				goto err;
			}
		    *buf_len = (body - rbufinitbuf) + bodylen;
		} else if ( r == 0 ) {
			r = SC_ERROR_FILE_NOT_FOUND;
			goto err;
		} else {
			goto err;
		}
	}

	sc_log(card->ctx,
	       "buffer for #%d *buf=0x%p len=%"SC_FORMAT_LEN_SIZE_T"u",
	       enumtag, *buf, *buf_len);
	if (*buf == NULL && *buf_len > 0) {
		if (*buf_len > MAX_FILE_SIZE) {
			goto err;
		}
		*buf = malloc(*buf_len);
		if (*buf == NULL ) {
			r = SC_ERROR_OUT_OF_MEMORY;
			goto err;
		}
	}

	r = piv_general_io(card, 0xCB, 0x3F, 0xFF, tagbuf,  p - tagbuf, *buf, *buf_len);

err:
	sc_unlock(card);
	LOG_FUNC_RETURN(card->ctx, r);
}


inline size_t WireFormatLite::Int64Size(int64_t value) {
  return io::CodedOutputStream::VarintSize64(static_cast<uint64_t>(value));
}


inline uint8_t* WireFormatLite::WriteSFixed32ToArray(
    int field_number, const RepeatedField<int32_t>& value, uint8_t* target) {
  return WritePrimitiveToArray(field_number, value, WriteSFixed32ToArray,
                               target);
}


inline bool WireFormatLite::ReadPrimitive<int32_t, WireFormatLite::TYPE_SINT32>(
    io::CodedInputStream* input, int32_t* value) {
  uint32_t temp;
  if (!input->ReadVarint32(&temp)) return false;
  *value = ZigZagDecode32(temp);
  return true;
}


inline int64_t WireFormatLite::ZigZagDecode64(uint64_t n) {
  // Note:  Using unsigned types prevent undefined behavior
  return static_cast<int64_t>((n >> 1) ^ (~(n & 1) + 1));
}


inline size_t WireFormatLite::SInt32Size(int32_t value) {
  return io::CodedOutputStream::VarintSize32(ZigZagEncode32(value));
}


bool WireFormat::ParseAndMergeMessageSetField(uint32_t field_number,
                                              const FieldDescriptor* field,
                                              Message* message,
                                              io::CodedInputStream* input) {
  const Reflection* message_reflection = message->GetReflection();
  if (field == NULL) {
    // We store unknown MessageSet extensions as groups.
    return SkipMessageSetField(
        input, field_number, message_reflection->MutableUnknownFields(message));
  } else if (field->is_repeated() ||
             field->type() != FieldDescriptor::TYPE_MESSAGE) {
    // This shouldn't happen as we only allow optional message extensions to
    // MessageSet.
    GOOGLE_LOG(ERROR) << "Extensions of MessageSets must be optional messages.";
    return false;
  } else {
    Message* sub_message = message_reflection->MutableMessage(
        message, field, input->GetExtensionFactory());
    return WireFormatLite::ReadMessage(input, sub_message);
  }
}


inline int WireFormatLite::GetTagFieldNumber(uint32_t tag) {
  return static_cast<int>(tag >> kTagTypeBits);
}


inline uint8_t* WireFormatLite::WriteInt64NoTagToArray(int64_t value,
                                                       uint8_t* target) {
  return io::CodedOutputStream::WriteVarint64ToArray(
      static_cast<uint64_t>(value), target);
}


uint8_t* WireFormat::InternalSerializeField(const FieldDescriptor* field,
                                            const Message& message,
                                            uint8_t* target,
                                            io::EpsCopyOutputStream* stream) {
  const Reflection* message_reflection = message.GetReflection();

  if (field->is_extension() &&
      field->containing_type()->options().message_set_wire_format() &&
      field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
      !field->is_repeated()) {
    return InternalSerializeMessageSetItem(field, message, target, stream);
  }

  // For map fields, we can use either repeated field reflection or map
  // reflection.  Our choice has some subtle effects.  If we use repeated field
  // reflection here, then the repeated field representation becomes
  // authoritative for this field: any existing references that came from map
  // reflection remain valid for reading, but mutations to them are lost and
  // will be overwritten next time we call map reflection!
  //
  // So far this mainly affects Python, which keeps long-term references to map
  // values around, and always uses map reflection.  See: b/35918691
  //
  // Here we choose to use map reflection API as long as the internal
  // map is valid. In this way, the serialization doesn't change map field's
  // internal state and existing references that came from map reflection remain
  // valid for both reading and writing.
  if (field->is_map()) {
    const MapFieldBase* map_field =
        message_reflection->GetMapData(message, field);
    if (map_field->IsMapValid()) {
      if (stream->IsSerializationDeterministic()) {
        std::vector<MapKey> sorted_key_list =
            MapKeySorter::SortKey(message, message_reflection, field);
        for (std::vector<MapKey>::iterator it = sorted_key_list.begin();
             it != sorted_key_list.end(); ++it) {
          MapValueConstRef map_value;
          message_reflection->LookupMapValue(message, field, *it, &map_value);
          target =
              InternalSerializeMapEntry(field, *it, map_value, target, stream);
        }
      } else {
        for (MapIterator it = message_reflection->MapBegin(
                 const_cast<Message*>(&message), field);
             it !=
             message_reflection->MapEnd(const_cast<Message*>(&message), field);
             ++it) {
          target = InternalSerializeMapEntry(field, it.GetKey(),
                                             it.GetValueRef(), target, stream);
        }
      }

      return target;
    }
  }
  int count = 0;

  if (field->is_repeated()) {
    count = message_reflection->FieldSize(message, field);
  } else if (field->containing_type()->options().map_entry()) {
    // Map entry fields always need to be serialized.
    count = 1;
  } else if (message_reflection->HasField(message, field)) {
    count = 1;
  }

  // map_entries is for maps that'll be deterministically serialized.
  std::vector<const Message*> map_entries;
  if (count > 1 && field->is_map() && stream->IsSerializationDeterministic()) {
    map_entries =
        DynamicMapSorter::Sort(message, count, message_reflection, field);
  }

  if (field->is_packed()) {
    if (count == 0) return target;
    target = stream->EnsureSpace(target);
    switch (field->type()) {
#define HANDLE_PRIMITIVE_TYPE(TYPE, CPPTYPE, TYPE_METHOD, CPPTYPE_METHOD)      \
  case FieldDescriptor::TYPE_##TYPE: {                                         \
    auto r =                                                                   \
        message_reflection->GetRepeatedFieldInternal<CPPTYPE>(message, field); \
    target = stream->Write##TYPE_METHOD##Packed(                               \
        field->number(), r, FieldDataOnlyByteSize(field, message), target);    \
    break;                                                                     \
  }

      HANDLE_PRIMITIVE_TYPE(INT32, int32_t, Int32, Int32)
      HANDLE_PRIMITIVE_TYPE(INT64, int64_t, Int64, Int64)
      HANDLE_PRIMITIVE_TYPE(SINT32, int32_t, SInt32, Int32)
      HANDLE_PRIMITIVE_TYPE(SINT64, int64_t, SInt64, Int64)
      HANDLE_PRIMITIVE_TYPE(UINT32, uint32_t, UInt32, UInt32)
      HANDLE_PRIMITIVE_TYPE(UINT64, uint64_t, UInt64, UInt64)
      HANDLE_PRIMITIVE_TYPE(ENUM, int, Enum, Enum)

#undef HANDLE_PRIMITIVE_TYPE
#define HANDLE_PRIMITIVE_TYPE(TYPE, CPPTYPE, TYPE_METHOD, CPPTYPE_METHOD)      \
  case FieldDescriptor::TYPE_##TYPE: {                                         \
    auto r =                                                                   \
        message_reflection->GetRepeatedFieldInternal<CPPTYPE>(message, field); \
    target = stream->WriteFixedPacked(field->number(), r, target);             \
    break;                                                                     \
  }

      HANDLE_PRIMITIVE_TYPE(FIXED32, uint32_t, Fixed32, UInt32)
      HANDLE_PRIMITIVE_TYPE(FIXED64, uint64_t, Fixed64, UInt64)
      HANDLE_PRIMITIVE_TYPE(SFIXED32, int32_t, SFixed32, Int32)
      HANDLE_PRIMITIVE_TYPE(SFIXED64, int64_t, SFixed64, Int64)

      HANDLE_PRIMITIVE_TYPE(FLOAT, float, Float, Float)
      HANDLE_PRIMITIVE_TYPE(DOUBLE, double, Double, Double)

      HANDLE_PRIMITIVE_TYPE(BOOL, bool, Bool, Bool)
#undef HANDLE_PRIMITIVE_TYPE
      default:
        GOOGLE_LOG(FATAL) << "Invalid descriptor";
    }
    return target;
  }

  for (int j = 0; j < count; j++) {
    target = stream->EnsureSpace(target);
    switch (field->type()) {
#define HANDLE_PRIMITIVE_TYPE(TYPE, CPPTYPE, TYPE_METHOD, CPPTYPE_METHOD)     \
  case FieldDescriptor::TYPE_##TYPE: {                                        \
    const CPPTYPE value =                                                     \
        field->is_repeated()                                                  \
            ? message_reflection->GetRepeated##CPPTYPE_METHOD(message, field, \
                                                              j)              \
            : message_reflection->Get##CPPTYPE_METHOD(message, field);        \
    target = WireFormatLite::Write##TYPE_METHOD##ToArray(field->number(),     \
                                                         value, target);      \
    break;                                                                    \
  }

      HANDLE_PRIMITIVE_TYPE(INT32, int32_t, Int32, Int32)
      HANDLE_PRIMITIVE_TYPE(INT64, int64_t, Int64, Int64)
      HANDLE_PRIMITIVE_TYPE(SINT32, int32_t, SInt32, Int32)
      HANDLE_PRIMITIVE_TYPE(SINT64, int64_t, SInt64, Int64)
      HANDLE_PRIMITIVE_TYPE(UINT32, uint32_t, UInt32, UInt32)
      HANDLE_PRIMITIVE_TYPE(UINT64, uint64_t, UInt64, UInt64)

      HANDLE_PRIMITIVE_TYPE(FIXED32, uint32_t, Fixed32, UInt32)
      HANDLE_PRIMITIVE_TYPE(FIXED64, uint64_t, Fixed64, UInt64)
      HANDLE_PRIMITIVE_TYPE(SFIXED32, int32_t, SFixed32, Int32)
      HANDLE_PRIMITIVE_TYPE(SFIXED64, int64_t, SFixed64, Int64)

      HANDLE_PRIMITIVE_TYPE(FLOAT, float, Float, Float)
      HANDLE_PRIMITIVE_TYPE(DOUBLE, double, Double, Double)

      HANDLE_PRIMITIVE_TYPE(BOOL, bool, Bool, Bool)
#undef HANDLE_PRIMITIVE_TYPE

#define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE_METHOD)                         \
  case FieldDescriptor::TYPE_##TYPE:                                           \
    target = WireFormatLite::InternalWrite##TYPE_METHOD(                       \
        field->number(),                                                       \
        field->is_repeated()                                                   \
            ? (map_entries.empty()                                             \
                   ? message_reflection->GetRepeated##CPPTYPE_METHOD(message,  \
                                                                     field, j) \
                   : *map_entries[j])                                          \
            : message_reflection->Get##CPPTYPE_METHOD(message, field),         \
        target, stream);                                                       \
    break;

      HANDLE_TYPE(GROUP, Group, Message)
      HANDLE_TYPE(MESSAGE, Message, Message)
#undef HANDLE_TYPE

      case FieldDescriptor::TYPE_ENUM: {
        const EnumValueDescriptor* value =
            field->is_repeated()
                ? message_reflection->GetRepeatedEnum(message, field, j)
                : message_reflection->GetEnum(message, field);
        target = WireFormatLite::WriteEnumToArray(field->number(),
                                                  value->number(), target);
        break;
      }

      // Handle strings separately so that we can get string references
      // instead of copying.
      case FieldDescriptor::TYPE_STRING: {
        bool strict_utf8_check = StrictUtf8Check(field);
        std::string scratch;
        const std::string& value =
            field->is_repeated()
                ? message_reflection->GetRepeatedStringReference(message, field,
                                                                 j, &scratch)
                : message_reflection->GetStringReference(message, field,
                                                         &scratch);
        if (strict_utf8_check) {
          WireFormatLite::VerifyUtf8String(value.data(), value.length(),
                                           WireFormatLite::SERIALIZE,
                                           field->full_name().c_str());
        } else {
          VerifyUTF8StringNamedField(value.data(), value.length(), SERIALIZE,
                                     field->full_name().c_str());
        }
        target = stream->WriteString(field->number(), value, target);
        break;
      }

      case FieldDescriptor::TYPE_BYTES: {
        std::string scratch;
        const std::string& value =
            field->is_repeated()
                ? message_reflection->GetRepeatedStringReference(message, field,
                                                                 j, &scratch)
                : message_reflection->GetStringReference(message, field,
                                                         &scratch);
        target = stream->WriteString(field->number(), value, target);
        break;
      }
    }
  }
  return target;
}


inline uint8_t* WireFormatLite::WriteSFixed32NoTagToArray(
    const RepeatedField<int32_t>& value, uint8_t* target) {
  return WriteFixedNoTagToArray(value, WriteSFixed32NoTagToArray, target);
}


inline uint8_t* WireFormatLite::WriteFixed32NoTagToArray(uint32_t value,
                                                         uint8_t* target) {
  return io::CodedOutputStream::WriteLittleEndian32ToArray(value, target);
}


inline size_t WireFormatLite::MessageSizeNoVirtual(
    const MessageType_WorkAroundCppLookupDefect& value) {
  return LengthDelimitedSize(
      value.MessageType_WorkAroundCppLookupDefect::ByteSizeLong());
}


uint8_t* WireFormat::InternalSerializeUnknownMessageSetItemsToArray(
    const UnknownFieldSet& unknown_fields, uint8_t* target,
    io::EpsCopyOutputStream* stream) {
  for (int i = 0; i < unknown_fields.field_count(); i++) {
    const UnknownField& field = unknown_fields.field(i);

    // The only unknown fields that are allowed to exist in a MessageSet are
    // messages, which are length-delimited.
    if (field.type() == UnknownField::TYPE_LENGTH_DELIMITED) {
      target = stream->EnsureSpace(target);
      // Start group.
      target = io::CodedOutputStream::WriteTagToArray(
          WireFormatLite::kMessageSetItemStartTag, target);

      // Write type ID.
      target = io::CodedOutputStream::WriteTagToArray(
          WireFormatLite::kMessageSetTypeIdTag, target);
      target =
          io::CodedOutputStream::WriteVarint32ToArray(field.number(), target);

      // Write message.
      target = io::CodedOutputStream::WriteTagToArray(
          WireFormatLite::kMessageSetMessageTag, target);

      target = field.InternalSerializeLengthDelimitedNoTag(target, stream);

      target = stream->EnsureSpace(target);
      // End group.
      target = io::CodedOutputStream::WriteTagToArray(
          WireFormatLite::kMessageSetItemEndTag, target);
    }
  }

  return target;
}


  void readField(folly::Optional<T>& data, FieldType /* fieldType */) {
    data = folly::Optional<T>(readRaw<T>());
  }


  void readField(
      apache::thrift::optional_field_ref<T&> data,
      FieldType /* fieldType */) {
    data = readRaw<T>();
  }


lexer_skip_empty_statements (parser_context_t *context_p) /**< context */
{
  lexer_skip_spaces (context_p);

  while (context_p->source_p < context_p->source_end_p && *context_p->source_p == LIT_CHAR_SEMICOLON)
  {
    lexer_consume_next_character (context_p);
    lexer_skip_spaces (context_p);
  }

  context_p->token.flags = (uint8_t) (context_p->token.flags | LEXER_NO_SKIP_SPACES);
} /* lexer_skip_empty_statements */


lexer_convert_push_number_to_push_literal (parser_context_t *context_p) /**< context */
{
  ecma_integer_value_t value;
  bool two_literals = context_p->last_cbc_opcode >= CBC_PUSH_LITERAL_PUSH_NUMBER_0;

  if (context_p->last_cbc_opcode == CBC_PUSH_NUMBER_0 || context_p->last_cbc_opcode == CBC_PUSH_LITERAL_PUSH_NUMBER_0)
  {
    value = 0;
  }
  else if (context_p->last_cbc_opcode == CBC_PUSH_NUMBER_POS_BYTE
           || context_p->last_cbc_opcode == CBC_PUSH_LITERAL_PUSH_NUMBER_POS_BYTE)
  {
    value = ((ecma_integer_value_t) context_p->last_cbc.value) + 1;
  }
  else
  {
    JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_NUMBER_NEG_BYTE
                  || context_p->last_cbc_opcode == CBC_PUSH_LITERAL_PUSH_NUMBER_NEG_BYTE);
    value = -((ecma_integer_value_t) context_p->last_cbc.value) - 1;
  }

  ecma_value_t lit_value = ecma_make_integer_value (value);

  parser_list_iterator_t literal_iterator;
  parser_list_iterator_init (&context_p->literal_pool, &literal_iterator);

  context_p->last_cbc_opcode = two_literals ? CBC_PUSH_TWO_LITERALS : CBC_PUSH_LITERAL;

  uint32_t literal_index = 0;
  lexer_literal_t *literal_p;

  while ((literal_p = (lexer_literal_t *) parser_list_iterator_next (&literal_iterator)) != NULL)
  {
    if (literal_p->type == LEXER_NUMBER_LITERAL && literal_p->u.value == lit_value)
    {
      if (two_literals)
      {
        context_p->last_cbc.value = (uint16_t) literal_index;
      }
      else
      {
        context_p->last_cbc.literal_index = (uint16_t) literal_index;
      }
      return;
    }

    literal_index++;
  }

  JERRY_ASSERT (literal_index == context_p->literal_count);

  if (literal_index >= PARSER_MAXIMUM_NUMBER_OF_LITERALS)
  {
    parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED);
  }

  literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool);
  literal_p->u.value = lit_value;
  literal_p->prop.length = 0; /* Unused. */
  literal_p->type = LEXER_NUMBER_LITERAL;
  literal_p->status_flags = 0;

  context_p->literal_count++;

  if (two_literals)
  {
    context_p->last_cbc.value = (uint16_t) literal_index;
  }
  else
  {
    context_p->last_cbc.literal_index = (uint16_t) literal_index;
  }
} /* lexer_convert_push_number_to_push_literal */


lexer_next_token (parser_context_t *context_p) /**< context */
{
  size_t length;

#if JERRY_ESNEXT && JERRY_FUNCTION_TO_STRING
  /* Needed by arrow functions with expression body */
  context_p->function_end_p = context_p->source_p;
#endif /* JERRY_ESNEXT && JERRY_FUNCTION_TO_STRING */

  lexer_skip_spaces (context_p);

  context_p->token.keyword_type = LEXER_EOS;
  context_p->token.line = context_p->line;
  context_p->token.column = context_p->column;

  length = (size_t) (context_p->source_end_p - context_p->source_p);
  if (length == 0)
  {
    context_p->token.type = LEXER_EOS;
    return;
  }

  if (lexer_parse_identifier (context_p, LEXER_PARSE_CHECK_KEYWORDS))
  {
    return;
  }

  if (context_p->source_p[0] >= LIT_CHAR_0 && context_p->source_p[0] <= LIT_CHAR_9)
  {
    lexer_parse_number (context_p);
    return;
  }

  switch (context_p->source_p[0])
  {
    LEXER_TYPE_A_TOKEN (LIT_CHAR_LEFT_BRACE, LEXER_LEFT_BRACE);
    LEXER_TYPE_A_TOKEN (LIT_CHAR_LEFT_PAREN, LEXER_LEFT_PAREN);
    LEXER_TYPE_A_TOKEN (LIT_CHAR_LEFT_SQUARE, LEXER_LEFT_SQUARE);
    LEXER_TYPE_A_TOKEN (LIT_CHAR_RIGHT_BRACE, LEXER_RIGHT_BRACE);
    LEXER_TYPE_A_TOKEN (LIT_CHAR_RIGHT_PAREN, LEXER_RIGHT_PAREN);
    LEXER_TYPE_A_TOKEN (LIT_CHAR_RIGHT_SQUARE, LEXER_RIGHT_SQUARE);
    LEXER_TYPE_A_TOKEN (LIT_CHAR_SEMICOLON, LEXER_SEMICOLON);
    LEXER_TYPE_A_TOKEN (LIT_CHAR_COMMA, LEXER_COMMA);
#if JERRY_ESNEXT
    LEXER_TYPE_A_TOKEN (LIT_CHAR_HASHMARK, LEXER_HASHMARK);
#endif /* JERRY_ESNEXT */

    case (uint8_t) LIT_CHAR_DOT:
    {
      if (length >= 2 && (context_p->source_p[1] >= LIT_CHAR_0 && context_p->source_p[1] <= LIT_CHAR_9))
      {
        lexer_parse_number (context_p);
        return;
      }

#if JERRY_ESNEXT
      if (length >= 3 && context_p->source_p[1] == LIT_CHAR_DOT && context_p->source_p[2] == LIT_CHAR_DOT)
      {
        context_p->token.type = LEXER_THREE_DOTS;
        length = 3;
        break;
      }
#endif /* JERRY_ESNEXT */

      context_p->token.type = LEXER_DOT;
      length = 1;
      break;
    }

    case (uint8_t) LIT_CHAR_LESS_THAN:
    {
      if (length >= 2)
      {
        if (context_p->source_p[1] == (uint8_t) LIT_CHAR_EQUALS)
        {
          context_p->token.type = LEXER_LESS_EQUAL;
          length = 2;
          break;
        }

        if (context_p->source_p[1] == (uint8_t) LIT_CHAR_LESS_THAN)
        {
          if (length >= 3 && context_p->source_p[2] == (uint8_t) LIT_CHAR_EQUALS)
          {
            context_p->token.type = LEXER_ASSIGN_LEFT_SHIFT;
            length = 3;
            break;
          }

          context_p->token.type = LEXER_LEFT_SHIFT;
          length = 2;
          break;
        }
      }

      context_p->token.type = LEXER_LESS;
      length = 1;
      break;
    }

    case (uint8_t) LIT_CHAR_GREATER_THAN:
    {
      if (length >= 2)
      {
        if (context_p->source_p[1] == (uint8_t) LIT_CHAR_EQUALS)
        {
          context_p->token.type = LEXER_GREATER_EQUAL;
          length = 2;
          break;
        }

        if (context_p->source_p[1] == (uint8_t) LIT_CHAR_GREATER_THAN)
        {
          if (length >= 3)
          {
            if (context_p->source_p[2] == (uint8_t) LIT_CHAR_EQUALS)
            {
              context_p->token.type = LEXER_ASSIGN_RIGHT_SHIFT;
              length = 3;
              break;
            }

            if (context_p->source_p[2] == (uint8_t) LIT_CHAR_GREATER_THAN)
            {
              if (length >= 4 && context_p->source_p[3] == (uint8_t) LIT_CHAR_EQUALS)
              {
                context_p->token.type = LEXER_ASSIGN_UNS_RIGHT_SHIFT;
                length = 4;
                break;
              }

              context_p->token.type = LEXER_UNS_RIGHT_SHIFT;
              length = 3;
              break;
            }
          }

          context_p->token.type = LEXER_RIGHT_SHIFT;
          length = 2;
          break;
        }
      }

      context_p->token.type = LEXER_GREATER;
      length = 1;
      break;
    }

    case (uint8_t) LIT_CHAR_EQUALS:
    {
      if (length >= 2)
      {
        if (context_p->source_p[1] == (uint8_t) LIT_CHAR_EQUALS)
        {
          if (length >= 3 && context_p->source_p[2] == (uint8_t) LIT_CHAR_EQUALS)
          {
            context_p->token.type = LEXER_STRICT_EQUAL;
            length = 3;
            break;
          }

          context_p->token.type = LEXER_EQUAL;
          length = 2;
          break;
        }

#if JERRY_ESNEXT
        if (context_p->source_p[1] == (uint8_t) LIT_CHAR_GREATER_THAN)
        {
          context_p->token.type = LEXER_ARROW;
          length = 2;
          break;
        }
#endif /* JERRY_ESNEXT */
      }

      context_p->token.type = LEXER_ASSIGN;
      length = 1;
      break;
    }

    case (uint8_t) LIT_CHAR_EXCLAMATION:
    {
      if (length >= 2 && context_p->source_p[1] == (uint8_t) LIT_CHAR_EQUALS)
      {
        if (length >= 3 && context_p->source_p[2] == (uint8_t) LIT_CHAR_EQUALS)
        {
          context_p->token.type = LEXER_STRICT_NOT_EQUAL;
          length = 3;
          break;
        }

        context_p->token.type = LEXER_NOT_EQUAL;
        length = 2;
        break;
      }

      context_p->token.type = LEXER_LOGICAL_NOT;
      length = 1;
      break;
    }

      LEXER_TYPE_C_TOKEN (LIT_CHAR_PLUS, LEXER_ADD, LIT_CHAR_EQUALS, LEXER_ASSIGN_ADD, LIT_CHAR_PLUS, LEXER_INCREASE)
      LEXER_TYPE_C_TOKEN (LIT_CHAR_MINUS,
                          LEXER_SUBTRACT,
                          LIT_CHAR_EQUALS,
                          LEXER_ASSIGN_SUBTRACT,
                          LIT_CHAR_MINUS,
                          LEXER_DECREASE)

    case (uint8_t) LIT_CHAR_ASTERISK:
    {
      if (length >= 2)
      {
        if (context_p->source_p[1] == (uint8_t) LIT_CHAR_EQUALS)
        {
          context_p->token.type = LEXER_ASSIGN_MULTIPLY;
          length = 2;
          break;
        }

#if JERRY_ESNEXT
        if (context_p->source_p[1] == (uint8_t) LIT_CHAR_ASTERISK)
        {
          if (length >= 3 && context_p->source_p[2] == (uint8_t) LIT_CHAR_EQUALS)
          {
            context_p->token.type = LEXER_ASSIGN_EXPONENTIATION;
            length = 3;
            break;
          }

          context_p->token.type = LEXER_EXPONENTIATION;
          length = 2;
          break;
        }
#endif /* JERRY_ESNEXT */
      }

      context_p->token.type = LEXER_MULTIPLY;
      length = 1;
      break;
    }

      LEXER_TYPE_B_TOKEN (LIT_CHAR_SLASH, LEXER_DIVIDE, LIT_CHAR_EQUALS, LEXER_ASSIGN_DIVIDE)
      LEXER_TYPE_B_TOKEN (LIT_CHAR_PERCENT, LEXER_MODULO, LIT_CHAR_EQUALS, LEXER_ASSIGN_MODULO)

      LEXER_TYPE_D_TOKEN (LIT_CHAR_AMPERSAND,
                          LEXER_BIT_AND,
                          LIT_CHAR_EQUALS,
                          LEXER_ASSIGN_BIT_AND,
                          LIT_CHAR_AMPERSAND,
                          LEXER_LOGICAL_AND,
                          LIT_CHAR_EQUALS,
                          LEXER_ASSIGN_LOGICAL_AND)
      LEXER_TYPE_D_TOKEN (LIT_CHAR_VLINE,
                          LEXER_BIT_OR,
                          LIT_CHAR_EQUALS,
                          LEXER_ASSIGN_BIT_OR,
                          LIT_CHAR_VLINE,
                          LEXER_LOGICAL_OR,
                          LIT_CHAR_EQUALS,
                          LEXER_ASSIGN_LOGICAL_OR)

      LEXER_TYPE_B_TOKEN (LIT_CHAR_CIRCUMFLEX, LEXER_BIT_XOR, LIT_CHAR_EQUALS, LEXER_ASSIGN_BIT_XOR)

      LEXER_TYPE_A_TOKEN (LIT_CHAR_TILDE, LEXER_BIT_NOT);
    case (uint8_t) (LIT_CHAR_QUESTION):
    {
#if JERRY_ESNEXT
      if (length >= 2)
      {
        if (context_p->source_p[1] == (uint8_t) LIT_CHAR_QUESTION)
        {
          if (length >= 3 && context_p->source_p[2] == (uint8_t) LIT_CHAR_EQUALS)
          {
            context_p->token.type = LEXER_ASSIGN_NULLISH_COALESCING;
            length = 3;
            break;
          }
          context_p->token.type = LEXER_NULLISH_COALESCING;
          length = 2;
          break;
        }
      }
#endif /* JERRY_ESNEXT */
      context_p->token.type = LEXER_QUESTION_MARK;
      length = 1;
      break;
    }

      LEXER_TYPE_A_TOKEN (LIT_CHAR_COLON, LEXER_COLON);

    case LIT_CHAR_SINGLE_QUOTE:
    case LIT_CHAR_DOUBLE_QUOTE:
#if JERRY_ESNEXT
    case LIT_CHAR_GRAVE_ACCENT:
#endif /* JERRY_ESNEXT */
    {
      lexer_parse_string (context_p, LEXER_STRING_NO_OPTS);
      return;
    }

    default:
    {
      parser_raise_error (context_p, PARSER_ERR_INVALID_CHARACTER);
    }
  }

  context_p->source_p += length;
  PARSER_PLUS_EQUAL_LC (context_p->column, length);
} /* lexer_next_token */


lexer_skip_spaces (parser_context_t *context_p) /**< context */
{
  skip_mode_t mode = LEXER_SKIP_SPACES;
  const uint8_t *source_end_p = context_p->source_end_p;

  if (context_p->token.flags & LEXER_NO_SKIP_SPACES)
  {
    context_p->token.flags &= (uint8_t) ~LEXER_NO_SKIP_SPACES;
    return;
  }

  context_p->token.flags = 0;

  while (true)
  {
    if (context_p->source_p >= source_end_p)
    {
      if (mode == LEXER_SKIP_MULTI_LINE_COMMENT)
      {
        parser_raise_error (context_p, PARSER_ERR_UNTERMINATED_MULTILINE_COMMENT);
      }
      return;
    }

    switch (context_p->source_p[0])
    {
      case LIT_CHAR_CR:
      {
        if (context_p->source_p + 1 < source_end_p && context_p->source_p[1] == LIT_CHAR_LF)
        {
          context_p->source_p++;
        }
        /* FALLTHRU */
      }

      case LIT_CHAR_LF:
      {
        context_p->line++;
        context_p->column = 0;
        context_p->token.flags = LEXER_WAS_NEWLINE;

        if (mode == LEXER_SKIP_SINGLE_LINE_COMMENT)
        {
          mode = LEXER_SKIP_SPACES;
        }
        /* FALLTHRU */
      }

      case LIT_CHAR_VTAB:
      case LIT_CHAR_FF:
      case LIT_CHAR_SP:
      {
        context_p->source_p++;
        context_p->column++;
        continue;
      }

      case LIT_CHAR_TAB:
      {
        context_p->column = align_column_to_tab (context_p->column);
        context_p->source_p++;
        continue;
      }

      case LIT_CHAR_SLASH:
      {
        if (mode == LEXER_SKIP_SPACES && context_p->source_p + 1 < source_end_p)
        {
          if (context_p->source_p[1] == LIT_CHAR_SLASH)
          {
            mode = LEXER_SKIP_SINGLE_LINE_COMMENT;
          }
          else if (context_p->source_p[1] == LIT_CHAR_ASTERISK)
          {
            mode = LEXER_SKIP_MULTI_LINE_COMMENT;
            context_p->token.line = context_p->line;
            context_p->token.column = context_p->column;
          }

          if (mode != LEXER_SKIP_SPACES)
          {
            context_p->source_p += 2;
            PARSER_PLUS_EQUAL_LC (context_p->column, 2);
            continue;
          }
        }
        break;
      }

      case LIT_CHAR_ASTERISK:
      {
        if (mode == LEXER_SKIP_MULTI_LINE_COMMENT && context_p->source_p + 1 < source_end_p
            && context_p->source_p[1] == LIT_CHAR_SLASH)
        {
          mode = LEXER_SKIP_SPACES;
          context_p->source_p += 2;
          PARSER_PLUS_EQUAL_LC (context_p->column, 2);
          continue;
        }
        break;
      }

      case 0xc2:
      {
        if (context_p->source_p + 1 < source_end_p && context_p->source_p[1] == 0xa0)
        {
          /* Codepoint \u00A0 */
          context_p->source_p += 2;
          context_p->column++;
          continue;
        }
        break;
      }

      case LEXER_NEWLINE_LS_PS_BYTE_1:
      {
        JERRY_ASSERT (context_p->source_p + 2 < source_end_p);
        if (LEXER_NEWLINE_LS_PS_BYTE_23 (context_p->source_p))
        {
          /* Codepoint \u2028 and \u2029 */
          context_p->source_p += 3;
          context_p->line++;
          context_p->column = 1;
          context_p->token.flags = LEXER_WAS_NEWLINE;

          if (mode == LEXER_SKIP_SINGLE_LINE_COMMENT)
          {
            mode = LEXER_SKIP_SPACES;
          }
          continue;
        }
        break;
      }

      case 0xef:
      {
        if (context_p->source_p + 2 < source_end_p && context_p->source_p[1] == 0xbb && context_p->source_p[2] == 0xbf)
        {
          /* Codepoint \uFEFF */
          context_p->source_p += 3;
          context_p->column++;
          continue;
        }
        break;
      }

      default:
      {
        break;
      }
    }

    if (mode == LEXER_SKIP_SPACES)
    {
      return;
    }

    context_p->source_p++;

    if (context_p->source_p < source_end_p && !IS_UTF8_INTERMEDIATE_OCTET (context_p->source_p[0]))
    {
      context_p->column++;
    }
  }
} /* lexer_skip_spaces */


lexer_construct_literal_object (parser_context_t *context_p, /**< context */
                                const lexer_lit_location_t *lit_location_p, /**< literal location */
                                uint8_t literal_type) /**< final literal type */
{
  uint8_t local_byte_array[LEXER_MAX_LITERAL_LOCAL_BUFFER_SIZE];

  const uint8_t *char_p =
    lexer_convert_literal_to_chars (context_p, lit_location_p, local_byte_array, LEXER_STRING_NO_OPTS);

  size_t length = lit_location_p->length;
  parser_list_iterator_t literal_iterator;
  lexer_literal_t *literal_p;
  uint32_t literal_index = 0;
  bool search_scope_stack = (literal_type == LEXER_IDENT_LITERAL);

  if (JERRY_UNLIKELY (literal_type == LEXER_NEW_IDENT_LITERAL))
  {
    literal_type = LEXER_IDENT_LITERAL;
  }

  JERRY_ASSERT (literal_type == LEXER_IDENT_LITERAL || literal_type == LEXER_STRING_LITERAL);

  JERRY_ASSERT (literal_type != LEXER_IDENT_LITERAL || length <= PARSER_MAXIMUM_IDENT_LENGTH);
  JERRY_ASSERT (literal_type != LEXER_STRING_LITERAL || length <= PARSER_MAXIMUM_STRING_LENGTH);

  parser_list_iterator_init (&context_p->literal_pool, &literal_iterator);

  while ((literal_p = (lexer_literal_t *) parser_list_iterator_next (&literal_iterator)) != NULL)
  {
    if (literal_p->type == literal_type && literal_p->prop.length == length
        && memcmp (literal_p->u.char_p, char_p, length) == 0)
    {
      context_p->lit_object.literal_p = literal_p;
      context_p->lit_object.index = (uint16_t) literal_index;

      parser_free_allocated_buffer (context_p);

      if (search_scope_stack)
      {
        parser_scope_stack_t *scope_stack_start_p = context_p->scope_stack_p;
        parser_scope_stack_t *scope_stack_p = scope_stack_start_p + context_p->scope_stack_top;

        while (scope_stack_p > scope_stack_start_p)
        {
          scope_stack_p--;

          if (scope_stack_p->map_from == literal_index)
          {
            JERRY_ASSERT (scanner_decode_map_to (scope_stack_p) >= PARSER_REGISTER_START
                          || (literal_p->status_flags & LEXER_FLAG_USED));
            context_p->lit_object.index = scanner_decode_map_to (scope_stack_p);
            return;
          }
        }

        literal_p->status_flags |= LEXER_FLAG_USED;
      }
      return;
    }

    literal_index++;
  }

  JERRY_ASSERT (literal_index == context_p->literal_count);

  if (literal_index >= PARSER_MAXIMUM_NUMBER_OF_LITERALS)
  {
    parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED);
  }

  literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool);
  literal_p->prop.length = (prop_length_t) length;
  literal_p->type = literal_type;

  uint8_t status_flags = LEXER_FLAG_SOURCE_PTR;

  if (length > 0 && char_p == local_byte_array)
  {
    literal_p->u.char_p = (uint8_t *) jmem_heap_alloc_block (length);
    memcpy ((uint8_t *) literal_p->u.char_p, char_p, length);
    status_flags = 0;
  }
  else
  {
    literal_p->u.char_p = char_p;

    /* Buffer is taken over when a new literal is constructed. */
    if (context_p->u.allocated_buffer_p != NULL)
    {
      JERRY_ASSERT (char_p == context_p->u.allocated_buffer_p);

      context_p->u.allocated_buffer_p = NULL;
      status_flags = 0;
    }
  }

  if (search_scope_stack)
  {
    status_flags |= LEXER_FLAG_USED;
  }

  if (lit_location_p->status_flags & LEXER_LIT_LOCATION_IS_ASCII)
  {
    literal_p->status_flags |= LEXER_FLAG_ASCII;
  }

  literal_p->status_flags = status_flags;

  context_p->lit_object.literal_p = literal_p;
  context_p->lit_object.index = (uint16_t) literal_index;
  context_p->literal_count++;

  JERRY_ASSERT (context_p->u.allocated_buffer_p == NULL);
} /* lexer_construct_literal_object */


lexer_check_post_primary_exp (parser_context_t *context_p) /**< context */
{
  if (!(context_p->token.flags & LEXER_NO_SKIP_SPACES))
  {
    lexer_skip_spaces (context_p);
    context_p->token.flags = (uint8_t) (context_p->token.flags | LEXER_NO_SKIP_SPACES);
  }

  if (context_p->source_p >= context_p->source_end_p)
  {
    return false;
  }

  switch (context_p->source_p[0])
  {
    case LIT_CHAR_DOT:
    case LIT_CHAR_LEFT_PAREN:
    case LIT_CHAR_LEFT_SQUARE:
#if JERRY_ESNEXT
    case LIT_CHAR_GRAVE_ACCENT:
#endif /* JERRY_ESNEXT */
    {
      return true;
    }
    case LIT_CHAR_PLUS:
    case LIT_CHAR_MINUS:
    {
      return (!(context_p->token.flags & LEXER_WAS_NEWLINE) && context_p->source_p + 1 < context_p->source_end_p
              && context_p->source_p[1] == context_p->source_p[0]);
    }
#if JERRY_ESNEXT
    case LIT_CHAR_ASTERISK:
    {
      return (context_p->source_p + 1 < context_p->source_end_p
              && context_p->source_p[1] == (uint8_t) LIT_CHAR_ASTERISK);
    }
#endif /* JERRY_ESNEXT */
  }

  return false;
} /* lexer_check_post_primary_exp */


lexer_scan_private_identifier (parser_context_t *context_p) /**< context */
{
  context_p->token.keyword_type = LEXER_EOS;
  context_p->token.line = context_p->line;
  context_p->token.column = context_p->column;

  return (context_p->source_p < context_p->source_end_p && lexer_parse_identifier (context_p, LEXER_PARSE_NO_OPTS));
} /* lexer_scan_private_identifier */


lexer_check_next_characters (parser_context_t *context_p, /**< context */
                             lit_utf8_byte_t character1, /**< first alternative character */
                             lit_utf8_byte_t character2) /**< second alternative character */
{
  if (!(context_p->token.flags & LEXER_NO_SKIP_SPACES))
  {
    lexer_skip_spaces (context_p);
    context_p->token.flags = (uint8_t) (context_p->token.flags | LEXER_NO_SKIP_SPACES);
  }

  return (context_p->source_p < context_p->source_end_p
          && (context_p->source_p[0] == (uint8_t) character1 || context_p->source_p[0] == (uint8_t) character2));
} /* lexer_check_next_characters */


lexer_current_is_literal (parser_context_t *context_p, /**< context */
                          const lexer_lit_location_t *right_ident_p) /**< identifier */
{
  JERRY_ASSERT (context_p->token.type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_IDENT_LITERAL);

  lexer_lit_location_t *left_ident_p = &context_p->token.lit_location;

  JERRY_ASSERT (left_ident_p->length > 0 && right_ident_p->length > 0);

  if (left_ident_p->length != right_ident_p->length)
  {
    return false;
  }

  if (!((left_ident_p->status_flags | right_ident_p->status_flags) & LEXER_LIT_LOCATION_HAS_ESCAPE))
  {
    return memcmp (left_ident_p->char_p, right_ident_p->char_p, left_ident_p->length) == 0;
  }

  return lexer_compare_identifiers (context_p, left_ident_p, right_ident_p);
} /* lexer_current_is_literal */


static int r_cmd_java_handle_find_cp_const (RCore *core, const char *cmd) {
	const char *p = (cmd && *cmd == ' ')?  r_cmd_java_consumetok (cmd, ' ', -1): NULL;
	RBinJavaObj *obj = (RBinJavaObj *) r_cmd_java_get_bin_obj (get_anal (core));
	RAnalFunction *fcn = NULL;
	RAnalBlock *bb = NULL;
	RListIter *bb_iter, *fn_iter, *iter;
	RCmdJavaCPResult *cp_res = NULL;
	ut16 idx = -1;
	RList *find_list;

	if (p && *p == 'a') {
		idx = -1;
	} else {
		idx = r_cmd_java_get_input_num_value (core, p);
	}

	IFDBG r_cons_printf ("Function call made: %s\n", cmd);

	if (!obj) {
		eprintf ("[-] r_cmd_java: no valid java bins found.\n");
		return true;
	}
	if (!cmd || !*cmd) {
		eprintf ("[-] r_cmd_java: invalid command syntax.\n");
		r_cmd_java_print_cmd_help (JAVA_CMDS+FIND_CP_CONST_IDX);
		return true;
	}
	if (idx == 0) {
		eprintf ("[-] r_cmd_java: invalid CP Obj Index Supplied.\n");
		return true;
	}
	find_list = r_list_new ();
	find_list->free = free;
	// XXX - this will break once RAnal moves to sdb
	r_list_foreach (core->anal->fcns, fn_iter, fcn) {
		r_list_foreach (fcn->bbs, bb_iter, bb) {
			char op = bb->op_bytes[0];
			cp_res = NULL;
			switch (op) {
			case 0x12:
				cp_res = (idx == (ut16) -1) || (bb->op_bytes[1] == idx) ?
							R_NEW0(RCmdJavaCPResult) : NULL;
				if (cp_res) {
					cp_res->idx = bb->op_bytes[1];
				}
				break;
			case 0x13:
			case 0x14:
				cp_res = (idx == (ut16) -1) || (R_BIN_JAVA_USHORT (bb->op_bytes, 1) == idx) ?
							R_NEW0(RCmdJavaCPResult) : NULL;
				if (cp_res) {
					cp_res->idx = R_BIN_JAVA_USHORT (bb->op_bytes, 1);
				}
				break;
			}
			if (cp_res) {
				cp_res->addr = bb->addr;
				cp_res->obj = r_bin_java_get_item_from_cp (obj, cp_res->idx);
				r_list_append (find_list, cp_res);
			}
		}
	}
	if (idx == (ut16) -1) {
		r_list_foreach (find_list, iter, cp_res) {
			const char *t = ((RBinJavaCPTypeMetas *) cp_res->obj->metas->type_info)->name;
			r_cons_printf ("@0x%"PFMT64x" idx = %d Type = %s\n", cp_res->addr, cp_res->idx, t);
		}

	} else {
		r_list_foreach (find_list, iter, cp_res) {
			r_cons_printf ("@0x%"PFMT64x"\n", cp_res->addr);
		}
	}
	r_list_free (find_list);
	return true;
}


static RList * r_cmd_java_get_bin_obj_list(RAnal *anal) {
	RBinJavaObj *bin_obj = (RBinJavaObj * ) r_cmd_java_get_bin_obj(anal);
	// See libr/bin/p/bin_java.c to see what is happening here.  The original intention
	// was to use a shared global db variable from shlr/java/class.c, but the
	// BIN_OBJS_ADDRS variable kept getting corrupted on Mac, so I (deeso) switched the
	// way the access to the db was taking place by using the bin_obj as a proxy back
	// to the BIN_OBJS_ADDRS which is instantiated in libr/bin/p/bin_java.c
	// not the easiest way to make sausage, but its getting made.
	return  r_bin_java_get_bin_obj_list_thru_obj (bin_obj);
}


static RAnal * get_anal (RCore *core) {
	return core? core->anal: NULL;
}


static ut8 _(r_cmd_java_obj_ref)(const char *name, const char *class_name, ut32 len) {
	if (!name || !class_name) {
		return false;
	}
	if (strncmp (class_name, name, len)) {
		return false;
	}
	if (*(name - 1) == 'L' && *(name + len) == ';') {
		return true;
	}
	if (!strncmp (class_name, name, len) && !*(name + len)) {
		return true;
	}
	return false;
}


static int r_cmd_java_print_field_access_flags_value( const char * flags ){
	ut16 result = r_bin_java_calculate_field_access_value (flags);
	r_cons_printf ("Access Value for %s = 0x%04x\n", flags,  result);
	return true;
}


static int r_cmd_is_object_descriptor (const char *name, ut32 name_len) {
	int found_L = false, found_Semi = false;
	ut32 idx = 0, L_pos = 0, Semi_pos = 0;
	const char *p_name = name;

	for (idx = 0, L_pos = 0; idx < name_len; idx++,p_name++) {
		if (*p_name == 'L') {
			found_L = true;
			L_pos = idx;
			break;
		}
	}

	for (idx = 0, Semi_pos = 0; idx < name_len; idx++,p_name++) {
		if (*p_name == ';') {
			found_Semi = true;
			Semi_pos = idx;
			break;
		}
	}

	return true ? found_L == found_Semi && found_L == true && L_pos < Semi_pos : false;
}


static int r_cmd_java_print_method_definitions ( RBinJavaObj *obj ) {
	RList * the_list = r_bin_java_get_method_definitions (obj),
			* off_list = r_bin_java_get_method_offsets (obj);
	char * str = NULL;
	ut32 idx = 0, end = r_list_length (the_list);

	while (idx < end) {
		ut64 *addr = r_list_get_n (off_list, idx);
		str = r_list_get_n (the_list, idx);
		r_cons_printf("%s; // @0x%04"PFMT64x"\n", str, *addr);
		idx++;
	}

	r_list_free (the_list);
	r_list_free (off_list);
	return true;
}


Status SliceShape(InferenceContext* c) {
  ShapeHandle input = c->input(0);
  ShapeHandle begin_shape;
  TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 1, &begin_shape));
  ShapeHandle sizes_shape;
  TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 1, &sizes_shape));

  // Merge to check compatibility of begin and sizes tensors.
  TF_RETURN_IF_ERROR(c->Merge(begin_shape, sizes_shape, &begin_shape));

  DimensionHandle ndims = c->Dim(begin_shape, 0);
  if (c->ValueKnown(ndims)) {
    TF_RETURN_IF_ERROR(c->WithRank(input, c->Value(ndims), &input));
  }

  // NOTE(mrry): Use MakeShapeFromShapeTensor to handle partially-known
  // values, even though the `begin` value does not represent a shape.
  ShapeHandle begin_value;
  TF_RETURN_IF_ERROR(c->MakeShapeFromShapeTensor(1, &begin_value));

  // We check the tensor value here and will only use
  // `MakeShapeFromShapeTensor` when `sizes_value` is null.
  // The reason is that `sizes` might contain -1, which can't
  // be represented (-1 in the ShapeHandle would mean "unknown").
  const Tensor* sizes_value = c->input_tensor(2);

  if (sizes_value != nullptr) {
    TF_RETURN_IF_ERROR(
        c->WithRank(begin_value, sizes_value->NumElements(), &begin_value));
    std::vector<DimensionHandle> dims;
    // If the begin and sizes tensors are available, then
    // we can be precise about the shape of the output.
    if (sizes_value->dtype() == DT_INT64) {
      TF_RETURN_IF_ERROR(
          SliceHelper<int64_t>(c, begin_value, sizes_value, &dims));
    } else {
      TF_RETURN_IF_ERROR(
          SliceHelper<int32>(c, begin_value, sizes_value, &dims));
    }
    c->set_output(0, c->MakeShape(dims));
    return Status::OK();
  } else {
    // In case `sizes` is not available (`sizes_value` is null),
    // we could try to use `MakeShapeFromShapeTensor` here.
    // If sizes contain -1, we will simply consider it as `Unknown`.
    // This is less than ideal but still an improvement of shape inference.
    // The following is an example that returns [None, 1, None] with this
    // code path:
    //   z = tf.zeros((1, 2, 3))
    //   m = tf.slice(z, [0, 0, 0], [tf.constant(1) + 0, 1, -1])
    //   m.get_shape().as_list()
    ShapeHandle sizes_value;
    TF_RETURN_IF_ERROR(c->MakeShapeFromShapeTensor(2, &sizes_value));
    if (c->RankKnown(sizes_value)) {
      TF_RETURN_IF_ERROR(
          c->WithRank(begin_value, c->Rank(sizes_value), &begin_value));
      std::vector<DimensionHandle> dims;
      dims.reserve(c->Rank(sizes_value));
      for (int i = 0; i < c->Rank(sizes_value); ++i) {
        dims.emplace_back(c->Dim(sizes_value, i));
      }
      c->set_output(0, c->MakeShape(dims));
      return Status::OK();
    }
    // We might know the rank of the input.
    if (c->RankKnown(input)) {
      c->set_output(0, c->UnknownShapeOfRank(c->Rank(input)));
      return Status::OK();
    } else {
      return shape_inference::UnknownShape(c);
    }
  }

  return Status::OK();
}


static void credential_apply_config(struct credential *c)
{
	if (c->configured)
		return;
	git_config(credential_config_callback, c);
	c->configured = 1;

	if (!c->use_http_path && proto_is_http(c->protocol)) {
		FREE_AND_NULL(c->path);
	}
}


  static Status Compute(OpKernelContext* context,
                        const typename TTypes<Tidx, 1>::ConstTensor& arr,
                        const typename TTypes<T, 1>::ConstTensor& weights,
                        typename TTypes<T, 1>::Tensor& output,
                        const Tidx num_bins) {
    Tensor all_nonneg_t;
    TF_RETURN_IF_ERROR(context->allocate_temp(
        DT_BOOL, TensorShape({}), &all_nonneg_t, AllocatorAttributes()));
    all_nonneg_t.scalar<bool>().device(context->eigen_cpu_device()) =
        (arr >= Tidx(0)).all();
    if (!all_nonneg_t.scalar<bool>()()) {
      return errors::InvalidArgument("Input arr must be non-negative!");
    }

    // Allocate partial output bin sums for each worker thread. Worker ids in
    // ParallelForWithWorkerId range from 0 to NumThreads() inclusive.
    ThreadPool* thread_pool =
        context->device()->tensorflow_cpu_worker_threads()->workers;
    const int64_t num_threads = thread_pool->NumThreads() + 1;
    Tensor partial_bins_t;
    TF_RETURN_IF_ERROR(context->allocate_temp(
        DT_BOOL, TensorShape({num_threads, num_bins}), &partial_bins_t));
    auto partial_bins = partial_bins_t.matrix<bool>();
    partial_bins.setZero();
    thread_pool->ParallelForWithWorkerId(
        arr.size(), 8 /* cost */,
        [&](int64_t start_ind, int64_t limit_ind, int64_t worker_id) {
          for (int64_t i = start_ind; i < limit_ind; i++) {
            Tidx value = arr(i);
            if (value < num_bins) {
              partial_bins(worker_id, value) = true;
            }
          }
        });

    // Sum the partial bins along the 0th axis.
    Eigen::array<int, 1> reduce_dim({0});
    output.device(context->eigen_cpu_device()) =
        partial_bins.any(reduce_dim).cast<T>();
    return Status::OK();
  }


  static Status Compute(OpKernelContext* context,
                        const typename TTypes<Tidx, 2>::ConstTensor& in,
                        const typename TTypes<T, 2>::ConstTensor& weights,
                        typename TTypes<T, 2>::Tensor& out,
                        const Tidx num_bins) {
    const int num_rows = out.dimension(0);
    const int num_cols = in.dimension(1);
    ThreadPool* thread_pool =
        context->device()->tensorflow_cpu_worker_threads()->workers;
    thread_pool->ParallelForWithWorkerId(
        num_rows, 8 /* cost */,
        [&](int64_t start_row, int64_t end_row, int64_t worker_id) {
          for (int64_t i = start_row; i < end_row; ++i) {
            for (int64_t j = 0; j < num_cols; ++j) {
              Tidx value = in(i, j);
              if (value < num_bins) {
                if (binary_output) {
                  out(i, value) = T(1);
                } else {
                  if (weights.size()) {
                    out(i, value) += weights(i, j);
                  } else {
                    out(i, value) += T(1);
                  }
                }
              }
            }
          }
        });
    return Status::OK();
  }


  void Compute(OpKernelContext* ctx) override {
    const Tensor& indices = ctx->input(0);
    const auto values = ctx->input(1).flat<Tidx>();
    const Tensor& dense_shape = ctx->input(2);
    const Tensor& size_t = ctx->input(3);
    const auto weights = ctx->input(4).flat<T>();
    const int64_t weights_size = weights.size();

    Tidx size = size_t.scalar<Tidx>()();
    OP_REQUIRES(
        ctx, size >= 0,
        errors::InvalidArgument("size (", size, ") must be non-negative"));

    bool is_1d = dense_shape.NumElements() == 1;

    Tensor* out_t;
    functor::SetZeroFunctor<Device, T> fill;
    if (is_1d) {
      OP_REQUIRES_OK(ctx, ctx->allocate_output(0, TensorShape({size}), &out_t));
      auto out = out_t->flat<T>();
      fill(ctx->eigen_device<Device>(), out);
      if (binary_output_) {
        OP_REQUIRES_OK(ctx,
                       functor::BincountFunctor<Device, Tidx, T, true>::Compute(
                           ctx, values, weights, out, size));
      } else {
        OP_REQUIRES_OK(
            ctx, functor::BincountFunctor<Device, Tidx, T, false>::Compute(
                     ctx, values, weights, out, size));
      }
    } else {
      const auto shape = dense_shape.flat<int64_t>();
      const int64_t num_rows = shape(0);
      OP_REQUIRES_OK(
          ctx, ctx->allocate_output(0, TensorShape({num_rows, size}), &out_t));
      const auto out = out_t->matrix<T>();
      fill(ctx->eigen_device<Device>(), out_t->flat<T>());
      const auto indices_mat = indices.matrix<int64_t>();
      for (int64_t i = 0; i < indices_mat.dimension(0); ++i) {
        const int64_t batch = indices_mat(i, 0);
        const Tidx bin = values(i);
        OP_REQUIRES(
            ctx, batch < out.dimension(0),
            errors::InvalidArgument("Index out of bound. `batch` (", batch,
                                    ") must be less than the dimension size (",
                                    out.dimension(0), ")."));
        OP_REQUIRES(
            ctx, bin < out.dimension(1),
            errors::InvalidArgument("Index out ouf bound. `bin` (", bin,
                                    ") must be less then the dimension size (",
                                    out.dimension(1), ")."));
        if (bin < size) {
          if (binary_output_) {
            out(batch, bin) = T(1);
          } else {
            if (weights_size) {
              out(batch, bin) += weights(i);
            } else {
              out(batch, bin) += T(1);
            }
          }
        }
      }
    }
  }


CConfigEntry::~CConfigEntry() { delete m_pSubConfig; }


int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
			    struct btrfs_root *root,
			    struct btrfs_path *path,
			    struct btrfs_key *cpu_key, u32 *data_size,
			    int nr)
{
	int ret = 0;
	int slot;
	int i;
	u32 total_size = 0;
	u32 total_data = 0;

	for (i = 0; i < nr; i++)
		total_data += data_size[i];

	total_size = total_data + (nr * sizeof(struct btrfs_item));
	ret = btrfs_search_slot(trans, root, cpu_key, path, total_size, 1);
	if (ret == 0)
		return -EEXIST;
	if (ret < 0)
		return ret;

	slot = path->slots[0];
	BUG_ON(slot < 0);

	setup_items_for_insert(root, path, cpu_key, data_size,
			       total_data, total_size, nr);
	return 0;
}


tree_mod_log_eb_copy(struct btrfs_fs_info *fs_info, struct extent_buffer *dst,
		     struct extent_buffer *src, unsigned long dst_offset,
		     unsigned long src_offset, int nr_items)
{
	int ret = 0;
	struct tree_mod_elem **tm_list = NULL;
	struct tree_mod_elem **tm_list_add, **tm_list_rem;
	int i;
	int locked = 0;

	if (!tree_mod_need_log(fs_info, NULL))
		return 0;

	if (btrfs_header_level(dst) == 0 && btrfs_header_level(src) == 0)
		return 0;

	tm_list = kzalloc(nr_items * 2 * sizeof(struct tree_mod_elem *),
			  GFP_NOFS);
	if (!tm_list)
		return -ENOMEM;

	tm_list_add = tm_list;
	tm_list_rem = tm_list + nr_items;
	for (i = 0; i < nr_items; i++) {
		tm_list_rem[i] = alloc_tree_mod_elem(src, i + src_offset,
		    MOD_LOG_KEY_REMOVE, GFP_NOFS);
		if (!tm_list_rem[i]) {
			ret = -ENOMEM;
			goto free_tms;
		}

		tm_list_add[i] = alloc_tree_mod_elem(dst, i + dst_offset,
		    MOD_LOG_KEY_ADD, GFP_NOFS);
		if (!tm_list_add[i]) {
			ret = -ENOMEM;
			goto free_tms;
		}
	}

	if (tree_mod_dont_log(fs_info, NULL))
		goto free_tms;
	locked = 1;

	for (i = 0; i < nr_items; i++) {
		ret = __tree_mod_log_insert(fs_info, tm_list_rem[i]);
		if (ret)
			goto free_tms;
		ret = __tree_mod_log_insert(fs_info, tm_list_add[i]);
		if (ret)
			goto free_tms;
	}

	tree_mod_log_write_unlock(fs_info);
	kfree(tm_list);

	return 0;

free_tms:
	for (i = 0; i < nr_items * 2; i++) {
		if (tm_list[i] && !RB_EMPTY_NODE(&tm_list[i]->node))
			rb_erase(&tm_list[i]->node, &fs_info->tree_mod_log);
		kfree(tm_list[i]);
	}
	if (locked)
		tree_mod_log_write_unlock(fs_info);
	kfree(tm_list);

	return ret;
}


int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
			 struct btrfs_path *path,
			 u64 min_trans)
{
	struct extent_buffer *cur;
	struct btrfs_key found_key;
	int slot;
	int sret;
	u32 nritems;
	int level;
	int ret = 1;
	int keep_locks = path->keep_locks;

	path->keep_locks = 1;
again:
	cur = btrfs_read_lock_root_node(root);
	level = btrfs_header_level(cur);
	WARN_ON(path->nodes[level]);
	path->nodes[level] = cur;
	path->locks[level] = BTRFS_READ_LOCK;

	if (btrfs_header_generation(cur) < min_trans) {
		ret = 1;
		goto out;
	}
	while (1) {
		nritems = btrfs_header_nritems(cur);
		level = btrfs_header_level(cur);
		sret = bin_search(cur, min_key, level, &slot);

		/* at the lowest level, we're done, setup the path and exit */
		if (level == path->lowest_level) {
			if (slot >= nritems)
				goto find_next_key;
			ret = 0;
			path->slots[level] = slot;
			btrfs_item_key_to_cpu(cur, &found_key, slot);
			goto out;
		}
		if (sret && slot > 0)
			slot--;
		/*
		 * check this node pointer against the min_trans parameters.
		 * If it is too old, old, skip to the next one.
		 */
		while (slot < nritems) {
			u64 gen;

			gen = btrfs_node_ptr_generation(cur, slot);
			if (gen < min_trans) {
				slot++;
				continue;
			}
			break;
		}
find_next_key:
		/*
		 * we didn't find a candidate key in this node, walk forward
		 * and find another one
		 */
		if (slot >= nritems) {
			path->slots[level] = slot;
			btrfs_set_path_blocking(path);
			sret = btrfs_find_next_key(root, path, min_key, level,
						  min_trans);
			if (sret == 0) {
				btrfs_release_path(path);
				goto again;
			} else {
				goto out;
			}
		}
		/* save our key for returning back */
		btrfs_node_key_to_cpu(cur, &found_key, slot);
		path->slots[level] = slot;
		if (level == path->lowest_level) {
			ret = 0;
			goto out;
		}
		btrfs_set_path_blocking(path);
		cur = read_node_slot(root, cur, slot);
		BUG_ON(!cur); /* -ENOMEM */

		btrfs_tree_read_lock(cur);

		path->locks[level - 1] = BTRFS_READ_LOCK;
		path->nodes[level - 1] = cur;
		unlock_up(path, level, 1, 0, NULL);
		btrfs_clear_path_blocking(path, NULL, 0);
	}
out:
	path->keep_locks = keep_locks;
	if (ret == 0) {
		btrfs_unlock_up_safe(path, path->lowest_level + 1);
		btrfs_set_path_blocking(path);
		memcpy(min_key, &found_key, sizeof(found_key));
	}
	return ret;
}


int btrfs_previous_extent_item(struct btrfs_root *root,
			struct btrfs_path *path, u64 min_objectid)
{
	struct btrfs_key found_key;
	struct extent_buffer *leaf;
	u32 nritems;
	int ret;

	while (1) {
		if (path->slots[0] == 0) {
			btrfs_set_path_blocking(path);
			ret = btrfs_prev_leaf(root, path);
			if (ret != 0)
				return ret;
		} else {
			path->slots[0]--;
		}
		leaf = path->nodes[0];
		nritems = btrfs_header_nritems(leaf);
		if (nritems == 0)
			return 1;
		if (path->slots[0] == nritems)
			path->slots[0]--;

		btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
		if (found_key.objectid < min_objectid)
			break;
		if (found_key.type == BTRFS_EXTENT_ITEM_KEY ||
		    found_key.type == BTRFS_METADATA_ITEM_KEY)
			return 0;
		if (found_key.objectid == min_objectid &&
		    found_key.type < BTRFS_EXTENT_ITEM_KEY)
			break;
	}
	return 1;
}


static noinline int push_for_double_split(struct btrfs_trans_handle *trans,
					  struct btrfs_root *root,
					  struct btrfs_path *path,
					  int data_size)
{
	int ret;
	int progress = 0;
	int slot;
	u32 nritems;
	int space_needed = data_size;

	slot = path->slots[0];
	if (slot < btrfs_header_nritems(path->nodes[0]))
		space_needed -= btrfs_leaf_free_space(root, path->nodes[0]);

	/*
	 * try to push all the items after our slot into the
	 * right leaf
	 */
	ret = push_leaf_right(trans, root, path, 1, space_needed, 0, slot);
	if (ret < 0)
		return ret;

	if (ret == 0)
		progress++;

	nritems = btrfs_header_nritems(path->nodes[0]);
	/*
	 * our goal is to get our slot at the start or end of a leaf.  If
	 * we've done so we're done
	 */
	if (path->slots[0] == 0 || path->slots[0] == nritems)
		return 0;

	if (btrfs_leaf_free_space(root, path->nodes[0]) >= data_size)
		return 0;

	/* try to push all the items before our slot into the next leaf */
	slot = path->slots[0];
	ret = push_leaf_left(trans, root, path, 1, space_needed, 0, slot);
	if (ret < 0)
		return ret;

	if (ret == 0)
		progress++;

	if (progress)
		return 0;
	return 1;
}


int btrfs_old_root_level(struct btrfs_root *root, u64 time_seq)
{
	struct tree_mod_elem *tm;
	int level;
	struct extent_buffer *eb_root = btrfs_root_node(root);

	tm = __tree_mod_log_oldest_root(root->fs_info, eb_root, time_seq);
	if (tm && tm->op == MOD_LOG_ROOT_REPLACE) {
		level = tm->old_root.level;
	} else {
		level = btrfs_header_level(eb_root);
	}
	free_extent_buffer(eb_root);

	return level;
}


struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
						 struct btrfs_path *path,
						 const char *name, int name_len)
{
	struct btrfs_dir_item *dir_item;
	unsigned long name_ptr;
	u32 total_len;
	u32 cur = 0;
	u32 this_len;
	struct extent_buffer *leaf;

	leaf = path->nodes[0];
	dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
	if (verify_dir_item(root, leaf, dir_item))
		return NULL;

	total_len = btrfs_item_size_nr(leaf, path->slots[0]);
	while (cur < total_len) {
		this_len = sizeof(*dir_item) +
			btrfs_dir_name_len(leaf, dir_item) +
			btrfs_dir_data_len(leaf, dir_item);
		name_ptr = (unsigned long)(dir_item + 1);

		if (btrfs_dir_name_len(leaf, dir_item) == name_len &&
		    memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)
			return dir_item;

		cur += this_len;
		dir_item = (struct btrfs_dir_item *)((char *)dir_item +
						     this_len);
	}
	return NULL;
}


void btrfs_extend_item(struct btrfs_root *root, struct btrfs_path *path,
		       u32 data_size)
{
	int slot;
	struct extent_buffer *leaf;
	struct btrfs_item *item;
	u32 nritems;
	unsigned int data_end;
	unsigned int old_data;
	unsigned int old_size;
	int i;
	struct btrfs_map_token token;

	btrfs_init_map_token(&token);

	leaf = path->nodes[0];

	nritems = btrfs_header_nritems(leaf);
	data_end = leaf_data_end(root, leaf);

	if (btrfs_leaf_free_space(root, leaf) < data_size) {
		btrfs_print_leaf(root, leaf);
		BUG();
	}
	slot = path->slots[0];
	old_data = btrfs_item_end_nr(leaf, slot);

	BUG_ON(slot < 0);
	if (slot >= nritems) {
		btrfs_print_leaf(root, leaf);
		btrfs_crit(root->fs_info, "slot %d too large, nritems %d",
		       slot, nritems);
		BUG_ON(1);
	}

	/*
	 * item0..itemN ... dataN.offset..dataN.size .. data0.size
	 */
	/* first correct the data pointers */
	for (i = slot; i < nritems; i++) {
		u32 ioff;
		item = btrfs_item_nr(i);

		ioff = btrfs_token_item_offset(leaf, item, &token);
		btrfs_set_token_item_offset(leaf, item,
					    ioff - data_size, &token);
	}

	/* shift the data */
	memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) +
		      data_end - data_size, btrfs_leaf_data(leaf) +
		      data_end, old_data - data_end);

	data_end = old_data;
	old_size = btrfs_item_size_nr(leaf, slot);
	item = btrfs_item_nr(slot);
	btrfs_set_item_size(leaf, item, old_size + data_size);
	btrfs_mark_buffer_dirty(leaf);

	if (btrfs_leaf_free_space(root, leaf) < 0) {
		btrfs_print_leaf(root, leaf);
		BUG();
	}
}


int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path,
			u64 time_seq)
{
	int slot;
	int level;
	struct extent_buffer *c;
	struct extent_buffer *next;
	struct btrfs_key key;
	u32 nritems;
	int ret;
	int old_spinning = path->leave_spinning;
	int next_rw_lock = 0;

	nritems = btrfs_header_nritems(path->nodes[0]);
	if (nritems == 0)
		return 1;

	btrfs_item_key_to_cpu(path->nodes[0], &key, nritems - 1);
again:
	level = 1;
	next = NULL;
	next_rw_lock = 0;
	btrfs_release_path(path);

	path->keep_locks = 1;
	path->leave_spinning = 1;

	if (time_seq)
		ret = btrfs_search_old_slot(root, &key, path, time_seq);
	else
		ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
	path->keep_locks = 0;

	if (ret < 0)
		return ret;

	nritems = btrfs_header_nritems(path->nodes[0]);
	/*
	 * by releasing the path above we dropped all our locks.  A balance
	 * could have added more items next to the key that used to be
	 * at the very end of the block.  So, check again here and
	 * advance the path if there are now more items available.
	 */
	if (nritems > 0 && path->slots[0] < nritems - 1) {
		if (ret == 0)
			path->slots[0]++;
		ret = 0;
		goto done;
	}
	/*
	 * So the above check misses one case:
	 * - after releasing the path above, someone has removed the item that
	 *   used to be at the very end of the block, and balance between leafs
	 *   gets another one with bigger key.offset to replace it.
	 *
	 * This one should be returned as well, or we can get leaf corruption
	 * later(esp. in __btrfs_drop_extents()).
	 *
	 * And a bit more explanation about this check,
	 * with ret > 0, the key isn't found, the path points to the slot
	 * where it should be inserted, so the path->slots[0] item must be the
	 * bigger one.
	 */
	if (nritems > 0 && ret > 0 && path->slots[0] == nritems - 1) {
		ret = 0;
		goto done;
	}

	while (level < BTRFS_MAX_LEVEL) {
		if (!path->nodes[level]) {
			ret = 1;
			goto done;
		}

		slot = path->slots[level] + 1;
		c = path->nodes[level];
		if (slot >= btrfs_header_nritems(c)) {
			level++;
			if (level == BTRFS_MAX_LEVEL) {
				ret = 1;
				goto done;
			}
			continue;
		}

		if (next) {
			btrfs_tree_unlock_rw(next, next_rw_lock);
			free_extent_buffer(next);
		}

		next = c;
		next_rw_lock = path->locks[level];
		ret = read_block_for_search(NULL, root, path, &next, level,
					    slot, &key, 0);
		if (ret == -EAGAIN)
			goto again;

		if (ret < 0) {
			btrfs_release_path(path);
			goto done;
		}

		if (!path->skip_locking) {
			ret = btrfs_try_tree_read_lock(next);
			if (!ret && time_seq) {
				/*
				 * If we don't get the lock, we may be racing
				 * with push_leaf_left, holding that lock while
				 * itself waiting for the leaf we've currently
				 * locked. To solve this situation, we give up
				 * on our lock and cycle.
				 */
				free_extent_buffer(next);
				btrfs_release_path(path);
				cond_resched();
				goto again;
			}
			if (!ret) {
				btrfs_set_path_blocking(path);
				btrfs_tree_read_lock(next);
				btrfs_clear_path_blocking(path, next,
							  BTRFS_READ_LOCK);
			}
			next_rw_lock = BTRFS_READ_LOCK;
		}
		break;
	}
	path->slots[level] = slot;
	while (1) {
		level--;
		c = path->nodes[level];
		if (path->locks[level])
			btrfs_tree_unlock_rw(c, path->locks[level]);

		free_extent_buffer(c);
		path->nodes[level] = next;
		path->slots[level] = 0;
		if (!path->skip_locking)
			path->locks[level] = next_rw_lock;
		if (!level)
			break;

		ret = read_block_for_search(NULL, root, path, &next, level,
					    0, &key, 0);
		if (ret == -EAGAIN)
			goto again;

		if (ret < 0) {
			btrfs_release_path(path);
			goto done;
		}

		if (!path->skip_locking) {
			ret = btrfs_try_tree_read_lock(next);
			if (!ret) {
				btrfs_set_path_blocking(path);
				btrfs_tree_read_lock(next);
				btrfs_clear_path_blocking(path, next,
							  BTRFS_READ_LOCK);
			}
			next_rw_lock = BTRFS_READ_LOCK;
		}
	}
	ret = 0;
done:
	unlock_up(path, 0, 1, 0, NULL);
	path->leave_spinning = old_spinning;
	if (!old_spinning)
		btrfs_set_path_blocking(path);

	return ret;
}


int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
			      struct btrfs_root *root,
			      struct btrfs_path *path,
			      struct btrfs_dir_item *di)
{

	struct extent_buffer *leaf;
	u32 sub_item_len;
	u32 item_len;
	int ret = 0;

	leaf = path->nodes[0];
	sub_item_len = sizeof(*di) + btrfs_dir_name_len(leaf, di) +
		btrfs_dir_data_len(leaf, di);
	item_len = btrfs_item_size_nr(leaf, path->slots[0]);
	if (sub_item_len == item_len) {
		ret = btrfs_del_item(trans, root, path);
	} else {
		/* MARKER */
		unsigned long ptr = (unsigned long)di;
		unsigned long start;

		start = btrfs_item_ptr_offset(leaf, path->slots[0]);
		memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
			item_len - (ptr + sub_item_len - start));
		btrfs_truncate_item(root, path, item_len - sub_item_len, 1);
	}
	return ret;
}


int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root
		      *root, struct btrfs_key *cpu_key, void *data, u32
		      data_size)
{
	int ret = 0;
	struct btrfs_path *path;
	struct extent_buffer *leaf;
	unsigned long ptr;

	path = btrfs_alloc_path();
	if (!path)
		return -ENOMEM;
	ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
	if (!ret) {
		leaf = path->nodes[0];
		ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
		write_extent_buffer(leaf, data, ptr, data_size);
		btrfs_mark_buffer_dirty(leaf);
	}
	btrfs_free_path(path);
	return ret;
}


struct extent_buffer *btrfs_root_node(struct btrfs_root *root)
{
	struct extent_buffer *eb;

	while (1) {
		rcu_read_lock();
		eb = rcu_dereference(root->node);

		/*
		 * RCU really hurts here, we could free up the root node because
		 * it was cow'ed but we may not get the new root node yet so do
		 * the inc_not_zero dance and if it doesn't work then
		 * synchronize_rcu and try again.
		 */
		if (atomic_inc_not_zero(&eb->refs)) {
			rcu_read_unlock();
			break;
		}
		rcu_read_unlock();
		synchronize_rcu();
	}
	return eb;
}


__tree_mod_log_search(struct btrfs_fs_info *fs_info, u64 start, u64 min_seq,
		      int smallest)
{
	struct rb_root *tm_root;
	struct rb_node *node;
	struct tree_mod_elem *cur = NULL;
	struct tree_mod_elem *found = NULL;
	u64 index = start >> PAGE_CACHE_SHIFT;

	tree_mod_log_read_lock(fs_info);
	tm_root = &fs_info->tree_mod_log;
	node = tm_root->rb_node;
	while (node) {
		cur = container_of(node, struct tree_mod_elem, node);
		if (cur->index < index) {
			node = node->rb_left;
		} else if (cur->index > index) {
			node = node->rb_right;
		} else if (cur->seq < min_seq) {
			node = node->rb_left;
		} else if (!smallest) {
			/* we want the node with the highest seq */
			if (found)
				BUG_ON(found->seq > cur->seq);
			found = cur;
			node = node->rb_left;
		} else if (cur->seq > min_seq) {
			/* we want the node with the smallest seq */
			if (found)
				BUG_ON(found->seq < cur->seq);
			found = cur;
			node = node->rb_right;
		} else {
			found = cur;
			break;
		}
	}
	tree_mod_log_read_unlock(fs_info);

	return found;
}


juniper_chdlc_print(netdissect_options *ndo,
                    const struct pcap_pkthdr *h, register const u_char *p)
{
        struct juniper_l2info_t l2info;

        l2info.pictype = DLT_JUNIPER_CHDLC;
        if (juniper_parse_header(ndo, p, h, &l2info) == 0)
            return l2info.header_len;

        p+=l2info.header_len;
        /* this DLT contains nothing but raw c-hdlc frames */
        chdlc_print(ndo, p, l2info.length);
        return l2info.header_len;
}


juniper_mfr_print(netdissect_options *ndo,
                  const struct pcap_pkthdr *h, register const u_char *p)
{
        struct juniper_l2info_t l2info;

        memset(&l2info, 0, sizeof(l2info));
        l2info.pictype = DLT_JUNIPER_MFR;
        if (juniper_parse_header(ndo, p, h, &l2info) == 0)
            return l2info.header_len;

        p+=l2info.header_len;

        /* child-link ? */
        if (l2info.cookie_len == 0) {
            mfr_print(ndo, p, l2info.length);
            return l2info.header_len;
        }

        /* first try the LSQ protos */
        if (l2info.cookie_len == AS_PIC_COOKIE_LEN) {
            switch(l2info.proto) {
            case JUNIPER_LSQ_L3_PROTO_IPV4:
                ip_print(ndo, p, l2info.length);
                return l2info.header_len;
            case JUNIPER_LSQ_L3_PROTO_IPV6:
                ip6_print(ndo, p,l2info.length);
                return l2info.header_len;
            case JUNIPER_LSQ_L3_PROTO_MPLS:
                mpls_print(ndo, p, l2info.length);
                return l2info.header_len;
            case JUNIPER_LSQ_L3_PROTO_ISO:
                isoclns_print(ndo, p, l2info.length);
                return l2info.header_len;
            default:
                break;
            }
            return l2info.header_len;
        }

        /* suppress Bundle-ID if frame was captured on a child-link */
        if (ndo->ndo_eflag && EXTRACT_32BITS(l2info.cookie) != 1)
            ND_PRINT((ndo, "Bundle-ID %u, ", l2info.bundle));
        switch (l2info.proto) {
        case (LLCSAP_ISONS<<8 | LLCSAP_ISONS):
            isoclns_print(ndo, p + 1, l2info.length - 1);
            break;
        case (LLC_UI<<8 | NLPID_Q933):
        case (LLC_UI<<8 | NLPID_IP):
        case (LLC_UI<<8 | NLPID_IP6):
            /* pass IP{4,6} to the OSI layer for proper link-layer printing */
            isoclns_print(ndo, p - 1, l2info.length + 1);
            break;
        default:
            ND_PRINT((ndo, "unknown protocol 0x%04x, length %u", l2info.proto, l2info.length));
        }

        return l2info.header_len;
}


snap_print(netdissect_options *ndo, const u_char *p, u_int length, u_int caplen,
	const struct lladdr_info *src, const struct lladdr_info *dst,
	u_int bridge_pad)
{
	uint32_t orgcode;
	register u_short et;
	register int ret;

	ND_TCHECK2(*p, 5);
	if (caplen < 5 || length < 5)
		goto trunc;
	orgcode = EXTRACT_24BITS(p);
	et = EXTRACT_16BITS(p + 3);

	if (ndo->ndo_eflag) {
		/*
		 * Somebody's already printed the MAC addresses, if there
		 * are any, so just print the SNAP header, not the MAC
		 * addresses.
		 */
		ND_PRINT((ndo, "oui %s (0x%06x), %s %s (0x%04x), length %u: ",
		     tok2str(oui_values, "Unknown", orgcode),
		     orgcode,
		     (orgcode == 0x000000 ? "ethertype" : "pid"),
		     tok2str(oui_to_struct_tok(orgcode), "Unknown", et),
		     et, length - 5));
	}
	p += 5;
	length -= 5;
	caplen -= 5;

	switch (orgcode) {
	case OUI_ENCAP_ETHER:
	case OUI_CISCO_90:
		/*
		 * This is an encapsulated Ethernet packet,
		 * or a packet bridged by some piece of
		 * Cisco hardware; the protocol ID is
		 * an Ethernet protocol type.
		 */
		ret = ethertype_print(ndo, et, p, length, caplen, src, dst);
		if (ret)
			return (ret);
		break;

	case OUI_APPLETALK:
		if (et == ETHERTYPE_ATALK) {
			/*
			 * No, I have no idea why Apple used one
			 * of their own OUIs, rather than
			 * 0x000000, and an Ethernet packet
			 * type, for Appletalk data packets,
			 * but used 0x000000 and an Ethernet
			 * packet type for AARP packets.
			 */
			ret = ethertype_print(ndo, et, p, length, caplen, src, dst);
			if (ret)
				return (ret);
		}
		break;

	case OUI_CISCO:
                switch (et) {
                case PID_CISCO_CDP:
                        cdp_print(ndo, p, length, caplen);
                        return (1);
                case PID_CISCO_DTP:
                        dtp_print(ndo, p, length);
                        return (1);
                case PID_CISCO_UDLD:
                        udld_print(ndo, p, length);
                        return (1);
                case PID_CISCO_VTP:
                        vtp_print(ndo, p, length);
                        return (1);
                case PID_CISCO_PVST:
                case PID_CISCO_VLANBRIDGE:
                        stp_print(ndo, p, length);
                        return (1);
                default:
                        break;
                }
		break;

	case OUI_RFC2684:
		switch (et) {

		case PID_RFC2684_ETH_FCS:
		case PID_RFC2684_ETH_NOFCS:
			/*
			 * XXX - remove the last two bytes for
			 * PID_RFC2684_ETH_FCS?
			 */
			/*
			 * Skip the padding.
			 */
			ND_TCHECK2(*p, bridge_pad);
			caplen -= bridge_pad;
			length -= bridge_pad;
			p += bridge_pad;

			/*
			 * What remains is an Ethernet packet.
			 */
			ether_print(ndo, p, length, caplen, NULL, NULL);
			return (1);

		case PID_RFC2684_802_5_FCS:
		case PID_RFC2684_802_5_NOFCS:
			/*
			 * XXX - remove the last two bytes for
			 * PID_RFC2684_ETH_FCS?
			 */
			/*
			 * Skip the padding, but not the Access
			 * Control field.
			 */
			ND_TCHECK2(*p, bridge_pad);
			caplen -= bridge_pad;
			length -= bridge_pad;
			p += bridge_pad;

			/*
			 * What remains is an 802.5 Token Ring
			 * packet.
			 */
			token_print(ndo, p, length, caplen);
			return (1);

		case PID_RFC2684_FDDI_FCS:
		case PID_RFC2684_FDDI_NOFCS:
			/*
			 * XXX - remove the last two bytes for
			 * PID_RFC2684_ETH_FCS?
			 */
			/*
			 * Skip the padding.
			 */
			ND_TCHECK2(*p, bridge_pad + 1);
			caplen -= bridge_pad + 1;
			length -= bridge_pad + 1;
			p += bridge_pad + 1;

			/*
			 * What remains is an FDDI packet.
			 */
			fddi_print(ndo, p, length, caplen);
			return (1);

		case PID_RFC2684_BPDU:
			stp_print(ndo, p, length);
			return (1);
		}
	}
	if (!ndo->ndo_eflag) {
		/*
		 * Nobody printed the link-layer addresses, so print them, if
		 * we have any.
		 */
		if (src != NULL && dst != NULL) {
			ND_PRINT((ndo, "%s > %s ",
				(src->addr_string)(ndo, src->addr),
				(dst->addr_string)(ndo, dst->addr)));
		}
		/*
		 * Print the SNAP header, but if the OUI is 000000, don't
		 * bother printing it, and report the PID as being an
		 * ethertype.
		 */
		if (orgcode == 0x000000) {
			ND_PRINT((ndo, "SNAP, ethertype %s (0x%04x), length %u: ",
			     tok2str(ethertype_values, "Unknown", et),
			     et, length));
		} else {
			ND_PRINT((ndo, "SNAP, oui %s (0x%06x), pid %s (0x%04x), length %u: ",
			     tok2str(oui_values, "Unknown", orgcode),
			     orgcode,
			     tok2str(oui_to_struct_tok(orgcode), "Unknown", et),
			     et, length));
		}
	}
	return (0);

trunc:
	ND_PRINT((ndo, "[|snap]"));
	return (1);
}


gre_sre_print(netdissect_options *ndo, uint16_t af, uint8_t sreoff,
    uint8_t srelen, const u_char *bp, u_int len)
{
	int ret;

	switch (af) {
	case GRESRE_IP:
		ND_PRINT((ndo, ", (rtaf=ip"));
		ret = gre_sre_ip_print(ndo, sreoff, srelen, bp, len);
		ND_PRINT((ndo, ")"));
		break;
	case GRESRE_ASN:
		ND_PRINT((ndo, ", (rtaf=asn"));
		ret = gre_sre_asn_print(ndo, sreoff, srelen, bp, len);
		ND_PRINT((ndo, ")"));
		break;
	default:
		ND_PRINT((ndo, ", (rtaf=0x%x)", af));
		ret = 1;
	}
	return (ret);
}


juniper_ppp_print(netdissect_options *ndo,
                  const struct pcap_pkthdr *h, register const u_char *p)
{
        struct juniper_l2info_t l2info;

        l2info.pictype = DLT_JUNIPER_PPP;
        if (juniper_parse_header(ndo, p, h, &l2info) == 0)
            return l2info.header_len;

        p+=l2info.header_len;
        /* this DLT contains nothing but raw ppp frames */
        ppp_print(ndo, p, l2info.length);
        return l2info.header_len;
}


static TEE_Result get_open_session_meta(size_t num_params,
					struct optee_msg_param *params,
					size_t *num_meta, TEE_UUID *uuid,
					TEE_Identity *clnt_id)
{
	const uint32_t req_attr = OPTEE_MSG_ATTR_META |
				  OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;

	if (num_params < 2)
		return TEE_ERROR_BAD_PARAMETERS;

	if (params[0].attr != req_attr || params[1].attr != req_attr)
		return TEE_ERROR_BAD_PARAMETERS;

	tee_uuid_from_octets(uuid, (void *)&params[0].u.value);
	clnt_id->login = params[1].u.value.c;
	switch (clnt_id->login) {
	case TEE_LOGIN_PUBLIC:
		memset(&clnt_id->uuid, 0, sizeof(clnt_id->uuid));
		break;
	case TEE_LOGIN_USER:
	case TEE_LOGIN_GROUP:
	case TEE_LOGIN_APPLICATION:
	case TEE_LOGIN_APPLICATION_USER:
	case TEE_LOGIN_APPLICATION_GROUP:
		tee_uuid_from_octets(&clnt_id->uuid,
				     (void *)&params[1].u.value);
		break;
	default:
		return TEE_ERROR_BAD_PARAMETERS;
	}

	*num_meta = 2;
	return TEE_SUCCESS;
}


static TEE_Result copy_in_params(const struct optee_msg_param *params,
				 uint32_t num_params,
				 struct tee_ta_param *ta_param,
				 uint64_t *saved_attr)
{
	TEE_Result res;
	size_t n;
	uint8_t pt[TEE_NUM_PARAMS] = { 0 };

	if (num_params > TEE_NUM_PARAMS)
		return TEE_ERROR_BAD_PARAMETERS;

	memset(ta_param, 0, sizeof(*ta_param));

	for (n = 0; n < num_params; n++) {
		uint32_t attr;

		saved_attr[n] = READ_ONCE(params[n].attr);

		if (saved_attr[n] & OPTEE_MSG_ATTR_META)
			return TEE_ERROR_BAD_PARAMETERS;

		attr = saved_attr[n] & OPTEE_MSG_ATTR_TYPE_MASK;
		switch (attr) {
		case OPTEE_MSG_ATTR_TYPE_NONE:
			pt[n] = TEE_PARAM_TYPE_NONE;
			break;
		case OPTEE_MSG_ATTR_TYPE_VALUE_INPUT:
		case OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT:
		case OPTEE_MSG_ATTR_TYPE_VALUE_INOUT:
			pt[n] = TEE_PARAM_TYPE_VALUE_INPUT + attr -
				OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
			ta_param->u[n].val.a = READ_ONCE(params[n].u.value.a);
			ta_param->u[n].val.b = READ_ONCE(params[n].u.value.b);
			break;
		case OPTEE_MSG_ATTR_TYPE_TMEM_INPUT:
		case OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT:
		case OPTEE_MSG_ATTR_TYPE_TMEM_INOUT:
			res = set_tmem_param(&params[n].u.tmem, saved_attr[n],
					     &ta_param->u[n].mem);
			if (res)
				return res;
			pt[n] = TEE_PARAM_TYPE_MEMREF_INPUT + attr -
				OPTEE_MSG_ATTR_TYPE_TMEM_INPUT;
			break;
		case OPTEE_MSG_ATTR_TYPE_RMEM_INPUT:
		case OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT:
		case OPTEE_MSG_ATTR_TYPE_RMEM_INOUT:
			res = set_rmem_param(&params[n].u.rmem,
					     &ta_param->u[n].mem);
			if (res)
				return res;
			pt[n] = TEE_PARAM_TYPE_MEMREF_INPUT + attr -
				OPTEE_MSG_ATTR_TYPE_RMEM_INPUT;
			break;
		default:
			return TEE_ERROR_BAD_PARAMETERS;
		}
	}

	ta_param->types = TEE_PARAM_TYPES(pt[0], pt[1], pt[2], pt[3]);

	return TEE_SUCCESS;
}


static void entry_open_session(struct thread_smc_args *smc_args,
			       struct optee_msg_arg *arg, uint32_t num_params)
{
	TEE_Result res;
	TEE_ErrorOrigin err_orig = TEE_ORIGIN_TEE;
	struct tee_ta_session *s = NULL;
	TEE_Identity clnt_id;
	TEE_UUID uuid;
	struct tee_ta_param param;
	size_t num_meta;
	uint64_t saved_attr[TEE_NUM_PARAMS] = { 0 };

	res = get_open_session_meta(num_params, arg->params, &num_meta, &uuid,
				    &clnt_id);
	if (res != TEE_SUCCESS)
		goto out;

	res = copy_in_params(arg->params + num_meta, num_params - num_meta,
			     &param, saved_attr);
	if (res != TEE_SUCCESS)
		goto cleanup_shm_refs;

	res = tee_ta_open_session(&err_orig, &s, &tee_open_sessions, &uuid,
				  &clnt_id, TEE_TIMEOUT_INFINITE, &param);
	if (res != TEE_SUCCESS)
		s = NULL;
	copy_out_param(&param, num_params - num_meta, arg->params + num_meta,
		       saved_attr);

	/*
	 * The occurrence of open/close session command is usually
	 * un-predictable, using this property to increase randomness
	 * of prng
	 */
	plat_prng_add_jitter_entropy(CRYPTO_RNG_SRC_JITTER_SESSION,
				     &session_pnum);

cleanup_shm_refs:
	cleanup_shm_refs(saved_attr, &param, num_params - num_meta);

out:
	if (s)
		arg->session = (vaddr_t)s;
	else
		arg->session = 0;
	arg->ret = res;
	arg->ret_origin = err_orig;
	smc_args->a0 = OPTEE_SMC_RETURN_OK;
}


  Status ValidateInputsGenerateOutputs(
      OpKernelContext* ctx, const Tensor** inputs, const Tensor** seq_len,
      Tensor** log_prob, OpOutputList* decoded_indices,
      OpOutputList* decoded_values, OpOutputList* decoded_shape) const {
    Status status = ctx->input("inputs", inputs);
    if (!status.ok()) return status;
    status = ctx->input("sequence_length", seq_len);
    if (!status.ok()) return status;

    const TensorShape& inputs_shape = (*inputs)->shape();

    if (inputs_shape.dims() != 3) {
      return errors::InvalidArgument("inputs is not a 3-Tensor");
    }
    if (inputs_shape.num_elements() == 0) {
      return errors::InvalidArgument("inputs must not be empty");
    }

    const int64 max_time = inputs_shape.dim_size(0);
    const int64 batch_size = inputs_shape.dim_size(1);

    if (max_time == 0) {
      return errors::InvalidArgument("max_time is 0");
    }
    if (!TensorShapeUtils::IsVector((*seq_len)->shape())) {
      return errors::InvalidArgument("sequence_length is not a vector");
    }

    if (!(batch_size == (*seq_len)->dim_size(0))) {
      return errors::FailedPrecondition(
          "len(sequence_length) != batch_size.  ",
          "len(sequence_length):  ", (*seq_len)->dim_size(0),
          " batch_size: ", batch_size);
    }

    auto seq_len_t = (*seq_len)->vec<int32>();

    for (int b = 0; b < batch_size; ++b) {
      if (!(seq_len_t(b) <= max_time)) {
        return errors::FailedPrecondition("sequence_length(", b,
                                          ") <= ", max_time);
      }
    }

    Status s = ctx->allocate_output(
        "log_probability", TensorShape({batch_size, top_paths_}), log_prob);
    if (!s.ok()) return s;

    s = ctx->output_list("decoded_indices", decoded_indices);
    if (!s.ok()) return s;
    s = ctx->output_list("decoded_values", decoded_values);
    if (!s.ok()) return s;
    s = ctx->output_list("decoded_shape", decoded_shape);
    if (!s.ok()) return s;

    return Status::OK();
  }


void SetTopPaths(int tp) { top_paths_ = tp; }


void SFS_WhileStatement(ScriptParser *parser)
{
	if (parser->codec->LastError) return;
	SFS_AddString(parser, "while (");
	SFS_CompoundExpression(parser);
	SFS_AddString(parser, ")");

	SFS_StatementBlock(parser, GF_FALSE);
}