text: Database driven web application for Dean & Sons Estate Agency

redpajama_set_name: RedPajamaGithub


text:
<component name="libraryTable">
  <library name="Project4Attempt21">
    <CLASSES>
      <root url="jar://$PROJECT_DIR$/CS 249 - Project4 (2)/src/com/company/Project4Attempt2.zip!/" />
    </CLASSES>
    <JAVADOC />
    <SOURCES />
  </library>
</component>


text:
<meta charset="UTF-8">
<title>org.akop.ararat.view - library</title>
<link rel="stylesheet" href="../../style.css">

library / org.akop.ararat.view

Package org.akop.ararat.view

Types

CrosswordView

class CrosswordView : View, OnKeyListener

Type Aliases

InputValidator

typealias InputValidator = (String) -> Boolean


text:
<?php
/**
 * @author: Wojciech Iskra <wojciech.iskra@schibsted.pl>
 */

namespace Dashboard\Model\Widget;

/**
 * Class MessagesWidget
 *
 * @package Dashboard\Model\Widget
 */
class MessagesWidget extends AbstractWidget
{
}


text:
package cypress

import "strings"

func ExpandPath(path string) string {
	if strings.HasPrefix(path, "~/") {
		path = HomeDir + "/" + path[2:]
	}

	return path
}


text:
require 'formula'

class Mp3check < Formula
  desc "Tool to check mp3 files for consistency"
  homepage 'http://code.google.com/p/mp3check/'
  url 'https://mp3check.googlecode.com/files/mp3check-0.8.7.tgz'
  sha1 '31fe95bb7949343f6ebc04fcaa2faffd2b738264'

  def install
    ENV.deparallelize
    # The makefile's install target is kinda iffy, but there's
    # only one file to install so it's easier to do it ourselves
    system "make"
    bin.install 'mp3check'
  end
end


text:
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.

#include "ShaderCompilerCommon.h"
#include "glsl_parser_extras.h"
#include "ir.h"
#include "ir_visitor.h"
#include "ir_rvalue_visitor.h"
#include "OptValueNumbering.h"
#include "IRDump.h"
//@todo-rco: Remove STL!
#include <algorithm>
#include <stack>
#include <vector>
#include "ir_basic_block.h"

#define printf(...)

typedef std::list<struct SBasicBlock*> TBasicBlockList;

struct SBasicBlock
{
	const int id;

	ir_instruction* IRFirst;
	ir_instruction* IRLast;

	TBasicBlockList Predecessors;
	TBasicBlockList Successors;

	static int IDCounter;

	SBasicBlock(ir_instruction* InIRFirst, ir_instruction* InIRLast) : id(IDCounter++), IRFirst(InIRFirst), IRLast(InIRLast)
	{
	}
};

int SBasicBlock::IDCounter(1);

struct SCFG
{
	TBasicBlockList BasicBlocks;

	_mesa_glsl_parse_state* ParseState;
	bool bChanged;

	SCFG(_mesa_glsl_parse_state* InParseState) : ParseState(InParseState), bChanged(false) {}
	~SCFG()
	{
		for (auto it = BasicBlocks.begin(); it != BasicBlocks.end(); ++it)
		{
			delete *it;
		}
	}

	void CallPerBasicBlock( void(*Callback)(SBasicBlock*, SCFG*, void* Data), void* Data )
	{
		for (auto it = BasicBlocks.begin(); it != BasicBlocks.end(); ++it)
		{
			auto* BB = *it;
			Callback(BB, this, Data);
		}
	}
};

struct SNumber
{
	int Number;
	bool bPartialWrite;

	SNumber(int InNumber = -1) : Number(InNumber), bPartialWrite(false) {}

	bool operator==(const SNumber& N) { return Number == N.Number; }
	bool operator!=(const SNumber& N) { return !(*this == N); }

	static SNumber CreateNumber()
	{
		static int Counter = 0;
		++Counter;
		SNumber N(Counter);
		return N;
	}
};
static bool operator<(const SNumber& N1, const SNumber& N2) { return N1.Number < N2.Number; }
typedef TArray<SNumber> TNumberVector;

inline bool AreEqual(TNumberVector& A, TNumberVector& B)
{
	auto Size = A.Num();
	if (Size != B.Num())
	{
		return false;
	}

	for (int i = 0; i < Size; ++i)
	{
		if (A[i] != B[i])
		{
			return false;
		}
	}

	return true;
}

typedef std::map<ir_instruction*, SNumber> TLVN;

struct SLVNRedundancyInfo
{
	int NumRedundancies;
	ir_variable* NewVar;
	ir_assignment* NewAssign;

	SLVNRedundancyInfo() : NumRedundancies(0), NewVar(nullptr), NewAssign(nullptr) {}
};

struct SLVNOptimizeRedundant : public ir_rvalue_visitor
{
	_mesa_glsl_parse_state* ParseState;
	TLVN& LVN;
	std::map<SNumber, SLVNRedundancyInfo>& NumRedundancies;
	bool bChanged;

	SLVNOptimizeRedundant(_mesa_glsl_parse_state* InParseState, TLVN& InLVN, std::map<SNumber, SLVNRedundancyInfo>& InNumRedundancies) :
	ParseState(InParseState),
		LVN(InLVN),
		NumRedundancies(InNumRedundancies),
		bChanged(false)
	{
	}

	virtual void handle_rvalue(ir_rvalue** RValuePtr) override
	{
		if (RValuePtr && *RValuePtr)
		{
			ir_rvalue* RValue = *RValuePtr;
			auto Found = LVN.find(RValue);
			if (Found != LVN.end())
			{
				auto Num = Found->second;
				auto& RedundancyInfo = NumRedundancies[Num];
				if (RedundancyInfo.NumRedundancies > 1)
				{
					if (RedundancyInfo.NewVar == nullptr)
					{
						RedundancyInfo.NewVar = new(ParseState) ir_variable(RValue->type, nullptr, ir_var_temporary);
						RedundancyInfo.NewAssign = new(ParseState) ir_assignment(new(ParseState) ir_dereference_variable(RedundancyInfo.NewVar), RValue);
						base_ir->insert_before(RedundancyInfo.NewVar);
						base_ir->insert_before(RedundancyInfo.NewAssign);
						printf("--- Adding redundancy %d, NewVar %d, New Assign %d\n", Num.Number, RedundancyInfo.NewVar->id, RedundancyInfo.NewAssign->id);
					}

					*RValuePtr = new(ParseState) ir_dereference_variable(RedundancyInfo.NewVar);
					bChanged = true;
				}
			}
		}
	}

	virtual ir_visitor_status visit_leave(ir_call* IR) override
	{
		auto Found = LVN.find(IR);
		if (Found != LVN.end())
		{
			auto Num = Found->second;
			auto& RedundancyInfo = NumRedundancies[Num];
			if (RedundancyInfo.NumRedundancies > 1)
			{
				if (RedundancyInfo.NewVar == nullptr)
				{
					check(IR->return_deref);
					RedundancyInfo.NewVar = new(ParseState) ir_variable(IR->return_deref->type, nullptr, ir_var_temporary);
					RedundancyInfo.NewAssign = new(ParseState) ir_assignment(new(ParseState) ir_dereference_variable(IR->return_deref->var), new(ParseState) ir_dereference_variable(RedundancyInfo.NewVar));
					IR->return_deref = new(ParseState) ir_dereference_variable(RedundancyInfo.NewVar);
					base_ir->insert_before(RedundancyInfo.NewVar);
					base_ir->insert_after(RedundancyInfo.NewAssign);
				}
				else
				{
					// Convert call to assignment
					auto* NewAssign = new(ParseState) ir_assignment(new(ParseState) ir_dereference_variable(IR->return_deref->var), new(ParseState) ir_dereference_variable(RedundancyInfo.NewVar));
					base_ir->insert_after(NewAssign);
					base_ir->remove();
				}
			}
		}

		return visit_continue;
	}
};

typedef std::map<SBasicBlock*, struct SLVNVisitor*> TLVNVisitors;
struct SLVNVisitor : public ir_hierarchical_visitor
{
	TLVN LVN;
	bool bChanged;
	struct SArrayPair
	{
		SNumber Base;
		SNumber Index;

		SArrayPair() {}
		SArrayPair(SNumber B, SNumber I) : Base(B), Index(I) {}
		bool operator==(const SArrayPair& P) { return Base == P.Base && Index == P.Index; }
	};
	std::stack<SNumber> ExpressionNumberStack;
	std::map<ir_variable*, TNumberVector > Assignments;
	std::map<ir_expression*, TNumberVector > Expressions;
	struct SFunctionCall
	{
		TNumberVector Parameters;
		SNumber AssignmentNumber;
	};
	std::map<ir_call*, SFunctionCall > FunctionCalls;
	std::map<ir_texture*, TNumberVector > Textures;
	std::map<ir_dereference_array*, SArrayPair > Arrays;
	std::map<ir_swizzle*, SNumber > SwizzleVars;
	_mesa_glsl_parse_state* ParseState;
	bool bInLHS;

	SLVNVisitor(_mesa_glsl_parse_state* InParseState) : ParseState(InParseState), bChanged(false), bInLHS(false) {}

	virtual ir_visitor_status visit(ir_constant* IR) override
	{
		printf("\tconst @ %d\n", IR->id);
		for (auto it = LVN.begin(); it != LVN.end(); ++it)
		{
			auto* K = it->first->as_constant();
			if (K && K->has_value(IR))
			{
				LVN[IR] = it->second;
				ExpressionNumberStack.push(it->second);
				printf("\t\tRED %d\n", it->second.Number);
				return visit_continue;
			}
		}

		auto Number = SNumber::CreateNumber();
		printf("\t\tNEW %d\n", Number.Number, IR->id);
		LVN[IR] = Number;
		ExpressionNumberStack.push(Number);
		return visit_continue;
	}

	virtual SNumber AddVariable(ir_variable* IR)
	{
		auto Number = SNumber::CreateNumber();
		Assignments[IR].Add(Number);
		return Number;
	}

	virtual ir_visitor_status visit(ir_variable* IR) override
	{
		AddVariable(IR);
		return visit_continue;
	}

	virtual ir_visitor_status visit(ir_dereference_variable* IR) override
	{
		printf("\tDeRefVar @ %d \n", IR->id);
		auto Found = Assignments.find(IR->var);
		if (Found == Assignments.end())
		{
			auto VarNumber = AddVariable(IR->var);
			printf("\t\tNEW %d\n", VarNumber.Number);
			ExpressionNumberStack.push(VarNumber.Number);
		}
		else
		{
			auto& NumberVector = Found->second;
			auto VarNumber = NumberVector[NumberVector.Num() - 1];
			printf("\t\tRED %d\n", VarNumber.Number);
			ExpressionNumberStack.push(VarNumber);
		}

		return visit_continue;
	}

	virtual ir_visitor_status visit_enter(ir_dereference_array* IR) override
	{
		printf("\tArray @ %d\n", IR->id);
		check(!bInLHS);
		auto StackSize = ExpressionNumberStack.size();
		IR->array->accept(this);
		check(StackSize + 1 == ExpressionNumberStack.size());
		IR->array_index->accept(this);
		check(StackSize + 2 == ExpressionNumberStack.size());

		auto Index = ExpressionNumberStack.top();
		ExpressionNumberStack.pop();
		auto Base = ExpressionNumberStack.top();
		ExpressionNumberStack.pop();
		SArrayPair Pair(Base, Index);

		for (auto it = Arrays.begin(); it != Arrays.end(); ++it)
		{
			auto& ArrayPair = it->second;
			if (ArrayPair == Pair)
			{
				auto ArrayNum = LVN[it->first];
				printf("\t\tRED %d\n", ArrayNum.Number);
				ExpressionNumberStack.push(ArrayNum);
				return visit_continue_with_parent;
			}
		}

		auto Number = SNumber::CreateNumber();
		printf("\t\tNEW %d\n", Number.Number);
		LVN[IR] = Number;
		Arrays[IR] = Pair;
		ExpressionNumberStack.push(Number);

		return visit_continue_with_parent;
	}

	virtual ir_visitor_status visit_enter(ir_dereference_image *) override
	{
		check(0);
		return visit_continue_with_parent;
	}

	virtual ir_visitor_status visit_enter(ir_call* IR) override
	{
		printf("* Call @ %d\n", IR->id);

		// Traverse parameters and definitions
		printf("\tParams\n");
		TNumberVector Parameters;
		exec_node* Param = IR->actual_parameters.head;
		exec_node* ParamDefinition = IR->callee->parameters.head;
		check(Param && ParamDefinition);
		while (!Param->is_tail_sentinel() && !ParamDefinition->is_tail_sentinel())
		{
			ir_variable* Def = ((ir_instruction*)ParamDefinition)->as_variable();
			bool bIsOut = (Def->mode == ir_var_inout || Def->mode == ir_var_out);
			// TODO: Support out parameters
			check(!bIsOut);
			ir_rvalue* Parameter = (ir_rvalue*)Param;
			auto StackSize = ExpressionNumberStack.size();
			Parameter->accept(this);
			check(StackSize + 1 == ExpressionNumberStack.size());
			auto ParameterNum = ExpressionNumberStack.top();
			Parameters.Add(ParameterNum);
			ExpressionNumberStack.pop();

			Param = Param->get_next();
			ParamDefinition = ParamDefinition->get_next();
		}
		check(Param->is_tail_sentinel() && ParamDefinition->is_tail_sentinel());
		printf("\t%s(", IR->callee_name());
		for (auto it = Parameters.begin(); it != Parameters.end(); ++it)
		{
			if (it != Parameters.begin())
			{
				printf(", ");
			}
			printf("%d", *it);
		}
		printf(")\n");

		for (auto it = FunctionCalls.begin(); it != FunctionCalls.end(); ++it)
		{
			auto& FuncCall = it->second;
			if (AreEqual(FuncCall.Parameters, Parameters))
			{
				// TODO: Check for UAV's as their read/writes can't be optimized/reordered!
				if (IR->return_deref)
				{
					ir_variable* ReturnVar = IR->return_deref->variable_referenced();
					LVN[IR] = FuncCall.AssignmentNumber;
					Assignments[ReturnVar].Add(FuncCall.AssignmentNumber);
					printf("\tRED Var %d = FunctionCall %d\n", ReturnVar->id, FuncCall.AssignmentNumber);
				}
				else
				{
					check(0);
				}
				return visit_continue_with_parent;
			}
		}

		SFunctionCall Call;
		Call.AssignmentNumber = SNumber::CreateNumber();
		Call.Parameters = Parameters;

		// TODO: Check for UAV's as their read/writes can't be optimized/reordered!
		if (IR->return_deref)
		{
			ir_variable* ReturnVar = IR->return_deref->variable_referenced();
			Assignments[ReturnVar].Add(Call.AssignmentNumber);
			printf("\tVar %d = FunctionCall %d\n", ReturnVar->id, Call.AssignmentNumber);
		}
		else
		{
			printf("\tFunctionCall %d\n", Call.AssignmentNumber.Number);
		}

		FunctionCalls[IR] = Call;
		LVN[IR] = Call.AssignmentNumber;

		return visit_continue_with_parent;
	}

	virtual ir_visitor_status visit_enter(ir_dereference_record *) override
	{
		return visit_continue_with_parent;
	}

	virtual ir_visitor_status visit_enter(ir_return *) override
	{
		return visit_continue_with_parent;
	}

	virtual ir_visitor_status visit_enter(ir_discard *) override
	{
		return visit_continue_with_parent;
	}

	virtual ir_visitor_status visit_enter(ir_if* IR) override
	{
		IR->condition->accept(this);
		check(ExpressionNumberStack.size() == 1);
		ExpressionNumberStack.pop();
		// Skip Then/Else
		return visit_continue_with_parent;
	}

	virtual ir_visitor_status visit_enter(ir_atomic *) override
	{
		return visit_continue_with_parent;
	}

	virtual ir_visitor_status visit_enter(ir_loop *) override
	{
		return visit_continue_with_parent;
	}

	virtual ir_visitor_status visit_enter(ir_function_signature *) override
	{
		return visit_continue_with_parent;
	}

	virtual ir_visitor_status visit_enter(ir_function *) override
	{
		// Do not step inside, as this was handled as part of a Basic Block
		return visit_continue_with_parent;
	}

	virtual ir_visitor_status visit_leave(ir_swizzle* IR) override
	{
		printf("\tSwizzle @ %d\n", IR->id);
		check(ExpressionNumberStack.size() >= 1);
		auto Operand = ExpressionNumberStack.top();
		ExpressionNumberStack.pop();

		for (auto it = SwizzleVars.begin(); it != SwizzleVars.end(); ++it)
		{
			auto* Swizzle = it->first;
			auto SwizzleOperand = it->second;
			if (SwizzleOperand == Operand && !memcmp(&Swizzle->mask, &IR->mask, sizeof(IR->mask)))
			{
				auto SwizzleNumber = LVN[Swizzle];
				printf("\t\tRED %d\n", SwizzleNumber.Number);
				LVN[IR] = SwizzleNumber;
				ExpressionNumberStack.push(SwizzleNumber);
				return visit_continue;
			}
		}

		auto Number = SNumber::CreateNumber();
		printf("\t\tNEW %d\n", Number.Number);
		LVN[IR] = Number;
		SwizzleVars[IR] = Operand;
		ExpressionNumberStack.push(Number);
		return visit_continue;
	}

	virtual ir_visitor_status visit_enter(ir_texture* IR) override
	{
		printf("\tTex @ %d\n", IR->id);

		TNumberVector Operands;
#define PROCESS_ENTRY(x) if (x) { auto n = ExpressionNumberStack.size(); x->accept(this); Operands.Add(ExpressionNumberStack.top()); ExpressionNumberStack.pop(); check(n == ExpressionNumberStack.size()); }
		PROCESS_ENTRY(IR->sampler);
		PROCESS_ENTRY(IR->coordinate);
		PROCESS_ENTRY(IR->projector);
		PROCESS_ENTRY(IR->shadow_comparitor);
		PROCESS_ENTRY(IR->offset);
		PROCESS_ENTRY(IR->lod_info.grad.dPdy);
		PROCESS_ENTRY(IR->lod_info.grad.dPdx);
		PROCESS_ENTRY(IR->SamplerState);
#undef PROCESS_ENTRY
		int NumOperands = Operands.Num();
		for (auto it = Textures.begin(); it != Textures.end(); ++it)
		{
			auto* Tex = it->first;
			if (Tex->op == IR->op && Tex->channel == IR->channel)
			{
				auto& TexOps = it->second;
				if (NumOperands == TexOps.Num())
				{
					if (AreEqual(TexOps, Operands))
					{
						auto TexNumber = LVN[Tex];
						LVN[IR] = TexNumber;
						Textures[IR] = Operands;
						ExpressionNumberStack.push(TexNumber);
						printf("\t\tRED %d\n", TexNumber.Number);
						return visit_continue_with_parent;
					}
				}
			}
		}

		auto Number = SNumber::CreateNumber();
		printf("\t\tNEW %d\n", Number.Number);
		LVN[IR] = Number;
		Exchange(Textures[IR], Operands);
		ExpressionNumberStack.push(Number);
		return visit_continue_with_parent;
	}

	virtual ir_visitor_status visit_leave(ir_expression* IR) override
	{
		printf("\tExpr @ %d\n", IR->id);
		int NumOperands = IR->get_num_operands();
		check(ExpressionNumberStack.size() >= NumOperands);

		TNumberVector Operands;
		for (int i = 0; i < NumOperands; ++i)
		{
			Operands.Add(ExpressionNumberStack.top());
			ExpressionNumberStack.pop();
		}
		std::reverse(Operands.begin(), Operands.end());

		printf("\t\top %s: ", IR->operator_string());
		for (int i = 0; i < NumOperands; ++i)
		{
			printf(" %d", Operands[i]);
		}
		printf("\n");

		for (auto& Pair : Expressions)
		{
			auto* Expr = Pair.first;
			if (Expr->operation == IR->operation)
			{
				auto& ExprOperands = Pair.second;
				check(ExprOperands.Num() == NumOperands);
				if (AreEqual(ExprOperands, Operands))
				{
					auto ExprNumber = LVN[Expr];
					LVN[IR] = ExprNumber;
					Expressions[IR] = Operands;
					ExpressionNumberStack.push(ExprNumber);
					printf("\t\tRED %d\n", ExprNumber.Number);
					return visit_continue;
				}
			}
		}

		auto Number = SNumber::CreateNumber();
		printf("\t\tNEW %d\n", Number.Number);
		LVN[IR] = Number;
		Expressions[IR] = Operands;
		ExpressionNumberStack.push(Number);

		return visit_continue;
	}

	virtual ir_visitor_status visit_enter(ir_assignment* IR) override
	{
		printf("* Assignment @ %d (stack size %d)\n", IR->id, ExpressionNumberStack.size());

		// Handle LHS
		printf("\tLHS\n");
		check(!bInLHS);
		bInLHS = true;
		ir_variable* LHSVar = IR->lhs->variable_referenced();
		check(LHSVar);
		bInLHS = false;

		printf("\tRHS\n");
		// Handle RHS
		auto StatusRHS = IR->rhs->accept(this);
		check(StatusRHS == visit_continue);
		check(!ExpressionNumberStack.empty());
		auto RHSNumber = ExpressionNumberStack.top();
		ExpressionNumberStack.pop();
		check(ExpressionNumberStack.empty());

		if (!IR->whole_variable_written())
		{
			// Currently we only support full masked writes
			RHSNumber.bPartialWrite = true;
		}
		Assignments[LHSVar].Add(RHSNumber);
		printf("\tVar %d, Expr %d %s\n", LHSVar->id, RHSNumber.Number, RHSNumber.bPartialWrite ? "SWIZZLE" : "");
		LVN[IR->rhs] = RHSNumber;

		return visit_continue_with_parent;
	}

	bool OptimizeRedundantExpressions(SBasicBlock* BasicBlock, TLVNVisitors& Visitors)
	{
		std::map<SNumber, SLVNRedundancyInfo> NumRedundancies;
		for (auto it = LVN.begin(); it != LVN.end(); ++it)
		{
			auto Num = it->second;
			// No need to increase redundancies on Vars or Constants
			auto* RValue = it->first;
			if (!RValue->as_constant() && !RValue->as_variable() && !RValue->as_swizzle())
			{
				if (!Num.bPartialWrite)
				{
					if (RValue->as_texture())
					{
						NumRedundancies[Num].NumRedundancies++;
						printf("+++ @ RValueIR @%d: Redundancy %d: %d\n", RValue->id, Num.Number, NumRedundancies[Num].NumRedundancies);
					}
				}
			}
		}

		printf("****************** LVN for BB %d (%d - %d)\n", BasicBlock->id, BasicBlock->IRFirst->id, BasicBlock->IRLast->id);
		SLVNOptimizeRedundant Visitor(ParseState, LVN, NumRedundancies);
		VisitRange(&Visitor, BasicBlock->IRFirst, BasicBlock->IRLast, true);
		return Visitor.bChanged;
	}

	static void RunPerBasicBlock(SBasicBlock* BB, SCFG* CFG, void* Data)
	{
		printf("----------- BB %d\n", BB->id);
		auto* LVNVisitorList = (TLVNVisitors*)Data;
		// Deleted looping through map later on
		auto* Visitor = new SLVNVisitor(CFG->ParseState);
		VisitRange(Visitor, BB->IRFirst, BB->IRLast);
		(*LVNVisitorList)[BB] = Visitor;
	}
};

struct SCFGCreator
{
	SCFG& CFG;
	TBasicBlockList& BasicBlocks;
	SCFGCreator(SCFG& InCFG) : CFG(InCFG), BasicBlocks(InCFG.BasicBlocks) {}

	static void CreateBasicBlocks(ir_instruction* IRFirst, ir_instruction* IRLast, void* Data)
	{
		SCFGCreator* CFGCreator = (SCFGCreator*)Data;
		// Deleted in ~SCFG()
		auto* BasicBlock = new SBasicBlock(IRFirst, IRLast);
		CFGCreator->/*CFG->*/BasicBlocks.push_back(BasicBlock);
	}

	void LinkBBs(SBasicBlock* Prev, SBasicBlock* Next)
	{
		Next->Predecessors.push_back(Prev);
		Prev->Successors.push_back(Next);
	}

	void LinkBBs(SBasicBlock* Prev, TBasicBlockList::iterator& Next)
	{
		if (Next != BasicBlocks.end())
		{
			LinkBBs(Prev, *Next);
		}
	}

	void LinkBBs(TBasicBlockList::iterator& Prev, TBasicBlockList::iterator& Next)
	{
		if (Prev != BasicBlocks.end() && Next != BasicBlocks.end())
		{
			LinkBBs(*Prev, *Next);
		}
	}

	TBasicBlockList::iterator FindBasicBlock(ir_instruction* IR)
	{
		if (IR)
		{
			for (auto it = BasicBlocks.begin(); it != BasicBlocks.end(); ++it)
			{
				auto* Block = *it;
				if (Block->IRFirst == IR)
				{
					return it;
				}
			}
		}

		return BasicBlocks.end();
	}

	TBasicBlockList::iterator FindBasicBlock(exec_list& List)
	{
		auto* IR = (ir_instruction*)List.get_head();
		return FindBasicBlock(IR);
	}

	void LinkBasicBlocks(TBasicBlockList::iterator& It)
	{
		check(It != BasicBlocks.end());
		auto* BasicBlock = *It;
		auto* IRLast = (*It)->IRLast;
		auto* IRIf = IRLast->as_if();
		if (IRIf)
		{
			auto ThenIter = FindBasicBlock(IRIf->then_instructions);
			auto ElseIter = FindBasicBlock(IRIf->else_instructions);

			auto* IRAfterElse = (ir_instruction*)IRIf->get_next();
			auto IterAfterElse = FindBasicBlock(IRAfterElse);

			if (ThenIter != BasicBlocks.end() && ElseIter != BasicBlocks.end())
			{
				// Only need to link If to then & else
				LinkBBs(BasicBlock, ThenIter);
				LinkBBs(BasicBlock, ElseIter);
				LinkBBs(ThenIter, IterAfterElse);
				LinkBBs(ElseIter, IterAfterElse);
			}
			else
			{
				if (ThenIter != BasicBlocks.end())
				{
					LinkBBs(BasicBlock, ThenIter);
					LinkBBs(ThenIter, IterAfterElse);
				}
				else if (ElseIter != BasicBlocks.end())
				{
					LinkBBs(BasicBlock, ElseIter);
					LinkBBs(ElseIter, IterAfterElse);
				}

				LinkBBs(BasicBlock, IterAfterElse);
			}
		}
		else if (IRLast->as_loop())
		{
			check(0);
		}
		else if (IRLast->as_call())
		{
			++It;
			if (It != BasicBlocks.end())
			{
				auto* NextBB = *It;
				LinkBBs(BasicBlock, NextBB);
				LinkBasicBlocks(It);
			}
		}
		else if (IRLast->as_function() || IRLast->as_return() || IRLast->as_loop() || IRLast->as_loop())
		{
			// TODO
			check(0);
		}
		else
		{
			check(IRLast->as_assignment());
		}
	}

	void TrimOrphanBBs()
	{
		TBasicBlockList NewList;
		for (auto it = BasicBlocks.begin(); it != BasicBlocks.end(); ++it)
		{
			auto* BB = *it;
			if (!BB->Predecessors.empty() || !BB->Successors.empty())
			{
				NewList.push_back(BB);
			}
		}

		BasicBlocks.swap(NewList);
	}

	void Dump()
	{
		printf("------------\n");
		for (auto it = BasicBlocks.begin(); it != BasicBlocks.end(); ++it)
		{
			auto* BB = *it;
			printf("*** Basic Block %d @ %d - %d\n", BB->id, BB->IRFirst->id, BB->IRLast->id);
			printf("\tPRED:");
			for (auto j = BB->Predecessors.begin(); j != BB->Predecessors.end(); ++j)
			{
				auto* Pred = *j;
				printf(" %d", Pred->id);
			}
			printf("\n\tSUCC:");
			for (auto j = BB->Successors.begin(); j != BB->Successors.end(); ++j)
			{
				auto* Pred = *j;
				printf(" %d", Pred->id);
			}
			printf("\n");
		}
	}

	void MergeSingleBasicBlocks()
	{
		bool bChangesMade = false;
		do
		{
			bChangesMade = false;
			TBasicBlockList NewList;
			for (auto it = BasicBlocks.begin(); it != BasicBlocks.end(); ++it)
			{
				auto* BB = *it;
				bool bDoAdd = true;
				if (BB->Predecessors.size() == 1)
				{
					SBasicBlock* Pred = BB->Predecessors.front();
					if (Pred->Successors.size() == 1)
					{
						printf("\tMerging BB %d and BB %d\n", Pred->id, BB->id);

						// Modify Pred to include this instructions and remove this link
						Pred->IRLast = BB->IRLast;
						Pred->Successors.remove(BB);

						// Move all successors to be Pred's successors and update their Predecessors
						for (auto j = BB->Successors.begin(); j != BB->Successors.end(); ++j)
						{
							auto* Succ = *j;
							Succ->Predecessors.remove(BB);
							LinkBBs(Pred, Succ);
							bChangesMade = true;
						}
						bDoAdd = false;
					}
				}

				if (bDoAdd)
				{
					NewList.push_back(BB);
				}
			}

			BasicBlocks = NewList;
		}
		while (bChangesMade);
	}

	void Construct(exec_list* Instructions)
	{
		call_for_basic_blocks(Instructions, &CreateBasicBlocks, this);
		TBasicBlockList::iterator It = BasicBlocks.begin();
		LinkBasicBlocks(It);
//Dump();
		MergeSingleBasicBlocks();
//Dump();
//		TrimOrphanBBs();
//		Dump();
	}
};

bool LocalValueNumbering(exec_list* Instructions, _mesa_glsl_parse_state* ParseState)
{
//IRDump(Instructions);
	// Create initial CFG & Basic Blocks
	SCFG CFG(ParseState);
	SCFGCreator CFGCreator(CFG);
	CFGCreator.Construct(Instructions);

	// Perform Local Value Numbering per Basic Block
	TLVNVisitors LVNVisitors;
	CFG.CallPerBasicBlock(&SLVNVisitor::RunPerBasicBlock, &LVNVisitors);

	for (auto it = LVNVisitors.begin(); it != LVNVisitors.end(); ++it)
	{
		auto* BB = it->first;
		auto* Visitor = it->second;
		CFG.bChanged |= Visitor->OptimizeRedundantExpressions(BB, LVNVisitors);
	}

	{
		for (auto& Pair : LVNVisitors)
		{
			delete Pair.second;
		}
	}

//IRDump(Instructions);
	return CFG.bChanged;
}

struct SExpandSubexpressionsVisitor : public ir_rvalue_visitor
{
	_mesa_glsl_parse_state* ParseState;
	int ExpressionDepth;
	SExpandSubexpressionsVisitor(_mesa_glsl_parse_state* InParseState) : ParseState(InParseState), ExpressionDepth(0) {}

	virtual void handle_rvalue(ir_rvalue** RValuePtr) override
	{
		if (RValuePtr && *RValuePtr)
		{
			auto* Expression = (*RValuePtr)->as_expression();
			if (Expression && Expression->get_num_operands() > 1)
			{
				auto* NewVar = new(ParseState) ir_variable(Expression->type, nullptr, ir_var_temporary);
				auto* NewAssignment = new(ParseState) ir_assignment(new(ParseState) ir_dereference_variable(NewVar), Expression);
				base_ir->insert_before(NewVar);
				base_ir->insert_before(NewAssignment);
				*RValuePtr = new(ParseState) ir_dereference_variable(NewVar);
			}
		}
	}

	virtual ir_visitor_status visit_enter(ir_expression* IR) override
	{
		++ExpressionDepth;
		return ir_rvalue_visitor::visit_enter(IR);
	}

	virtual ir_visitor_status visit_leave(ir_expression* IR) override
	{
		--ExpressionDepth;
		return ir_rvalue_visitor::visit_leave(IR);
	}
};

bool ExpandSubexpressions( exec_list* Instructions, _mesa_glsl_parse_state* ParseState )
{
//IRDump(Instructions);
	SExpandSubexpressionsVisitor Visitor(ParseState);
	Visitor.run(Instructions);
//IRDump(Instructions);
	return true;
}


text:
/*
  popover like tooltip
  configuration

  $scope.config={
   position:'bottom',  //set the position
   onHover:false,      //show on mouse hover
   arrow:true,          //show arrow
   outsideClose:true,   // allow click to close anywhere within document
   delay:500,           // delay
   width:'300',         //set the element width
   cssClass:'popup',    //added container class
   closeBtn:{icon:'close'}, //allowed close button
   template:"popover.tpl.html",  //set template url
   data:{                   //define data object
     "id":<your_id>,
     "title":"<your_title> ",
     "text":"<content_text>"
   }
*/
//define module

var app=angular.module('popoverTooltip', []);

app.directive('popover', function($timeout,$compile,$document){
  return{
     transclude: false,
    scope:
    {
    popover:'=',
    },
    ristrict:"A",

    link: function(scope,element, attrs,$log)
    {

      var config=scope.popover;
      var position,arrow,width, close, delay;
      if(config.delay)
      {
        delay=config.delay;
      }
      else{
        delay=500;
      }

      $timeout(function(){
      if(config.position)
      {
        position=config.position;
      }
      if(config.arrow==true)
      {
        arrow='arrow';
      }
      if(config.width)
      {
        width='width:'+config.width+'px;';
      }
      else {
        $log.info('width is not define');
      }

      if(config.closeBtn){
        close='<md-icon ng-click="close()">'+config.closeBtn.icon+'</md-icon>';
      }
      else {
        close='';
      }

      var w=element[0].offsetWidth/2;
      var w1=element.prop('offsetLeft');
      var left=(w1-5)-((config.width/2)-w);

      var height=element.prop('clientHeight');
      var top=(element.prop('offsetTop')+height)+5;
      var style='height:'+height+'px;top:'+top+'px;left:'+left+'px;' +width + 'position:absolute';

      var template = '<md-popover style="'+style+'" class="md-popover '+config.cssClass + ' '+ position + ' '+ arrow +'">'+close+'<md-popover-content popover-content='+config.template +'></md-popover-content></md-popover>';

      var ele_data=$compile(template)(scope);
      $document.find('body').append(ele_data);

      //bind on element
      if(config.onHover==true){

        element.on('mouseover', function(){
          ele_data.addClass('active');
        });

        element.on('mouseout', function(){
          ele_data.removeClass('active');

        });
      }
      else
       {
         element.on('click', function(e){
           e.preventDefault();
           e.stopPropagation();

           ele_data.toggleClass('active');
         });

      }
      if(config.outsideClose==true){
            $document.on('click', function(){
              ele_data.removeClass('active');
            })
      }
      scope.close=function(){
          ele_data.removeClass('active');
      }
    },delay);

    }
  }
})
.directive('popoverContent', function(){
  return{
 templateUrl: function(scope,element)
 {
     var template=element.popoverContent;
     return template;
   },
   link: function(scope,ele){
     ele.on('click', function(e){
       e.preventDefault();
       e.stopPropagation();
     })
   }
  }
});

  app.run(function( $document){
    //css style for popover
    var style="md-popover { display:none; position:absolute;}\
    md-popover.active { display:block;}\
    md-popover.arrow md-card:before\
    {\
        content: '';\
        position: absolute;\
        left: 48%;\
        border-top: 10px rgba(255, 0, 0, 0) solid;\
        border-bottom: 10px #9A9A9A solid;\
        top: -12px;\
        z-index: 1;\
        border-left: 10px rgba(255, 0, 0, 0) solid;\
        border-right: 10px rgba(255, 0, 0, 0) solid;\
    }\
    md-popover md-card\
    {\
      border: 1px #E4E4E4 solid;\
    }\
    md-popover md-icon\
    {\
        position: absolute;\
        right: 10px;\
        top: 11px;\
        font-size: 17px !important;\
        cursor: pointer;\
        height: 17px;\
        width: 17px;\
    }";

  $document.find('body').append('<style>'+style+'</style>');

  })


text:
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <memory>
#include <utility>
#include <vector>

#include "base/callback.h"
#include "base/memory/raw_ptr.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/apps/app_service/app_service_proxy.h"
#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
#include "chrome/browser/web_applications/test/fake_web_app_provider.h"
#include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
#include "chrome/test/base/testing_profile.h"
#include "components/services/app_service/public/cpp/app_types.h"
#include "components/services/app_service/public/cpp/icon_types.h"
#include "components/services/app_service/public/cpp/intent_filter_util.h"
#include "components/services/app_service/public/cpp/intent_test_util.h"
#include "components/services/app_service/public/cpp/intent_util.h"
#include "components/services/app_service/public/cpp/publisher_base.h"
#include "components/services/app_service/public/mojom/types.mojom-shared.h"
#include "components/services/app_service/public/mojom/types.mojom.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/image_skia_rep.h"

#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/common/chrome_features.h"
#endif

// TODO(crbug.com/1253250):  Remove mojom related test cases.

namespace apps {

class AppServiceProxyTest : public testing::Test {
 protected:
  using UniqueReleaser = std::unique_ptr<apps::IconLoader::Releaser>;

  class FakeIconLoader : public apps::IconLoader {
   public:
    void FlushPendingCallbacks() {
      for (auto& callback : pending_callbacks_) {
        auto iv = std::make_unique<IconValue>();
        iv->icon_type = IconType::kUncompressed;
        iv->uncompressed =
            gfx::ImageSkia(gfx::ImageSkiaRep(gfx::Size(1, 1), 1.0f));
        iv->is_placeholder_icon = false;

        std::move(callback).Run(std::move(iv));
        num_inner_finished_callbacks_++;
      }
      pending_callbacks_.clear();
    }

    int NumInnerFinishedCallbacks() { return num_inner_finished_callbacks_; }
    int NumPendingCallbacks() { return pending_callbacks_.size(); }

   private:
    std::unique_ptr<Releaser> LoadIconFromIconKey(
        AppType app_type,
        const std::string& app_id,
        const IconKey& icon_key,
        IconType icon_type,
        int32_t size_hint_in_dip,
        bool allow_placeholder_icon,
        apps::LoadIconCallback callback) override {
      if (icon_type == IconType::kUncompressed) {
        pending_callbacks_.push_back(std::move(callback));
      }
      return nullptr;
    }

    std::unique_ptr<Releaser> LoadIconFromIconKey(
        apps::mojom::AppType app_type,
        const std::string& app_id,
        apps::mojom::IconKeyPtr icon_key,
        apps::mojom::IconType icon_type,
        int32_t size_hint_in_dip,
        bool allow_placeholder_icon,
        apps::mojom::Publisher::LoadIconCallback callback) override {
      if (icon_type == apps::mojom::IconType::kUncompressed) {
        pending_callbacks_.push_back(
            IconValueToMojomIconValueCallback(std::move(callback)));
      }
      return nullptr;
    }

    int num_inner_finished_callbacks_ = 0;
    std::vector<apps::LoadIconCallback> pending_callbacks_;
  };

  void OverrideAppServiceProxyInnerIconLoader(AppServiceProxy* proxy,
                                              apps::IconLoader* icon_loader) {
    proxy->OverrideInnerIconLoaderForTesting(icon_loader);
  }

  int NumOuterFinishedCallbacks() { return num_outer_finished_callbacks_; }

  int num_outer_finished_callbacks_ = 0;

  content::BrowserTaskEnvironment task_environment_;
};

class AppServiceProxyIconTest : public AppServiceProxyTest,
                                public ::testing::WithParamInterface<bool> {
 protected:
  bool IsLoadIconWithoutMojomEnabled() const { return GetParam(); }

  UniqueReleaser LoadIcon(apps::IconLoader* loader, const std::string& app_id) {
    static constexpr int32_t size_hint_in_dip = 1;
    static bool allow_placeholder_icon = false;

    if (IsLoadIconWithoutMojomEnabled()) {
      static constexpr auto app_type = AppType::kWeb;
      static constexpr auto icon_type = IconType::kUncompressed;
      return loader->LoadIcon(
          app_type, app_id, icon_type, size_hint_in_dip, allow_placeholder_icon,
          base::BindOnce([](int* num_callbacks,
                            apps::IconValuePtr icon) { ++(*num_callbacks); },
                         &num_outer_finished_callbacks_));
    } else {
      static constexpr auto app_type = apps::mojom::AppType::kWeb;
      static constexpr auto icon_type = apps::mojom::IconType::kUncompressed;
      return loader->LoadIcon(
          app_type, app_id, icon_type, size_hint_in_dip, allow_placeholder_icon,
          base::BindOnce(
              [](int* num_callbacks, apps::mojom::IconValuePtr icon) {
                ++(*num_callbacks);
              },
              &num_outer_finished_callbacks_));
    }
  }
};

TEST_P(AppServiceProxyIconTest, IconCache) {
  // This is mostly a sanity check. For an isolated, comprehensive unit test of
  // the IconCache code, see icon_cache_unittest.cc.
  //
  // This tests an AppServiceProxy as a 'black box', which uses an
  // IconCache but also other IconLoader filters, such as an IconCoalescer.

  AppServiceProxy proxy(nullptr);
  FakeIconLoader fake;
  OverrideAppServiceProxyInnerIconLoader(&proxy, &fake);

  // The next LoadIcon call should be a cache miss.
  UniqueReleaser c0 = LoadIcon(&proxy, "cromulent");
  EXPECT_EQ(1, fake.NumPendingCallbacks());
  EXPECT_EQ(0, fake.NumInnerFinishedCallbacks());
  EXPECT_EQ(0, NumOuterFinishedCallbacks());

  // After a cache miss, manually trigger the inner callback.
  fake.FlushPendingCallbacks();
  EXPECT_EQ(0, fake.NumPendingCallbacks());
  EXPECT_EQ(1, fake.NumInnerFinishedCallbacks());
  EXPECT_EQ(1, NumOuterFinishedCallbacks());

  // The next LoadIcon call should be a cache hit.
  UniqueReleaser c1 = LoadIcon(&proxy, "cromulent");
  EXPECT_EQ(0, fake.NumPendingCallbacks());
  EXPECT_EQ(1, fake.NumInnerFinishedCallbacks());
  EXPECT_EQ(2, NumOuterFinishedCallbacks());

  // Destroy the IconLoader::Releaser's, clearing the cache.
  c0.reset();
  c1.reset();

  // The next LoadIcon call should be a cache miss.
  UniqueReleaser c2 = LoadIcon(&proxy, "cromulent");
  EXPECT_EQ(1, fake.NumPendingCallbacks());
  EXPECT_EQ(1, fake.NumInnerFinishedCallbacks());
  EXPECT_EQ(2, NumOuterFinishedCallbacks());

  // After a cache miss, manually trigger the inner callback.
  fake.FlushPendingCallbacks();
  EXPECT_EQ(0, fake.NumPendingCallbacks());
  EXPECT_EQ(2, fake.NumInnerFinishedCallbacks());
  EXPECT_EQ(3, NumOuterFinishedCallbacks());
}

TEST_P(AppServiceProxyIconTest, IconCoalescer) {
  // This is mostly a sanity check. For an isolated, comprehensive unit test of
  // the IconCoalescer code, see icon_coalescer_unittest.cc.
  //
  // This tests an AppServiceProxy as a 'black box', which uses an
  // IconCoalescer but also other IconLoader filters, such as an IconCache.

  AppServiceProxy proxy(nullptr);

  FakeIconLoader fake;
  OverrideAppServiceProxyInnerIconLoader(&proxy, &fake);

  // Issue 4 LoadIcon requests, 2 after de-duplication.
  UniqueReleaser a0 = LoadIcon(&proxy, "avocet");
  UniqueReleaser a1 = LoadIcon(&proxy, "avocet");
  UniqueReleaser b2 = LoadIcon(&proxy, "brolga");
  UniqueReleaser a3 = LoadIcon(&proxy, "avocet");
  EXPECT_EQ(2, fake.NumPendingCallbacks());
  EXPECT_EQ(0, fake.NumInnerFinishedCallbacks());
  EXPECT_EQ(0, NumOuterFinishedCallbacks());

  // Resolve their responses.
  fake.FlushPendingCallbacks();
  EXPECT_EQ(0, fake.NumPendingCallbacks());
  EXPECT_EQ(2, fake.NumInnerFinishedCallbacks());
  EXPECT_EQ(4, NumOuterFinishedCallbacks());

  // Issue another request, that triggers neither IconCache nor IconCoalescer.
  UniqueReleaser c4 = LoadIcon(&proxy, "curlew");
  EXPECT_EQ(1, fake.NumPendingCallbacks());
  EXPECT_EQ(2, fake.NumInnerFinishedCallbacks());
  EXPECT_EQ(4, NumOuterFinishedCallbacks());

  // Destroying the IconLoader::Releaser shouldn't affect the fact that there's
  // an in-flight "curlew" request to the FakeIconLoader.
  c4.reset();
  EXPECT_EQ(1, fake.NumPendingCallbacks());
  EXPECT_EQ(2, fake.NumInnerFinishedCallbacks());
  EXPECT_EQ(4, NumOuterFinishedCallbacks());

  // Issuing another "curlew" request should coalesce with the in-flight one.
  UniqueReleaser c5 = LoadIcon(&proxy, "curlew");
  EXPECT_EQ(1, fake.NumPendingCallbacks());
  EXPECT_EQ(2, fake.NumInnerFinishedCallbacks());
  EXPECT_EQ(4, NumOuterFinishedCallbacks());

  // Resolving the in-flight request to the inner IconLoader, |fake|, should
  // resolve the two coalesced requests to the outer IconLoader, |proxy|.
  fake.FlushPendingCallbacks();
  EXPECT_EQ(0, fake.NumPendingCallbacks());
  EXPECT_EQ(3, fake.NumInnerFinishedCallbacks());
  EXPECT_EQ(6, NumOuterFinishedCallbacks());
}

TEST_F(AppServiceProxyTest, ProxyAccessPerProfile) {
  TestingProfile::Builder profile_builder;

  // We expect an App Service in a regular profile.
  auto profile = profile_builder.Build();
  EXPECT_TRUE(apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(
      profile.get()));
  auto* proxy = apps::AppServiceProxyFactory::GetForProfile(profile.get());
  EXPECT_TRUE(proxy);

  // We expect App Service to be unsupported in incognito.
  TestingProfile::Builder incognito_builder;
  auto* incognito_profile = incognito_builder.BuildIncognito(profile.get());
  EXPECT_FALSE(apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(
      incognito_profile));

  // But if it's accidentally called, we expect the same App Service in the
  // incognito profile branched from that regular profile.
  // TODO(https://crbug.com/1122463): this should be nullptr once we address all
  // incognito access to the App Service.
  auto* incognito_proxy =
      apps::AppServiceProxyFactory::GetForProfile(incognito_profile);
  EXPECT_EQ(proxy, incognito_proxy);

  // We expect a different App Service in the Guest Session profile.
  TestingProfile::Builder guest_builder;
  guest_builder.SetGuestSession();
  auto guest_profile = guest_builder.Build();
  EXPECT_TRUE(apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(
      guest_profile.get()));
  auto* guest_proxy =
      apps::AppServiceProxyFactory::GetForProfile(guest_profile.get());
  EXPECT_TRUE(guest_proxy);
  EXPECT_NE(guest_proxy, proxy);
}

// The parameter indicates whether the kAppServiceLoadIconWithoutMojom feature
// is enabled.
INSTANTIATE_TEST_SUITE_P(All,
                         AppServiceProxyIconTest,
                         ::testing::Values(true, false));

#if !BUILDFLAG(IS_CHROMEOS_LACROS)
class AppServiceProxyPreferredAppsTest : public AppServiceProxyTest {
 public:
  void SetUp() override {
    proxy_ = AppServiceProxyFactory::GetForProfile(&profile_);

    auto* const provider = web_app::FakeWebAppProvider::Get(&profile_);
    provider->SkipAwaitingExtensionSystem();
    web_app::test::AwaitStartWebAppProviderAndSubsystems(&profile_);
  }

  AppServiceProxy* proxy() { return proxy_; }

  // Shortcut for adding apps to App Service without going through a real
  // Publisher.
  void OnApps(std::vector<mojom::AppPtr> apps, mojom::AppType type) {
    proxy_->OnApps(std::move(apps), type, /*should_notify_initialized=*/false);
  }

 private:
  TestingProfile profile_;
  raw_ptr<AppServiceProxy> proxy_;
};

TEST_F(AppServiceProxyPreferredAppsTest, UpdatedOnUninstall) {
  constexpr char kTestAppId[] = "foo";
  const GURL kTestUrl = GURL("https://www.example.com/");

  // Install an app and set it as preferred for a URL.
  {
    std::vector<mojom::AppPtr> apps;
    mojom::AppPtr app = PublisherBase::MakeApp(
        mojom::AppType::kWeb, kTestAppId, mojom::Readiness::kReady, "Test App",
        mojom::InstallReason::kUser);
    app->intent_filters.push_back(
        apps_util::CreateIntentFilterForUrlScope(kTestUrl));
    apps.push_back(std::move(app));

    OnApps(std::move(apps), mojom::AppType::kWeb);
    proxy()->AddPreferredApp(kTestAppId, kTestUrl);
    proxy()->FlushMojoCallsForTesting();

    absl::optional<std::string> preferred_app =
        proxy()->PreferredApps().FindPreferredAppForUrl(kTestUrl);
    ASSERT_EQ(kTestAppId, preferred_app);
  }

  // Updating the app should not change its preferred app status.
  {
    std::vector<mojom::AppPtr> apps;
    mojom::AppPtr app = mojom::App::New();
    app->app_type = mojom::AppType::kWeb;
    app->app_id = kTestAppId;
    app->last_launch_time = base::Time();
    apps.push_back(std::move(app));

    OnApps(std::move(apps), mojom::AppType::kWeb);
    proxy()->FlushMojoCallsForTesting();

    absl::optional<std::string> preferred_app =
        proxy()->PreferredApps().FindPreferredAppForUrl(kTestUrl);
    ASSERT_EQ(kTestAppId, preferred_app);
  }

  // Uninstalling the app should remove it from the preferred app list.
  {
    std::vector<mojom::AppPtr> apps;
    mojom::AppPtr app = mojom::App::New();
    app->app_type = mojom::AppType::kWeb;
    app->app_id = kTestAppId;
    app->readiness = mojom::Readiness::kUninstalledByUser;
    apps.push_back(std::move(app));

    OnApps(std::move(apps), mojom::AppType::kWeb);
    proxy()->FlushMojoCallsForTesting();

    absl::optional<std::string> preferred_app =
        proxy()->PreferredApps().FindPreferredAppForUrl(kTestUrl);
    ASSERT_EQ(absl::nullopt, preferred_app);
  }
}

TEST_F(AppServiceProxyPreferredAppsTest, SetPreferredApp) {
  constexpr char kTestAppId1[] = "abc";
  constexpr char kTestAppId2[] = "def";
  const GURL kTestUrl1 = GURL("https://www.foo.com/");
  const GURL kTestUrl2 = GURL("https://www.bar.com/");

  auto url_filter_1 = apps_util::CreateIntentFilterForUrlScope(kTestUrl1);
  auto url_filter_2 = apps_util::CreateIntentFilterForUrlScope(kTestUrl2);
  auto send_filter = apps_util::CreateIntentFilterForSend("image/png");

  std::vector<mojom::AppPtr> apps;
  mojom::AppPtr app1 = PublisherBase::MakeApp(
      mojom::AppType::kWeb, kTestAppId1, mojom::Readiness::kReady, "Test App",
      mojom::InstallReason::kUser);
  app1->intent_filters.push_back(url_filter_1.Clone());
  app1->intent_filters.push_back(url_filter_2.Clone());
  app1->intent_filters.push_back(send_filter.Clone());
  apps.push_back(std::move(app1));

  mojom::AppPtr app2 = PublisherBase::MakeApp(
      mojom::AppType::kWeb, kTestAppId2, mojom::Readiness::kReady, "Test App",
      mojom::InstallReason::kUser);
  app2->intent_filters.push_back(url_filter_1.Clone());
  apps.push_back(std::move(app2));

  OnApps(std::move(apps), mojom::AppType::kWeb);

  // Set app 1 as preferred. Both links should be set as preferred, but the
  // non-link filter is ignored.

  proxy()->SetSupportedLinksPreference(kTestAppId1);
  proxy()->FlushMojoCallsForTesting();

  ASSERT_EQ(kTestAppId1,
            proxy()->PreferredApps().FindPreferredAppForUrl(kTestUrl1));
  ASSERT_EQ(kTestAppId1,
            proxy()->PreferredApps().FindPreferredAppForUrl(kTestUrl2));
  apps::mojom::IntentPtr mime_intent = apps::mojom::Intent::New();
  mime_intent->mime_type = "image/png";
  mime_intent->action = apps_util::kIntentActionSend;
  ASSERT_EQ(absl::nullopt,
            proxy()->PreferredApps().FindPreferredAppForIntent(mime_intent));

  // Set app 2 as preferred. Both of the previous preferences for app 1 should
  // be removed.

  proxy()->SetSupportedLinksPreference(kTestAppId2);
  proxy()->FlushMojoCallsForTesting();

  ASSERT_EQ(kTestAppId2,
            proxy()->PreferredApps().FindPreferredAppForUrl(kTestUrl1));
  ASSERT_EQ(absl::nullopt,
            proxy()->PreferredApps().FindPreferredAppForUrl(kTestUrl2));

  // Remove all supported link preferences for app 2.

  proxy()->RemoveSupportedLinksPreference(kTestAppId2);
  proxy()->FlushMojoCallsForTesting();

  ASSERT_EQ(absl::nullopt,
            proxy()->PreferredApps().FindPreferredAppForUrl(kTestUrl1));
}

// Using AddPreferredApp to set a supported link should enable all supported
// links for that app.
TEST_F(AppServiceProxyPreferredAppsTest, AddPreferredAppForLink) {
  constexpr char kTestAppId[] = "aaa";
  const GURL kTestUrl1 = GURL("https://www.foo.com/");
  const GURL kTestUrl2 = GURL("https://www.bar.com/");
  auto url_filter_1 = apps_util::CreateIntentFilterForUrlScope(kTestUrl1);
  auto url_filter_2 = apps_util::CreateIntentFilterForUrlScope(kTestUrl2);

  std::vector<mojom::AppPtr> apps;
  mojom::AppPtr app1 = PublisherBase::MakeApp(
      mojom::AppType::kWeb, kTestAppId, mojom::Readiness::kReady, "Test App",
      mojom::InstallReason::kUser);
  app1->intent_filters.push_back(url_filter_1.Clone());
  app1->intent_filters.push_back(url_filter_2.Clone());
  apps.push_back(std::move(app1));
  OnApps(std::move(apps), mojom::AppType::kWeb);

  proxy()->AddPreferredApp(kTestAppId, GURL("https://www.foo.com/something/"));
  proxy()->FlushMojoCallsForTesting();

  ASSERT_EQ(kTestAppId,
            proxy()->PreferredApps().FindPreferredAppForUrl(kTestUrl1));
  ASSERT_EQ(kTestAppId,
            proxy()->PreferredApps().FindPreferredAppForUrl(kTestUrl2));
}

TEST_F(AppServiceProxyPreferredAppsTest, AddPreferredAppBrowser) {
  constexpr char kTestAppId1[] = "aaa";
  constexpr char kTestAppId2[] = "bbb";
  const GURL kTestUrl1 = GURL("https://www.foo.com/");
  const GURL kTestUrl2 = GURL("https://www.bar.com/");
  const GURL kTestUrl3 = GURL("https://www.baz.com/");

  auto url_filter_1 = apps_util::CreateIntentFilterForUrlScope(kTestUrl1);
  auto url_filter_2 = apps_util::CreateIntentFilterForUrlScope(kTestUrl2);
  auto url_filter_3 = apps_util::CreateIntentFilterForUrlScope(kTestUrl3);

  std::vector<mojom::AppPtr> apps;
  mojom::AppPtr app1 = PublisherBase::MakeApp(
      mojom::AppType::kWeb, kTestAppId1, mojom::Readiness::kReady, "Test App",
      mojom::InstallReason::kUser);
  app1->intent_filters.push_back(url_filter_1.Clone());
  app1->intent_filters.push_back(url_filter_2.Clone());
  apps.push_back(std::move(app1));

  mojom::AppPtr app2 = PublisherBase::MakeApp(
      mojom::AppType::kWeb, kTestAppId2, mojom::Readiness::kReady, "Test App",
      mojom::InstallReason::kUser);
  app2->intent_filters.push_back(url_filter_3.Clone());
  apps.push_back(std::move(app2));

  OnApps(std::move(apps), mojom::AppType::kWeb);

  proxy()->AddPreferredApp(kTestAppId1, kTestUrl1);
  proxy()->FlushMojoCallsForTesting();

  // Setting "use browser" for a URL currently handled by App 1 should unset
  // both of App 1's links.
  proxy()->AddPreferredApp(apps_util::kUseBrowserForLink, kTestUrl1);
  proxy()->FlushMojoCallsForTesting();

  ASSERT_EQ(apps_util::kUseBrowserForLink,
            proxy()->PreferredApps().FindPreferredAppForUrl(kTestUrl1));
  ASSERT_EQ(absl::nullopt,
            proxy()->PreferredApps().FindPreferredAppForUrl(kTestUrl2));

  proxy()->AddPreferredApp(apps_util::kUseBrowserForLink, kTestUrl3);
  proxy()->FlushMojoCallsForTesting();
  ASSERT_EQ(apps_util::kUseBrowserForLink,
            proxy()->PreferredApps().FindPreferredAppForUrl(kTestUrl3));

  // Changing the setting back from "use browser" to App 1 should only update
  // that "use-browser" setting, settings for other URLs are unchanged.
  proxy()->AddPreferredApp(kTestAppId1, kTestUrl1);
  proxy()->FlushMojoCallsForTesting();
  ASSERT_EQ(apps_util::kUseBrowserForLink,
            proxy()->PreferredApps().FindPreferredAppForUrl(kTestUrl3));
}

#endif  // !BUILDFLAG(IS_CHROMEOS_LACROS)

#if BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(AppServiceProxyTest, LaunchCallback) {
  AppServiceProxy proxy(nullptr);
  bool called_1 = false;
  bool called_2 = false;
  auto instance_id_1 = base::UnguessableToken::Create();
  LaunchResult result_1;
  result_1.instance_id = instance_id_1;
  auto instance_id_2 = base::UnguessableToken::Create();
  LaunchResult result_2;
  result_2.instance_id = instance_id_2;

  // If the instance is not created yet, the callback will be stored.
  proxy.OnLaunched(
      base::BindOnce([](bool* called,
                        apps::LaunchResult&& launch_result) { *called = true; },
                     &called_1),
      std::move(result_1));
  EXPECT_EQ(proxy.callback_list_.size(), 1U);
  EXPECT_FALSE(called_1);

  proxy.OnLaunched(
      base::BindOnce([](bool* called,
                        apps::LaunchResult&& launch_result) { *called = true; },
                     &called_2),
      std::move(result_2));
  EXPECT_EQ(proxy.callback_list_.size(), 2U);
  EXPECT_FALSE(called_2);

  // Once the instance is created, the callback will be called.
  auto delta = std::make_unique<apps::Instance>("abc", instance_id_1, nullptr);
  proxy.InstanceRegistry().OnInstance(std::move(delta));
  EXPECT_EQ(proxy.callback_list_.size(), 1U);
  EXPECT_TRUE(called_1);
  EXPECT_FALSE(called_2);

  // New callback with existing instance will be called immediately.
  called_1 = false;
  proxy.OnLaunched(
      base::BindOnce([](bool* called,
                        apps::LaunchResult&& launch_result) { *called = true; },
                     &called_1),
      std::move(result_1));
  EXPECT_EQ(proxy.callback_list_.size(), 1U);
  EXPECT_TRUE(called_1);
  EXPECT_FALSE(called_2);
}
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
}  // namespace apps