text:
#ifdef CONFIG_EXYNOS_IOMMU_DEBUG
#define DEBUG
#endif

#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/mm.h>
#include <linux/iommu.h>
#include <linux/errno.h>
#include <linux/list.h>
#include <linux/memblock.h>
#include <linux/export.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/pm_domain.h>
#include <linux/notifier.h>

#include <asm/cacheflush.h>
#include <asm/pgtable.h>

/* We does not consider super section mapping (16MB) */
#define SECT_ORDER 20
#define LPAGE_ORDER 16
#define SPAGE_ORDER 12

#define SECT_SIZE (1 << SECT_ORDER)
#define LPAGE_SIZE (1 << LPAGE_ORDER)
#define SPAGE_SIZE (1 << SPAGE_ORDER)

#define SECT_MASK (~(SECT_SIZE - 1))
#define LPAGE_MASK (~(LPAGE_SIZE - 1))
#define SPAGE_MASK (~(SPAGE_SIZE - 1))

#define lv1ent_fault(sent) ((*(sent) == ZERO_LV2LINK) || \
			   ((*(sent) & 3) == 0) || ((*(sent) & 3) == 3))
#define lv1ent_zero(sent) (*(sent) == ZERO_LV2LINK)
#define lv1ent_page_zero(sent) ((*(sent) & 3) == 1)
#define lv1ent_page(sent) ((*(sent) != ZERO_LV2LINK) && \
			  ((*(sent) & 3) == 1))
#define lv1ent_section(sent) ((*(sent) & 3) == 2)

#define lv2ent_fault(pent) ((*(pent) & 3) == 0)
#define lv2ent_small(pent) ((*(pent) & 2) == 2)
#define lv2ent_large(pent) ((*(pent) & 3) == 1)

#define section_phys(sent) (*(sent) & SECT_MASK)
#define section_offs(iova) ((sysmmu_iova_t)(iova) & 0xFFFFF)
#define lpage_phys(pent) (*(pent) & LPAGE_MASK)
#define lpage_offs(iova) ((sysmmu_iova_t)(iova) & 0xFFFF)
#define spage_phys(pent) (*(pent) & SPAGE_MASK)
#define spage_offs(iova) ((sysmmu_iova_t)(iova) & 0xFFF)

#define lv1ent_offset(iova) ((sysmmu_iova_t)(iova) >> SECT_ORDER)
#define lv2ent_offset(iova) (((sysmmu_iova_t)(iova) & 0xFF000) >> SPAGE_ORDER)

#define NUM_LV1ENTRIES 4096
#define NUM_LV2ENTRIES (SECT_SIZE / SPAGE_SIZE)

#define LV2TABLE_SIZE (NUM_LV2ENTRIES * sizeof(sysmmu_pte_t))

#define SPAGES_PER_LPAGE (LPAGE_SIZE / SPAGE_SIZE)

#define lv2table_base(sent) (*(sent) & 0xFFFFFC00)

#define mk_lv1ent_sect(pa) ((pa) | 2)
#define mk_lv1ent_page(pa) ((pa) | 1)
#define mk_lv2ent_lpage(pa) ((pa) | 1)
#define mk_lv2ent_spage(pa) ((pa) | 2)

#define CTRL_ENABLE	0x5
#define CTRL_BLOCK	0x7
#define CTRL_DISABLE	0x0

#define CFG_LRU		0x1
#define CFG_QOS(n)	((n & 0xF) << 7)
#define CFG_MASK	0x0150FFFF /* Selecting bit 0-15, 20, 22 and 24 */
#define CFG_ACGEN	(1 << 24) /* System MMU 3.3 only */
#define CFG_SYSSEL	(1 << 22) /* System MMU 3.2 only */
#define CFG_FLPDCACHE	(1 << 20) /* System MMU 3.2+ only */

#define REG_MMU_CTRL		0x000
#define REG_MMU_CFG		0x004
#define REG_MMU_STATUS		0x008
#define REG_MMU_FLUSH		0x00C
#define REG_MMU_FLUSH_ENTRY	0x010
#define REG_PT_BASE_ADDR	0x014
#define REG_INT_STATUS		0x018
#define REG_INT_CLEAR		0x01C

#define REG_PAGE_FAULT_ADDR	0x024
#define REG_AW_FAULT_ADDR	0x028
#define REG_AR_FAULT_ADDR	0x02C
#define REG_DEFAULT_SLAVE_ADDR	0x030

#define REG_MMU_VERSION		0x034

#define MMU_MAJ_VER(val)	((val) >> 7)
#define MMU_MIN_VER(val)	((val) & 0x7F)
#define MMU_RAW_VER(reg)	(((reg) >> 21) & ((1 << 11) - 1)) /* 11 bits */

#define MAKE_MMU_VER(maj, min)	((((maj) & 0xF) << 7) | ((min) & 0x7F))

#define REG_PB0_SADDR		0x04C
#define REG_PB0_EADDR		0x050
#define REG_PB1_SADDR		0x054
#define REG_PB1_EADDR		0x058

#define __clk_gate_ctrl(data, clk, en)	do {		\
		if (data->clk)				\
			clk_##en##able(data->clk);	\
	} while (0)

#define __sysmmu_clk_enable(data)	__clk_gate_ctrl(data, clk, en)
#define __sysmmu_clk_disable(data)	__clk_gate_ctrl(data, clk, dis)
#define __master_clk_enable(data)	__clk_gate_ctrl(data, clk_master, en)
#define __master_clk_disable(data)	__clk_gate_ctrl(data, clk_master, dis)

#define has_sysmmu(dev)		(dev->archdata.iommu != NULL)
#define for_each_sysmmu_list(dev, list_data)				\
	list_for_each_entry(list_data,					\
		&((struct exynos_iommu_owner *)dev->archdata.iommu)->mmu_list, \
		entry)

typedef u32 sysmmu_iova_t;
typedef u32 sysmmu_pte_t;

static struct kmem_cache *lv2table_kmem_cache;
static sysmmu_pte_t *zero_lv2_table;
#define ZERO_LV2LINK mk_lv1ent_page(virt_to_phys(zero_lv2_table))

static sysmmu_pte_t *section_entry(sysmmu_pte_t *pgtable, sysmmu_iova_t iova)
{
	return pgtable + lv1ent_offset(iova);
}

static sysmmu_pte_t *page_entry(sysmmu_pte_t *sent, sysmmu_iova_t iova)
{
	return (sysmmu_pte_t *)phys_to_virt(
				lv2table_base(sent)) + lv2ent_offset(iova);
}

enum exynos_sysmmu_inttype {
	SYSMMU_PAGEFAULT,
	SYSMMU_AR_MULTIHIT,
	SYSMMU_AW_MULTIHIT,
	SYSMMU_BUSERROR,
	SYSMMU_AR_SECURITY,
	SYSMMU_AR_ACCESS,
	SYSMMU_AW_SECURITY,
	SYSMMU_AW_PROTECTION, /* 7 */
	SYSMMU_FAULT_UNKNOWN,
	SYSMMU_FAULTS_NUM
};

static unsigned short fault_reg_offset[SYSMMU_FAULTS_NUM] = {
	REG_PAGE_FAULT_ADDR,
	REG_AR_FAULT_ADDR,
	REG_AW_FAULT_ADDR,
	REG_DEFAULT_SLAVE_ADDR,
	REG_AR_FAULT_ADDR,
	REG_AR_FAULT_ADDR,
	REG_AW_FAULT_ADDR,
	REG_AW_FAULT_ADDR
};

static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = {
	"PAGE FAULT",
	"AR MULTI-HIT FAULT",
	"AW MULTI-HIT FAULT",
	"BUS ERROR",
	"AR SECURITY PROTECTION FAULT",
	"AR ACCESS PROTECTION FAULT",
	"AW SECURITY PROTECTION FAULT",
	"AW ACCESS PROTECTION FAULT",
	"UNKNOWN FAULT"
};

/* attached to dev.archdata.iommu of the master device */
struct exynos_iommu_owner {
	struct list_head client; /* entry of exynos_iommu_domain.clients */
	struct device *dev;
	struct list_head mmu_list;  /* list of sysmmu_list_data.entry */
	struct iommu_domain *domain;
	void *vmm_data;         /* IO virtual memory manager's data */
	spinlock_t lock;        /* Lock to preserve consistency of System MMU */
};

struct exynos_iommu_domain {
	struct list_head clients; /* list of sysmmu_drvdata.node */
	sysmmu_pte_t *pgtable; /* lv1 page table, 16KB */
	short *lv2entcnt; /* free lv2 entry counter for each section */
	spinlock_t lock; /* lock for this structure */
	spinlock_t pgtablelock; /* lock for modifying page table @ pgtable */
};

struct sysmmu_list_data {
	struct list_head entry; /* entry of exynos_iommu_owner.mmu_list */
	struct device *sysmmu;
};

struct sysmmu_drvdata {
	struct device *sysmmu;	/* System MMU's device descriptor */
	struct device *master;	/* Owner of system MMU */
	void __iomem *sfrbase;
	struct clk *clk;
	struct clk *clk_master;
	int activations;
	spinlock_t lock;
	struct iommu_domain *domain;
	bool runtime_active;
	bool suspended;
	phys_addr_t pgtable;
};

static bool set_sysmmu_active(struct sysmmu_drvdata *data)
{
	/* return true if the System MMU was not active previously
	   and it needs to be initialized */
	return ++data->activations == 1;
}

static bool set_sysmmu_inactive(struct sysmmu_drvdata *data)
{
	/* return true if the System MMU is needed to be disabled */
	BUG_ON(data->activations < 1);
	return --data->activations == 0;
}

static bool is_sysmmu_active(struct sysmmu_drvdata *data)
{
	return data->activations > 0;
}

static void sysmmu_unblock(void __iomem *sfrbase)
{
	__raw_writel(CTRL_ENABLE, sfrbase + REG_MMU_CTRL);
}

static unsigned int __raw_sysmmu_version(struct sysmmu_drvdata *data)
{
	return MMU_RAW_VER(__raw_readl(data->sfrbase + REG_MMU_VERSION));
}

static bool sysmmu_block(void __iomem *sfrbase)
{
	int i = 120;

	__raw_writel(CTRL_BLOCK, sfrbase + REG_MMU_CTRL);
	while ((i > 0) && !(__raw_readl(sfrbase + REG_MMU_STATUS) & 1))
		--i;

	if (!(__raw_readl(sfrbase + REG_MMU_STATUS) & 1)) {
		sysmmu_unblock(sfrbase);
		return false;
	}

	return true;
}

static void __sysmmu_tlb_invalidate(void __iomem *sfrbase)
{
	__raw_writel(0x1, sfrbase + REG_MMU_FLUSH);
}

static void __sysmmu_tlb_invalidate_entry(void __iomem *sfrbase,
				sysmmu_iova_t iova, unsigned int num_inv)
{
	unsigned int i;
	for (i = 0; i < num_inv; i++) {
		__raw_writel((iova & SPAGE_MASK) | 1,
				sfrbase + REG_MMU_FLUSH_ENTRY);
		iova += SPAGE_SIZE;
	}
}

static void __sysmmu_set_ptbase(void __iomem *sfrbase,
				       phys_addr_t pgd)
{
	__raw_writel(pgd, sfrbase + REG_PT_BASE_ADDR);

	__sysmmu_tlb_invalidate(sfrbase);
}

static void show_fault_information(const char *name,
		enum exynos_sysmmu_inttype itype,
		phys_addr_t pgtable_base, sysmmu_iova_t fault_addr)
{
	sysmmu_pte_t *ent;

	if ((itype >= SYSMMU_FAULTS_NUM) || (itype < SYSMMU_PAGEFAULT))
		itype = SYSMMU_FAULT_UNKNOWN;

	pr_err("%s occurred at %#x by %s(Page table base: %pa)\n",
		sysmmu_fault_name[itype], fault_addr, name, &pgtable_base);

	ent = section_entry(phys_to_virt(pgtable_base), fault_addr);
	pr_err("\tLv1 entry: %#x\n", *ent);

	if (lv1ent_page(ent)) {
		ent = page_entry(ent, fault_addr);
		pr_err("\t Lv2 entry: %#x\n", *ent);
	}
}

static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
{
	/* SYSMMU is in blocked when interrupt occurred. */
	struct sysmmu_drvdata *data = dev_id;
	enum exynos_sysmmu_inttype itype;
	sysmmu_iova_t addr = -1;
	int ret = -ENOSYS;

	WARN_ON(!is_sysmmu_active(data));

	spin_lock(&data->lock);

	__master_clk_enable(data);

	itype = (enum exynos_sysmmu_inttype)
		__ffs(__raw_readl(data->sfrbase + REG_INT_STATUS));
	if (WARN_ON(!((itype >= 0) && (itype < SYSMMU_FAULT_UNKNOWN))))
		itype = SYSMMU_FAULT_UNKNOWN;
	else
		addr = __raw_readl(data->sfrbase + fault_reg_offset[itype]);

	if (itype == SYSMMU_FAULT_UNKNOWN) {
		pr_err("%s: Fault is not occurred by System MMU '%s'!\n",
			__func__, dev_name(data->sysmmu));
		pr_err("%s: Please check if IRQ is correctly configured.\n",
			__func__);
		BUG();
	} else {
		unsigned int base =
				__raw_readl(data->sfrbase + REG_PT_BASE_ADDR);
		show_fault_information(dev_name(data->sysmmu),
					itype, base, addr);
		if (data->domain)
			ret = report_iommu_fault(data->domain,
					data->master, addr, itype);
	}

	/* fault is not recovered by fault handler */
	BUG_ON(ret != 0);

	__raw_writel(1 << itype, data->sfrbase + REG_INT_CLEAR);

	sysmmu_unblock(data->sfrbase);

	__master_clk_disable(data);

	spin_unlock(&data->lock);

	return IRQ_HANDLED;
}

static void __sysmmu_disable_nocount(struct sysmmu_drvdata *data)
{
	clk_enable(data->clk_master);

	__raw_writel(CTRL_DISABLE, data->sfrbase + REG_MMU_CTRL);
	__raw_writel(0, data->sfrbase + REG_MMU_CFG);

	__sysmmu_clk_disable(data);
	__master_clk_disable(data);
}

static bool __sysmmu_disable(struct sysmmu_drvdata *data)
{
	bool disabled;
	unsigned long flags;

	spin_lock_irqsave(&data->lock, flags);

	disabled = set_sysmmu_inactive(data);

	if (disabled) {
		data->pgtable = 0;
		data->domain = NULL;

		if (data->runtime_active)
			__sysmmu_disable_nocount(data);

		dev_dbg(data->sysmmu, "Disabled\n");
	} else  {
		dev_dbg(data->sysmmu, "%d times left to disable\n",
					data->activations);
	}

	spin_unlock_irqrestore(&data->lock, flags);

	return disabled;
}

static void __sysmmu_init_config(struct sysmmu_drvdata *data)
{
	unsigned int cfg = CFG_LRU | CFG_QOS(15);
	unsigned int ver;

	ver = __raw_sysmmu_version(data);
	if (MMU_MAJ_VER(ver) == 3) {
		if (MMU_MIN_VER(ver) >= 2) {
			cfg |= CFG_FLPDCACHE;
			if (MMU_MIN_VER(ver) == 3) {
				cfg |= CFG_ACGEN;
				cfg &= ~CFG_LRU;
			} else {
				cfg |= CFG_SYSSEL;
			}
		}
	}

	__raw_writel(cfg, data->sfrbase + REG_MMU_CFG);
}

static void __sysmmu_enable_nocount(struct sysmmu_drvdata *data)
{
	__master_clk_enable(data);
	__sysmmu_clk_enable(data);

	__raw_writel(CTRL_BLOCK, data->sfrbase + REG_MMU_CTRL);

	__sysmmu_init_config(data);

	__sysmmu_set_ptbase(data->sfrbase, data->pgtable);

	__raw_writel(CTRL_ENABLE, data->sfrbase + REG_MMU_CTRL);

	__master_clk_disable(data);
}

static int __sysmmu_enable(struct sysmmu_drvdata *data,
			phys_addr_t pgtable, struct iommu_domain *domain)
{
	int ret = 0;
	unsigned long flags;

	spin_lock_irqsave(&data->lock, flags);
	if (set_sysmmu_active(data)) {
		data->pgtable = pgtable;
		data->domain = domain;

		if (data->runtime_active)
			__sysmmu_enable_nocount(data);

		dev_dbg(data->sysmmu, "Enabled\n");
	} else {
		ret = (pgtable == data->pgtable) ? 1 : -EBUSY;

		dev_dbg(data->sysmmu, "already enabled\n");
	}

	if (WARN_ON(ret < 0))
		set_sysmmu_inactive(data); /* decrement count */

	spin_unlock_irqrestore(&data->lock, flags);

	return ret;
}

/* __exynos_sysmmu_enable: Enables System MMU
 *
 * returns -error if an error occurred and System MMU is not enabled,
 * 0 if the System MMU has been just enabled and 1 if System MMU was already
 * enabled before.
 */
static int __exynos_sysmmu_enable(struct device *dev, phys_addr_t pgtable,
				  struct iommu_domain *domain)
{
	int ret = 0;
	unsigned long flags;
	struct exynos_iommu_owner *owner = dev->archdata.iommu;
	struct sysmmu_list_data *list;

	BUG_ON(!has_sysmmu(dev));

	spin_lock_irqsave(&owner->lock, flags);

	for_each_sysmmu_list(dev, list) {
		struct sysmmu_drvdata *data = dev_get_drvdata(list->sysmmu);
		data->master = dev;
		ret = __sysmmu_enable(data, pgtable, domain);
		if (ret < 0) {
			struct sysmmu_list_data *iter;
			for_each_sysmmu_list(dev, iter) {
				if (iter->sysmmu == list->sysmmu)
					break;
				data = dev_get_drvdata(iter->sysmmu);
				__sysmmu_disable(data);
				data->master = NULL;
			}
			break;
		}
	}

	spin_unlock_irqrestore(&owner->lock, flags);

	return ret;
}

int exynos_sysmmu_enable(struct device *dev, phys_addr_t pgtable)
{
	BUG_ON(!memblock_is_memory(pgtable));

	return __exynos_sysmmu_enable(dev, pgtable, NULL);
}

static bool exynos_sysmmu_disable(struct device *dev)
{
	unsigned long flags;
	bool disabled = true;
	struct exynos_iommu_owner *owner = dev->archdata.iommu;
	struct sysmmu_list_data *list;

	BUG_ON(!has_sysmmu(dev));

	spin_lock_irqsave(&owner->lock, flags);

	/* Every call to __sysmmu_disable() must return same result */
	for_each_sysmmu_list(dev, list) {
		struct sysmmu_drvdata *data = dev_get_drvdata(list->sysmmu);
		disabled = __sysmmu_disable(data);
		if (disabled)
			data->master = NULL;
	}

	spin_unlock_irqrestore(&owner->lock, flags);

	return disabled;
}

static void __sysmmu_tlb_invalidate_flpdcache(struct sysmmu_drvdata *data,
					      sysmmu_iova_t iova)
{
	if (__raw_sysmmu_version(data) == MAKE_MMU_VER(3, 3))
		__raw_writel(iova | 0x1, data->sfrbase + REG_MMU_FLUSH_ENTRY);
}

static void sysmmu_tlb_invalidate_flpdcache(struct device *dev,
					    sysmmu_iova_t iova)
{
	struct sysmmu_list_data *list;

	for_each_sysmmu_list(dev, list) {
		unsigned long flags;
		struct sysmmu_drvdata *data = dev_get_drvdata(list->sysmmu);

		__master_clk_enable(data);

		spin_lock_irqsave(&data->lock, flags);
		if (is_sysmmu_active(data) && data->runtime_active)
			__sysmmu_tlb_invalidate_flpdcache(data, iova);
		spin_unlock_irqrestore(&data->lock, flags);

		__master_clk_disable(data);
	}
}

static void sysmmu_tlb_invalidate_entry(struct device *dev, sysmmu_iova_t iova,
					size_t size)
{
	struct exynos_iommu_owner *owner = dev->archdata.iommu;
	unsigned long flags;
	struct sysmmu_list_data *list;

	spin_lock_irqsave(&owner->lock, flags);

	for_each_sysmmu_list(dev, list) {
		struct sysmmu_drvdata *data = dev_get_drvdata(list->sysmmu);
		spin_lock(&data->lock);
		if (is_sysmmu_active(data) && data->runtime_active) {
			unsigned int num_inv = 1;

			__master_clk_enable(data);

			/*
			 * L2TLB invalidation required
			 * 4KB page: 1 invalidation
			 * 64KB page: 16 invalidation
			 * 1MB page: 64 invalidation
			 * because it is set-associative TLB
			 * with 8-way and 64 sets.
			 * 1MB page can be cached in one of all sets.
			 * 64KB page can be one of 16 consecutive sets.
			 */
			if (MMU_MAJ_VER(__raw_sysmmu_version(data)) == 2)
				num_inv = min_t(unsigned int,
						size / PAGE_SIZE, 64);

			if (sysmmu_block(data->sfrbase)) {
				__sysmmu_tlb_invalidate_entry(data->sfrbase,
								iova, num_inv);
				sysmmu_unblock(data->sfrbase);
			}
			__master_clk_disable(data);
		} else {
			dev_dbg(dev,
				"disabled. Skipping TLB invalidation @ %#x\n",
				iova);
		}

		spin_unlock(&data->lock);
	}

	spin_unlock_irqrestore(&owner->lock, flags);
}

void exynos_sysmmu_tlb_invalidate(struct device *dev)
{
	struct exynos_iommu_owner *owner = dev->archdata.iommu;
	unsigned long flags;
	struct sysmmu_list_data *list;

	spin_lock_irqsave(&owner->lock, flags);

	for_each_sysmmu_list(dev, list) {
		struct sysmmu_drvdata *data = dev_get_drvdata(list->sysmmu);
		spin_lock(&data->lock);
		if (is_sysmmu_active(data) && data->runtime_active) {
			__master_clk_enable(data);
			if (sysmmu_block(data->sfrbase)) {
				__sysmmu_tlb_invalidate(data->sfrbase);
				sysmmu_unblock(data->sfrbase);
			}
			__master_clk_disable(data);
		} else {
			dev_dbg(dev, "disabled. Skipping TLB invalidation\n");
		}
		spin_unlock(&data->lock);
	}

	spin_unlock_irqrestore(&owner->lock, flags);
}

static int __init __sysmmu_init_clock(struct device *sysmmu,
				      struct sysmmu_drvdata *data)
{
	int ret;

	data->clk = devm_clk_get(sysmmu, "sysmmu");
	if (IS_ERR(data->clk)) {
		if (PTR_ERR(data->clk) == -ENOENT) {
			dev_info(sysmmu, "No gating clock found.\n");
			data->clk = NULL;
			return 0;
		}

		dev_err(sysmmu, "Failed get sysmmu clock\n");
		return PTR_ERR(data->clk);
	}

	ret = clk_prepare(data->clk);
	if (ret) {
		dev_err(sysmmu, "Failed to prepare sysmmu clock\n");
		return ret;
	}

	data->clk_master = devm_clk_get(sysmmu, "master");
	if (PTR_ERR(data->clk_master) == -ENOENT) {
		data->clk_master = NULL;
		return 0;
	} else if (IS_ERR(data->clk_master)) {
		dev_err(sysmmu, "Failed to get master clock\n");
		clk_unprepare(data->clk);
		return PTR_ERR(data->clk_master);
	}

	ret = clk_prepare(data->clk_master);
	if (ret) {
		clk_unprepare(data->clk);
		dev_err(sysmmu, "Failed to prepare master clock\n");
		return ret;
	}

	return 0;
}

static int __init __sysmmu_init_master(struct device *dev)
{
	int ret;
	int i = 0;
	struct device_node *node;

	while ((node = of_parse_phandle(dev->of_node, "mmu-masters", i++))) {
		struct platform_device *master = of_find_device_by_node(node);
		struct exynos_iommu_owner *owner;
		struct sysmmu_list_data *list_data;

		if (!master) {
			dev_err(dev, "%s: mmu-master '%s' not found\n",
				__func__, node->name);
			ret = -EINVAL;
			goto err;
		}

		owner = master->dev.archdata.iommu;
		if (!owner) {
			owner = devm_kzalloc(dev, sizeof(*owner), GFP_KERNEL);
			if (!owner) {
				dev_err(dev,
				"%s: Failed to allocate owner structure\n",
				__func__);
				ret = -ENOMEM;
				goto err;
			}

			INIT_LIST_HEAD(&owner->mmu_list);
			INIT_LIST_HEAD(&owner->client);
			owner->dev = &master->dev;
			spin_lock_init(&owner->lock);

			master->dev.archdata.iommu = owner;
		}

		list_data = devm_kzalloc(dev, sizeof(*list_data), GFP_KERNEL);
		if (!list_data) {
			dev_err(dev,
				"%s: Failed to allocate sysmmu_list_data\n",
				__func__);
			ret = -ENOMEM;
			goto err;
		}

		INIT_LIST_HEAD(&list_data->entry);
		list_data->sysmmu = dev;

		/*
		 * System MMUs are attached in the order of the presence
		 * in device tree
		 */
		list_add_tail(&list_data->entry, &owner->mmu_list);
	}

	return 0;
err:
	while ((node = of_parse_phandle(dev->of_node, "mmu-masters", i++))) {
		struct platform_device *master = of_find_device_by_node(node);
		struct exynos_iommu_owner *owner;
		struct sysmmu_list_data *list_data;

		if (!master)
			continue;

		owner = master->dev.archdata.iommu;
		if (!owner)
			continue;

		for_each_sysmmu_list(owner->dev, list_data) {
			if (list_data->sysmmu == dev) {
				list_del(&list_data->entry);
				kfree(list_data);
				break;
			}
		}
	}

	return ret;
}

static int __init __sysmmu_setup(struct device *sysmmu,
				 struct sysmmu_drvdata *data)
{
	int ret;

	ret = __sysmmu_init_clock(sysmmu, data);
	if (ret) {
		dev_err(sysmmu, "Failed to initialize gating clocks\n");
		return ret;
	}

	ret = __sysmmu_init_master(sysmmu);
	if (ret) {
		if (data->clk)
			clk_unprepare(data->clk);
		if (data->clk_master)
			clk_unprepare(data->clk_master);
		dev_err(sysmmu, "Failed to initialize master device.\n");
	}

	return ret;
}

static int __init exynos_sysmmu_probe(struct platform_device *pdev)
{
	int irq, ret;
	struct device *dev = &pdev->dev;
	struct sysmmu_drvdata *data;
	struct resource *res;

	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
	if (!data) {
		dev_err(dev, "Not enough memory for driver data\n");
		return -ENOMEM;
	}

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(dev, "Unable to find IOMEM region\n");
		return -ENOENT;
	}

	data->sfrbase = devm_request_and_ioremap(dev, res);
	if (!data->sfrbase) {
		dev_err(dev, "Unable to map IOMEM @ PA: %pa\n", &res->start);
		return -EBUSY;
	}

	irq = platform_get_irq(pdev, 0);
	if (irq <= 0) {
		dev_err(dev, "Unable to find IRQ resource\n");
		return irq;
	}

	ret = devm_request_irq(dev, irq, exynos_sysmmu_irq, 0,
				dev_name(dev), data);
	if (ret) {
		dev_err(dev, "Unabled to register handler of irq %d\n", irq);
		return ret;
	}

	pm_runtime_enable(dev);

	ret = __sysmmu_setup(dev, data);
	if (!ret) {
		data->runtime_active = !pm_runtime_enabled(dev);
		data->sysmmu = dev;
		spin_lock_init(&data->lock);

		platform_set_drvdata(pdev, data);
	}

	return ret;
}

#ifdef CONFIG_OF
static struct of_device_id sysmmu_of_match[] __initconst = {
	{ .compatible	= "samsung,sysmmu-v1", },
	{ .compatible	= "samsung,sysmmu-v2", },
	{ .compatible	= "samsung,sysmmu-v3.1", },
	{ .compatible	= "samsung,sysmmu-v3.2", },
	{ .compatible	= "samsung,sysmmu-v3.3", },
	{ },
};
#endif

static struct platform_driver exynos_sysmmu_driver __refdata = {
	.probe	= exynos_sysmmu_probe,
	.driver	= {
		.owner		= THIS_MODULE,
		.name		= "exynos-sysmmu",
		.of_match_table	= of_match_ptr(sysmmu_of_match),
	}
};

static inline void pgtable_flush(void *vastart, void *vaend)
{
	dmac_flush_range(vastart, vaend);
	outer_flush_range(virt_to_phys(vastart),
				virt_to_phys(vaend));
}

static int exynos_iommu_domain_init(struct iommu_domain *domain)
{
	struct exynos_iommu_domain *priv;
	int i;

	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;

	priv->pgtable = (sysmmu_pte_t *)__get_free_pages(GFP_KERNEL, 2);
	if (!priv->pgtable)
		goto err_pgtable;

	priv->lv2entcnt = (short *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 1);
	if (!priv->lv2entcnt)
		goto err_counter;

	/* w/a of System MMU v3.3 to prevent caching 1MiB mapping */
	for (i = 0; i < NUM_LV1ENTRIES; i += 8) {
		priv->pgtable[i + 0] = ZERO_LV2LINK;
		priv->pgtable[i + 1] = ZERO_LV2LINK;
		priv->pgtable[i + 2] = ZERO_LV2LINK;
		priv->pgtable[i + 3] = ZERO_LV2LINK;
		priv->pgtable[i + 4] = ZERO_LV2LINK;
		priv->pgtable[i + 5] = ZERO_LV2LINK;
		priv->pgtable[i + 6] = ZERO_LV2LINK;
		priv->pgtable[i + 7] = ZERO_LV2LINK;
	}

	pgtable_flush(priv->pgtable, priv->pgtable + NUM_LV1ENTRIES);

	spin_lock_init(&priv->lock);
	spin_lock_init(&priv->pgtablelock);
	INIT_LIST_HEAD(&priv->clients);

	domain->geometry.aperture_start = 0;
	domain->geometry.aperture_end   = ~0UL;
	domain->geometry.force_aperture = true;

	domain->priv = priv;
	return 0;

err_counter:
	free_pages((unsigned long)priv->pgtable, 2);
err_pgtable:
	kfree(priv);
	return -ENOMEM;
}

static void exynos_iommu_domain_destroy(struct iommu_domain *domain)
{
	struct exynos_iommu_domain *priv = domain->priv;
	struct exynos_iommu_owner *owner;
	unsigned long flags;
	int i;

	WARN_ON(!list_empty(&priv->clients));

	spin_lock_irqsave(&priv->lock, flags);

	list_for_each_entry(owner, &priv->clients, client) {
		while (!exynos_sysmmu_disable(owner->dev))
			; /* until System MMU is actually disabled */
	}

	while (!list_empty(&priv->clients))
		list_del_init(priv->clients.next);

	spin_unlock_irqrestore(&priv->lock, flags);

	for (i = 0; i < NUM_LV1ENTRIES; i++)
		if (lv1ent_page(priv->pgtable + i))
			kmem_cache_free(lv2table_kmem_cache,
				phys_to_virt(lv2table_base(priv->pgtable + i)));

	free_pages((unsigned long)priv->pgtable, 2);
	free_pages((unsigned long)priv->lv2entcnt, 1);
	kfree(domain->priv);
	domain->priv = NULL;
}

static int exynos_iommu_attach_device(struct iommu_domain *domain,
				   struct device *dev)
{
	struct exynos_iommu_owner *owner = dev->archdata.iommu;
	struct exynos_iommu_domain *priv = domain->priv;
	unsigned long flags;
	phys_addr_t pgtable = virt_to_phys(priv->pgtable);
	int ret;

	spin_lock_irqsave(&priv->lock, flags);

	ret = __exynos_sysmmu_enable(dev, pgtable, domain);
	if (ret == 0) {
		list_add_tail(&owner->client, &priv->clients);
		owner->domain = domain;
	}

	spin_unlock_irqrestore(&priv->lock, flags);

	if (ret < 0) {
		dev_err(dev, "%s: Failed to attach IOMMU with pgtable %pa\n",
				__func__, &pgtable);
		return ret;
	}

	dev_dbg(dev, "%s: Attached IOMMU with pgtable %pa %s\n",
		__func__, &pgtable, (ret == 0) ? "" : ", again");

	return ret;
}

static void exynos_iommu_detach_device(struct iommu_domain *domain,
				    struct device *dev)
{
	struct exynos_iommu_owner *owner;
	struct exynos_iommu_domain *priv = domain->priv;
	unsigned long flags;

	spin_lock_irqsave(&priv->lock, flags);

	list_for_each_entry(owner, &priv->clients, client) {
		if (owner == dev->archdata.iommu) {
			if (exynos_sysmmu_disable(dev)) {
				list_del_init(&owner->client);
				owner->domain = NULL;
			}
			break;
		}
	}

	spin_unlock_irqrestore(&priv->lock, flags);

	if (owner == dev->archdata.iommu) {
		phys_addr_t pgtable = virt_to_phys(priv->pgtable);
		dev_dbg(dev, "%s: Detached IOMMU with pgtable %pa\n",
					__func__, &pgtable);
	} else {
		dev_err(dev, "%s: No IOMMU is attached\n", __func__);
	}
}

static sysmmu_pte_t *alloc_lv2entry(struct exynos_iommu_domain *priv,
		sysmmu_pte_t *sent, sysmmu_iova_t iova, short *pgcounter)
{
	if (lv1ent_section(sent)) {
		WARN(1, "Trying mapping on %#08x mapped with 1MiB page", iova);
		return ERR_PTR(-EADDRINUSE);
	}

	if (lv1ent_fault(sent)) {
		sysmmu_pte_t *pent;
		bool need_flush_flpd_cache = lv1ent_zero(sent);

		pent = kmem_cache_zalloc(lv2table_kmem_cache, GFP_ATOMIC);
		BUG_ON((unsigned int)pent & (LV2TABLE_SIZE - 1));
		if (!pent)
			return ERR_PTR(-ENOMEM);

		*sent = mk_lv1ent_page(virt_to_phys(pent));
		*pgcounter = NUM_LV2ENTRIES;
		pgtable_flush(pent, pent + NUM_LV2ENTRIES);
		pgtable_flush(sent, sent + 1);

		/*
		 * If pretched SLPD is a fault SLPD in zero_l2_table, FLPD cache
		 * may caches the address of zero_l2_table. This function
		 * replaces the zero_l2_table with new L2 page table to write
		 * valid mappings.
		 * Accessing the valid area may cause page fault since FLPD
		 * cache may still caches zero_l2_table for the valid area
		 * instead of new L2 page table that have the mapping
		 * information of the valid area
		 * Thus any replacement of zero_l2_table with other valid L2
		 * page table must involve FLPD cache invalidation for System
		 * MMU v3.3.
		 * FLPD cache invalidation is performed with TLB invalidation
		 * by VPN without blocking. It is safe to invalidate TLB without
		 * blocking because the target address of TLB invalidation is
		 * not currently mapped.
		 */
		if (need_flush_flpd_cache) {
			struct exynos_iommu_owner *owner;
			spin_lock(&priv->lock);
			list_for_each_entry(owner, &priv->clients, client)
				sysmmu_tlb_invalidate_flpdcache(
							owner->dev, iova);
			spin_unlock(&priv->lock);
		}
	}

	return page_entry(sent, iova);
}

static int lv1set_section(struct exynos_iommu_domain *priv,
			  sysmmu_pte_t *sent, sysmmu_iova_t iova,
			  phys_addr_t paddr, short *pgcnt)
{
	if (lv1ent_section(sent)) {
		WARN(1, "Trying mapping on 1MiB@%#08x that is mapped",
			iova);
		return -EADDRINUSE;
	}

	if (lv1ent_page(sent)) {
		if (*pgcnt != NUM_LV2ENTRIES) {
			WARN(1, "Trying mapping on 1MiB@%#08x that is mapped",
				iova);
			return -EADDRINUSE;
		}

		kmem_cache_free(lv2table_kmem_cache, page_entry(sent, 0));
		*pgcnt = 0;
	}

	spin_lock(&priv->lock);
	if (lv1ent_page_zero(sent)) {
		struct exynos_iommu_owner *owner;
		/*
		 * Flushing FLPD cache in System MMU v3.3 that may cache a FLPD
		 * entry by speculative prefetch of SLPD which has no mapping.
		 */
		list_for_each_entry(owner, &priv->clients, client)
			sysmmu_tlb_invalidate_flpdcache(owner->dev, iova);
	}
	spin_unlock(&priv->lock);

	*sent = mk_lv1ent_sect(paddr);

	pgtable_flush(sent, sent + 1);

	return 0;
}

static int lv2set_page(sysmmu_pte_t *pent, phys_addr_t paddr, size_t size,
								short *pgcnt)
{
	if (size == SPAGE_SIZE) {
		if (WARN_ON(!lv2ent_fault(pent)))
			return -EADDRINUSE;

		*pent = mk_lv2ent_spage(paddr);
		pgtable_flush(pent, pent + 1);
		*pgcnt -= 1;
	} else { /* size == LPAGE_SIZE */
		int i;
		for (i = 0; i < SPAGES_PER_LPAGE; i++, pent++) {
			if (WARN_ON(!lv2ent_fault(pent))) {
				if (i > 0)
					memset(pent - i, 0, sizeof(*pent) * i);
				return -EADDRINUSE;
			}

			*pent = mk_lv2ent_lpage(paddr);
		}
		pgtable_flush(pent - SPAGES_PER_LPAGE, pent);
		*pgcnt -= SPAGES_PER_LPAGE;
	}

	return 0;
}

/*
 * *CAUTION* to the I/O virtual memory managers that support exynos-iommu:
 *
 * System MMU v3.x have an advanced logic to improve address translation
 * performance with caching more page table entries by a page table walk.
 * However, the logic has a bug that caching fault page table entries and System
 * MMU reports page fault if the cached fault entry is hit even though the fault
 * entry is updated to a valid entry after the entry is cached.
 * To prevent caching fault page table entries which may be updated to valid
 * entries later, the virtual memory manager should care about the w/a about the
 * problem. The followings describe w/a.
 *
 * Any two consecutive I/O virtual address regions must have a hole of 128KiB
 * in maximum to prevent misbehavior of System MMU 3.x. (w/a of h/w bug)
 *
 * Precisely, any start address of I/O virtual region must be aligned by
 * the following sizes for System MMU v3.1 and v3.2.
 * System MMU v3.1: 128KiB
 * System MMU v3.2: 256KiB
 *
 * Because System MMU v3.3 caches page table entries more aggressively, it needs
 * more w/a.
 * - Any two consecutive I/O virtual regions must be have a hole of larger size
 *   than or equal size to 128KiB.
 * - Start address of an I/O virtual region must be aligned by 128KiB.
 */
static int exynos_iommu_map(struct iommu_domain *domain, unsigned long l_iova,
			 phys_addr_t paddr, size_t size, int prot)
{
	struct exynos_iommu_domain *priv = domain->priv;
	sysmmu_pte_t *entry;
	sysmmu_iova_t iova = (sysmmu_iova_t)l_iova;
	unsigned long flags;
	int ret = -ENOMEM;

	BUG_ON(priv->pgtable == NULL);

	spin_lock_irqsave(&priv->pgtablelock, flags);

	entry = section_entry(priv->pgtable, iova);

	if (size == SECT_SIZE) {
		ret = lv1set_section(priv, entry, iova, paddr,
					&priv->lv2entcnt[lv1ent_offset(iova)]);
	} else {
		sysmmu_pte_t *pent;

		pent = alloc_lv2entry(priv, entry, iova,
					&priv->lv2entcnt[lv1ent_offset(iova)]);

		if (IS_ERR(pent))
			ret = PTR_ERR(pent);
		else
			ret = lv2set_page(pent, paddr, size,
					&priv->lv2entcnt[lv1ent_offset(iova)]);
	}

	if (ret)
		pr_err("%s: Failed(%d) to map %#zx bytes @ %#x\n",
			__func__, ret, size, iova);

	spin_unlock_irqrestore(&priv->pgtablelock, flags);

	return ret;
}

static void exynos_iommu_tlb_invalidate_entry(struct exynos_iommu_domain *priv,
						sysmmu_iova_t iova, size_t size)
{
	struct exynos_iommu_owner *owner;
	unsigned long flags;

	spin_lock_irqsave(&priv->lock, flags);

	list_for_each_entry(owner, &priv->clients, client)
		sysmmu_tlb_invalidate_entry(owner->dev, iova, size);

	spin_unlock_irqrestore(&priv->lock, flags);
}

static size_t exynos_iommu_unmap(struct iommu_domain *domain,
				       unsigned long l_iova, size_t size)
{
	struct exynos_iommu_domain *priv = domain->priv;
	sysmmu_iova_t iova = (sysmmu_iova_t)l_iova;
	sysmmu_pte_t *ent;
	size_t err_pgsize;
	unsigned long flags;

	BUG_ON(priv->pgtable == NULL);

	spin_lock_irqsave(&priv->pgtablelock, flags);

	ent = section_entry(priv->pgtable, iova);

	if (lv1ent_section(ent)) {
		if (WARN_ON(size < SECT_SIZE)) {
			err_pgsize = SECT_SIZE;
			goto err;
		}

		*ent = ZERO_LV2LINK; /* w/a for h/w bug in Sysmem MMU v3.3 */
		pgtable_flush(ent, ent + 1);
		size = SECT_SIZE;
		goto done;
	}

	if (unlikely(lv1ent_fault(ent))) {
		if (size > SECT_SIZE)
			size = SECT_SIZE;
		goto done;
	}

	/* lv1ent_page(sent) == true here */

	ent = page_entry(ent, iova);

	if (unlikely(lv2ent_fault(ent))) {
		size = SPAGE_SIZE;
		goto done;
	}

	if (lv2ent_small(ent)) {
		*ent = 0;
		size = SPAGE_SIZE;
		pgtable_flush(ent, ent + 1);
		priv->lv2entcnt[lv1ent_offset(iova)] += 1;
		goto done;
	}

	/* lv1ent_large(ent) == true here */
	if (WARN_ON(size < LPAGE_SIZE)) {
		err_pgsize = LPAGE_SIZE;
		goto err;
	}

	memset(ent, 0, sizeof(*ent) * SPAGES_PER_LPAGE);
	pgtable_flush(ent, ent + SPAGES_PER_LPAGE);

	size = LPAGE_SIZE;
	priv->lv2entcnt[lv1ent_offset(iova)] += SPAGES_PER_LPAGE;
done:
	spin_unlock_irqrestore(&priv->pgtablelock, flags);

	exynos_iommu_tlb_invalidate_entry(priv, iova, size);

	return size;
err:
	spin_unlock_irqrestore(&priv->pgtablelock, flags);

	pr_err("%s: Failed: size(%#zx) @ %#x is smaller than page size %#zx\n",
		__func__, size, iova, err_pgsize);

	return 0;
}

static phys_addr_t exynos_iommu_iova_to_phys(struct iommu_domain *domain,
					  dma_addr_t iova)
{
	struct exynos_iommu_domain *priv = domain->priv;
	sysmmu_pte_t *entry;
	unsigned long flags;
	phys_addr_t phys = 0;

	spin_lock_irqsave(&priv->pgtablelock, flags);

	entry = section_entry(priv->pgtable, iova);

	if (lv1ent_section(entry)) {
		phys = section_phys(entry) + section_offs(iova);
	} else if (lv1ent_page(entry)) {
		entry = page_entry(entry, iova);

		if (lv2ent_large(entry))
			phys = lpage_phys(entry) + lpage_offs(iova);
		else if (lv2ent_small(entry))
			phys = spage_phys(entry) + spage_offs(iova);
	}

	spin_unlock_irqrestore(&priv->pgtablelock, flags);

	return phys;
}

static int exynos_iommu_add_device(struct device *dev)
{
	struct iommu_group *group;
	int ret;

	group = iommu_group_get(dev);

	if (!group) {
		group = iommu_group_alloc();
		if (IS_ERR(group)) {
			dev_err(dev, "Failed to allocate IOMMU group\n");
			return PTR_ERR(group);
		}
	}

	ret = iommu_group_add_device(group, dev);
	iommu_group_put(group);

	return ret;
}

static void exynos_iommu_remove_device(struct device *dev)
{
	iommu_group_remove_device(dev);
}

static struct iommu_ops exynos_iommu_ops = {
	.domain_init = &exynos_iommu_domain_init,
	.domain_destroy = &exynos_iommu_domain_destroy,
	.attach_dev = &exynos_iommu_attach_device,
	.detach_dev = &exynos_iommu_detach_device,
	.map = &exynos_iommu_map,
	.unmap = &exynos_iommu_unmap,
	.iova_to_phys = &exynos_iommu_iova_to_phys,
	.add_device = &exynos_iommu_add_device,
	.remove_device = &exynos_iommu_remove_device,
	.pgsize_bitmap = SECT_SIZE | LPAGE_SIZE | SPAGE_SIZE,
};

static int __init exynos_iommu_init(void)
{
	int ret;

	lv2table_kmem_cache = kmem_cache_create("exynos-iommu-lv2table",
				LV2TABLE_SIZE, LV2TABLE_SIZE, 0, NULL);
	if (!lv2table_kmem_cache) {
		pr_err("%s: Failed to create kmem cache\n", __func__);
		return -ENOMEM;
	}

	ret = platform_driver_register(&exynos_sysmmu_driver);
	if (ret) {
		pr_err("%s: Failed to register driver\n", __func__);
		goto err_reg_driver;
	}

	zero_lv2_table = kmem_cache_zalloc(lv2table_kmem_cache, GFP_KERNEL);
	if (zero_lv2_table == NULL) {
		pr_err("%s: Failed to allocate zero level2 page table\n",
			__func__);
		ret = -ENOMEM;
		goto err_zero_lv2;
	}

	ret = bus_set_iommu(&platform_bus_type, &exynos_iommu_ops);
	if (ret) {
		pr_err("%s: Failed to register exynos-iommu driver.\n",
								__func__);
		goto err_set_iommu;
	}

	return 0;
err_set_iommu:
	kmem_cache_free(lv2table_kmem_cache, zero_lv2_table);
err_zero_lv2:
	platform_driver_unregister(&exynos_sysmmu_driver);
err_reg_driver:
	kmem_cache_destroy(lv2table_kmem_cache);
	return ret;
}
subsys_initcall(exynos_iommu_init);

#ifdef CONFIG_PM_SLEEP
static int sysmmu_pm_genpd_suspend(struct device *dev)
{
	struct sysmmu_list_data *list;
	int ret;

	ret = pm_generic_suspend(dev);
	if (ret)
		return ret;

	for_each_sysmmu_list(dev, list) {
		struct sysmmu_drvdata *data = dev_get_drvdata(list->sysmmu);
		unsigned long flags;
		spin_lock_irqsave(&data->lock, flags);
		if (!data->suspended && is_sysmmu_active(data) &&
			(!pm_runtime_enabled(dev) || data->runtime_active))
			__sysmmu_disable_nocount(data);
		data->suspended = true;
		spin_unlock_irqrestore(&data->lock, flags);
	}

	return 0;
}

static int sysmmu_pm_genpd_resume(struct device *dev)
{

	struct sysmmu_list_data *list;

	for_each_sysmmu_list(dev, list) {
		struct sysmmu_drvdata *data = dev_get_drvdata(list->sysmmu);
		unsigned long flags;
		spin_lock_irqsave(&data->lock, flags);
		if (data->suspended && is_sysmmu_active(data) &&
			(!pm_runtime_enabled(dev) || data->runtime_active))
			__sysmmu_enable_nocount(data);
		data->suspended = false;
		spin_unlock_irqrestore(&data->lock, flags);
	}

	return pm_generic_resume(dev);
}
#endif

#ifdef CONFIG_PM_RUNTIME
static void sysmmu_restore_state(struct device *dev)
{
	struct sysmmu_list_data *list;

	for_each_sysmmu_list(dev, list) {
		struct sysmmu_drvdata *data = dev_get_drvdata(list->sysmmu);
		unsigned long flags;

		spin_lock_irqsave(&data->lock, flags);
		if (!data->runtime_active && is_sysmmu_active(data))
			__sysmmu_enable_nocount(data);
		data->runtime_active = true;
		spin_unlock_irqrestore(&data->lock, flags);
	}
}

static void sysmmu_save_state(struct device *dev)
{
	struct sysmmu_list_data *list;

	for_each_sysmmu_list(dev, list) {
		struct sysmmu_drvdata *data = dev_get_drvdata(list->sysmmu);
		unsigned long flags;

		spin_lock_irqsave(&data->lock, flags);
		if (data->runtime_active && is_sysmmu_active(data))
			__sysmmu_disable_nocount(data);
		data->runtime_active = false;
		spin_unlock_irqrestore(&data->lock, flags);
	}
}

static int sysmmu_pm_genpd_save_state(struct device *dev)
{
	struct exynos_iommu_client *client = dev->archdata.iommu;
	int (*cb)(struct device *__dev);
	int ret = 0;

	if (dev->type && dev->type->pm)
		cb = dev->type->pm->runtime_suspend;
	else if (dev->class && dev->class->pm)
		cb = dev->class->pm->runtime_suspend;
	else if (dev->bus && dev->bus->pm)
		cb = dev->bus->pm->runtime_suspend;
	else
		cb = NULL;

	if (!cb && dev->driver && dev->driver->pm)
		cb = dev->driver->pm->runtime_suspend;

	if (cb)
		ret = cb(dev);

	if (ret == 0)
		sysmmu_save_state(dev);

	return ret;
}

static int sysmmu_pm_genpd_restore_state(struct device *dev)
{
	struct exynos_iommu_client *client = dev->archdata.iommu;
	int (*cb)(struct device *__dev);
	int ret = 0;

	if (dev->type && dev->type->pm)
		cb = dev->type->pm->runtime_resume;
	else if (dev->class && dev->class->pm)
		cb = dev->class->pm->runtime_resume;
	else if (dev->bus && dev->bus->pm)
		cb = dev->bus->pm->runtime_resume;
	else
		cb = NULL;

	if (!cb && dev->driver && dev->driver->pm)
		cb = dev->driver->pm->runtime_resume;

	sysmmu_restore_state(dev);

	if (cb)
		ret = cb(dev);

	if (ret)
		sysmmu_restore_state(dev);

	return ret;
}
#endif

#ifdef CONFIG_PM_GENERIC_DOMAINS
struct gpd_dev_ops sysmmu_devpm_ops = {
#ifdef CONFIG_PM_RUNTIME
	.save_state = &sysmmu_pm_genpd_save_state,
	.restore_state = &sysmmu_pm_genpd_restore_state,
#endif
#ifdef CONFIG_PM_SLEEP
	.suspend = &sysmmu_pm_genpd_suspend,
	.resume = &sysmmu_pm_genpd_resume,
#endif
};
#endif /* CONFIG_PM_GENERIC_DOMAINS */

static int sysmmu_hook_driver_register(struct notifier_block *nb,
					unsigned long val,
					void *p)
{
	struct device *dev = p;

	/*
	 * No System MMU assigned even though in the initial state.
	 * See exynos_sysmmu_probe().
	 */
	if (dev->archdata.iommu == NULL)
		return 0;

	switch (val) {
	case BUS_NOTIFY_BIND_DRIVER:
	{
		if (IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS) && dev->pm_domain) {
			int ret = pm_genpd_add_callbacks(
					dev, &sysmmu_devpm_ops, NULL);
			if (ret && (ret != -ENOSYS)) {
				dev_err(dev,
				"Failed to register 'dev_pm_ops' for iommu\n");
				return ret;
			}
		}

		break;
	}
	case BUS_NOTIFY_BOUND_DRIVER:
	{
		struct sysmmu_list_data *list;

		/* OK if runtime PM is enabled with genpd for dev */
		if (pm_runtime_enabled(dev) && dev->pm_domain)
			break;

		/*
		 * System MMU will be permanently enabled if the master H/W is
		 * neither registered to a power domain nor runtime PM enabled.
		 */
		for_each_sysmmu_list(dev, list) {
			struct sysmmu_drvdata *data =
					dev_get_drvdata(list->sysmmu);
			unsigned long flags;

			spin_lock_irqsave(&data->lock, flags);
			if (is_sysmmu_active(data) && !data->runtime_active)
				__sysmmu_enable_nocount(data);
			data->runtime_active = true;
			pm_runtime_disable(data->sysmmu);
			spin_unlock_irqrestore(&data->lock, flags);
		}

		break;
	}
	case BUS_NOTIFY_UNBOUND_DRIVER:
	{
		struct exynos_iommu_owner *owner = dev->archdata.iommu;
		if (WARN_ON(!list_empty(&owner->client)))
			iommu_detach_device(owner->domain, dev);
		__pm_genpd_remove_callbacks(dev, false);
		break;
	}
	} /* switch (val) */

	return 0;
}

static struct notifier_block sysmmu_notifier = {
	.notifier_call = &sysmmu_hook_driver_register,
};

static int __init exynos_iommu_prepare(void)
{
	return bus_register_notifier(&platform_bus_type, &sysmmu_notifier);
}
subsys_initcall_sync(exynos_iommu_prepare);


text:
require 'spec_helper'
require 'whois/parsers/whois.tld.ee.rb'

describe Whois::Parsers::WhoisTldEe, "status_registered.expected" do

  subject do
    file = fixture("responses", "whois.tld.ee/ee/status_registered.txt")
    part = Whois::Record::Part.new(body: File.read(file))
    described_class.new(part)
  end

  describe "#disclaimer" do
    it do
      expect(subject.disclaimer).to eq("Estonia .ee Top Level Domain WHOIS server\nMore information at http://internet.ee")
    end
  end
  describe "#domain" do
    it do
      expect(subject.domain).to eq("internet.ee")
    end
  end
  describe "#domain_id" do
    it do
      expect { subject.domain_id }.to raise_error(Whois::AttributeNotSupported)
    end
  end
  describe "#status" do
    it do
      expect(subject.status).to eq(:registered)
    end
  end
  describe "#available?" do
    it do
      expect(subject.available?).to eq(false)
    end
  end
  describe "#registered?" do
    it do
      expect(subject.registered?).to eq(true)
    end
  end
  describe "#created_on" do
    it do
      expect(subject.created_on).to be_a(Time)
      expect(subject.created_on).to eq(Time.parse("2010-08-10 16:43:38 +03:00"))
    end
  end
  describe "#updated_on" do
    it do
      expect(subject.updated_on).to be_a(Time)
      expect(subject.updated_on).to eq(Time.parse("2010-11-29 13:32:16 +02:00"))
    end
  end
  describe "#expires_on" do
    it do
      expect(subject.expires_on).to be_a(Time)
      expect(subject.expires_on).to eq(Time.parse("2017-02-04"))
    end
  end
  describe "#registrar" do
    it do
      expect(subject.registrar).to be_a(Whois::Parser::Registrar)
      expect(subject.registrar.name).to eq("Elisa Eesti AS")
      expect(subject.registrar.organization).to eq("Elisa Eesti AS")
      expect(subject.registrar.url).to eq("http://www.elisa.ee")
    end
  end
  describe "#registrant_contacts" do
    it do
      expect(subject.registrant_contacts).to be_a(Array)
      expect(subject.registrant_contacts.size).to eq(1)
      expect(subject.registrant_contacts[0]).to be_a(Whois::Parser::Contact)
      expect(subject.registrant_contacts[0].type).to eq(Whois::Parser::Contact::TYPE_REGISTRANT)
      expect(subject.registrant_contacts[0].id).to eq(nil)
      expect(subject.registrant_contacts[0].name).to eq("Eesti Interneti Sihtasutus")
      expect(subject.registrant_contacts[0].organization).to eq(nil)
      expect(subject.registrant_contacts[0].address).to eq(nil)
      expect(subject.registrant_contacts[0].city).to eq(nil)
      expect(subject.registrant_contacts[0].zip).to eq(nil)
      expect(subject.registrant_contacts[0].state).to eq(nil)
      expect(subject.registrant_contacts[0].country).to eq(nil)
      expect(subject.registrant_contacts[0].country_code).to eq(nil)
      expect(subject.registrant_contacts[0].phone).to eq(nil)
      expect(subject.registrant_contacts[0].fax).to eq(nil)
      expect(subject.registrant_contacts[0].email).to eq("Not Disclosed - Visit www.internet.ee for webbased WHOIS")
      expect(subject.registrant_contacts[0].created_on).to eq(nil)
      expect(subject.registrant_contacts[0].updated_on).to eq(Time.parse("2010-11-29 13:32:16 +02:00"))
    end
  end
  describe "#admin_contacts" do
    it do
      expect(subject.admin_contacts).to be_a(Array)
      expect(subject.admin_contacts.size).to eq(1)
      expect(subject.admin_contacts[0]).to be_a(Whois::Parser::Contact)
      expect(subject.admin_contacts[0].type).to eq(Whois::Parser::Contact::TYPE_ADMINISTRATIVE)
      expect(subject.admin_contacts[0].id).to eq(nil)
      expect(subject.admin_contacts[0].name).to eq("Jaana Järve")
      expect(subject.admin_contacts[0].organization).to eq(nil)
      expect(subject.admin_contacts[0].address).to eq(nil)
      expect(subject.admin_contacts[0].city).to eq(nil)
      expect(subject.admin_contacts[0].zip).to eq(nil)
      expect(subject.admin_contacts[0].state).to eq(nil)
      expect(subject.admin_contacts[0].country).to eq(nil)
      expect(subject.admin_contacts[0].country_code).to eq(nil)
      expect(subject.admin_contacts[0].phone).to eq(nil)
      expect(subject.admin_contacts[0].fax).to eq(nil)
      expect(subject.admin_contacts[0].email).to eq("Not Disclosed - Visit www.internet.ee for webbased WHOIS")
      expect(subject.admin_contacts[0].created_on).to eq(nil)
      expect(subject.admin_contacts[0].updated_on).to eq(Time.parse("2015-10-30 08:31:21 +02:00"))
    end
  end
  describe "#technical_contacts" do
    it do
      expect(subject.technical_contacts).to be_a(Array)
      expect(subject.technical_contacts.size).to eq(1)
      expect(subject.technical_contacts[0]).to be_a(Whois::Parser::Contact)
      expect(subject.technical_contacts[0].type).to eq(Whois::Parser::Contact::TYPE_TECHNICAL)
      expect(subject.technical_contacts[0].id).to eq(nil)
      expect(subject.technical_contacts[0].name).to eq("Jaana Järve")
      expect(subject.technical_contacts[0].organization).to eq(nil)
      expect(subject.technical_contacts[0].address).to eq(nil)
      expect(subject.technical_contacts[0].city).to eq(nil)
      expect(subject.technical_contacts[0].zip).to eq(nil)
      expect(subject.technical_contacts[0].state).to eq(nil)
      expect(subject.technical_contacts[0].country).to eq(nil)
      expect(subject.technical_contacts[0].country_code).to eq(nil)
      expect(subject.technical_contacts[0].phone).to eq(nil)
      expect(subject.technical_contacts[0].fax).to eq(nil)
      expect(subject.technical_contacts[0].email).to eq("Not Disclosed - Visit www.internet.ee for webbased WHOIS")
      expect(subject.technical_contacts[0].created_on).to eq(nil)
      expect(subject.technical_contacts[0].updated_on).to eq(Time.parse("2015-10-30 08:31:21 +02:00"))
    end
  end
  describe "#nameservers" do
    it do
      expect(subject.nameservers).to be_a(Array)
      expect(subject.nameservers.size).to eq(4)
      expect(subject.nameservers[0]).to be_a(Whois::Parser::Nameserver)
      expect(subject.nameservers[0].name).to eq("c.tld.ee")
      expect(subject.nameservers[0].ipv4).to eq(nil)
      expect(subject.nameservers[0].ipv6).to eq(nil)
      expect(subject.nameservers[1]).to be_a(Whois::Parser::Nameserver)
      expect(subject.nameservers[1].name).to eq("d.tld.ee")
      expect(subject.nameservers[1].ipv4).to eq(nil)
      expect(subject.nameservers[1].ipv6).to eq(nil)
      expect(subject.nameservers[2]).to be_a(Whois::Parser::Nameserver)
      expect(subject.nameservers[2].name).to eq("b.tld.ee")
      expect(subject.nameservers[2].ipv4).to eq(nil)
      expect(subject.nameservers[2].ipv6).to eq(nil)
      expect(subject.nameservers[3]).to be_a(Whois::Parser::Nameserver)
      expect(subject.nameservers[3].name).to eq("e.tld.ee")
      expect(subject.nameservers[3].ipv4).to eq(nil)
      expect(subject.nameservers[3].ipv6).to eq(nil)
    end
  end
end

redpajama_set_name: RedPajamaGithub


text:
@interface MyInfo : NSObject
@property(nonatomic,strong)NSString *city;
@property(nonatomic,strong)NSString *email;
@property(nonatomic,strong)NSString *headphoto;
@property(nonatomic,strong)NSString *uid;
@property(nonatomic,strong)NSString *shen;
@property(nonatomic,strong)NSString *truename;
@end


text:
package kikaha.core.modules.security.login;

import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*;

import java.util.*;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import io.undertow.server.HttpServerExchange;
import kikaha.core.modules.security.*;
import kikaha.core.test.*;
import kikaha.core.util.ChainedMap;
import kikaha.core.util.SystemResource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.*;

/**
 * Unit tests for AuthLoginHttpHandler.
 */
@RunWith( KikahaRunner.class )
public class AuthLoginHttpHandlerTest {

	static final String EXPECTED_PARSED_TEMPLATE = SystemResource.readFileAsString( "expected-parsed-template.html", "UTF-8" );

	@Inject AuthLoginHttpHandler handler;
	@Mock Session currentSession;
	@Mock SecurityContext securityContext;
	HttpServerExchange httpExchange;

	@PostConstruct
	public void loadMocks(){
		MockitoAnnotations.initMocks( this );
		doReturn( currentSession ).when( securityContext ).getCurrentSession();
		httpExchange = HttpServerExchangeStub.createHttpExchange();
		httpExchange.setSecurityContext( securityContext );
		handler.configurationHooks = asList( new CustomConfigurationHook() );
	}

	@Test
	public void ensureCanPreComputeTheLoginHTMLTemplate(){
		final String parsedTemplate = handler.readAndParseTemplate();
		assertEquals( EXPECTED_PARSED_TEMPLATE, parsedTemplate );
	}

	@Test
	public void ensureCanSendLoginPageAsResponse() throws Exception {
		handler.handleRequest( httpExchange );

		verify( currentSession ).setAttribute( eq(CustomConfigurationHook.KEY), eq(CustomConfigurationHook.VALUE) );
		verify( httpExchange.getResponseSender() ).send( eq(handler.getHtml()) );
		assertEquals( 200, httpExchange.getStatusCode() );
	}
}

class CustomConfigurationHook implements AuthLoginHttpHandler.ConfigurationHook {

	final static String KEY = "KEY", VALUE = "VALUE";

	@Override
	public Map<String, Object> getExtraParameters() {
		return ChainedMap.with( KEY, VALUE );
	}

	@Override
	public Map<String, Object> configure( HttpServerExchange exchange, Session session ) {
		session.setAttribute( KEY, VALUE );
		return Collections.emptyMap();
	}
}


text:
using System;
using ServiceStack.DesignPatterns.Model;

namespace ServiceStack.Common.Tests.Models
{
	public class Shipper
		: IHasIntId
	{
		public int Id { get; set; }
		public string CompanyName { get; set; }
		public ShipperType ShipperType { get; set; }
		public DateTime DateCreated { get; set; }
		public Guid UniqueRef { get; set; }

		public override bool Equals(object obj)
		{
			var other = obj as Shipper;
			if (other == null) return false;
			return this.Id == other.Id && this.UniqueRef == other.UniqueRef;
		}

		public override int GetHashCode()
		{
			return string.Concat(Id, UniqueRef).GetHashCode();
		}
	}

	public enum ShipperType
	{
		All = Planes | Trains | Automobiles,
		Unknown = 0,
		Planes = 1,
		Trains = 2,
		Automobiles = 4
	}
}


text:
<?php

/**
 * Stratégie pour l'association vers l'utilisateur
 *
 * PHP version 5.3.3
 *
 * @category Source
 * @package  SuiviProjet\Hydrator\Strategy
 * @author   Adrien Desfourneaux <adrien.desfourneaux@gmail.com>
 * @license  http://opensource.org/licenses/MIT The MIT License
 * @link     https://github.com/adrien-desfourneaux/suivi-projet/tree/master/module/SuiviProjet/src/SuiviProjet/Hydrator/Strategy/UserAssociationStrategy.php
 */

namespace SuiviProjet\Hydrator\Strategy;

use Zend\Stdlib\Hydrator\Strategy\DefaultStrategy;
use Zend\Stdlib\Hydrator\ClassMethods;

/**
 * Stratégie d'hydrateur de conversion d'une entité Doctrine User en array (extraction)
 *
 * @category Source
 * @package  SuiviProjet\Hydrator\Strategy
 * @author   Adrien Desfourneaux <adrien.desfourneaux@gmail.com>
 * @license  http://opensource.org/licenses/MIT The MIT License
 * @link     https://github.com/adrien-desfourneaux/suivi-projet/tree/master/module/SuiviProjet/src/SuiviProjet/Hydrator/Strategy/UserAssociationStrategy.php
 */
class UserAssociationStrategy extends DefaultStrategy
{
    /**
     * Convertit la collection d'entités Doctrine Task en array
     * extract: $object -> array()
     *
     * @param mixed $value Attend une collection d'entités Task
     *
     * @return mixed Renvoie le tableau des extractions
     */
    public function extract($value)
    {
        if (is_object($value)) {
            $hydrator = new ClassMethods();
            $value = $hydrator->extract($value);
        }

        return $value;
    }
}


text:
connect to	Oracle	database on	localhost:1521	with username	dftest	and password	dftest	and database	XE

Stored Procedures

The Execute interpreter can be used similar to the Rule For interpreter to specify behaviour of stored procedures and functions.

execute	procedure		CalcLength

name	str length?

mika	4

paradajz	8

saeiluhrweurhfi7fhi7rhgf	24

Multiple parameters and human-readable names

You can specify multiple parameters, with blanks in names and different letter casing

execute	procedure		ConcatenateStrings

first string	second string	concatenated?

Hello	World	Hello World

Ford	Prefect	Ford Prefect

Special case with no parameters

 If there are no parameters, you don't need to specify the second header row

execute	procedure		MakeUser

set of	query		select * from users

name	username

user1	fromproc

Order of parameters

table parameter order does not have to match database parameter order

execute	procedure		ConcatenateStrings

second string	concatenated?	first string

World	Hello World	Hello

Prefect	Ford Prefect	Ford

IN/OUT params

In/Out parameters of stored procedures should be specified twice. Once for the input and once for the expected output.

execute	procedure		Multiply

n1	n2	?

5	10	50

 Stored functions are treated like procs - just put ? in the result column header

execute	procedure		ConcatenateF

first string	second string	?

Hello	World	Hello World

Ford	Prefect	Ford Prefect

 ? does not have to appear on the end (although it is a good practice to put it there)

execute	procedure		ConcatenateF

second string	?	first string

World	Hello World	Hello

Prefect	Ford Prefect	Ford


text:
<?php
require_once 'lib/Test-More.php';
require_once 'lib/utils.php';
require_once '../inc/config_inc.php';
require_once '../inc/utils.php';

diag('escape_string');

plan(3);

connectDatabase();

$single_quotes_in  = "This isn't cool";
$single_quotes_out = escape_string($single_quotes_in);

is($single_quotes_out, "This isn\'t cool", 'single quotes');

$double_quotes_in  = 'Bob "Babyface" Smith';
$double_quotes_out = escape_string($double_quotes_in);

is($double_quotes_out, 'Bob \"Babyface\" Smith', 'double quotes');

$sql_injection_in  = "SELECT * FROM users WHERE user='aidan' AND password='' OR ''=''";
$sql_injection_out = escape_string($sql_injection_in);

is($sql_injection_out, "SELECT * FROM users WHERE user=\'aidan\' AND password=\'\' OR \'\'=\'\'", 'sql injection quotes');


text:
<?xml version="1.0" encoding="iso-8859-1"?>
<brreg:skjema xmlns:brreg="http://www.brreg.no/or" xmlns:xforms="http://www.w3.org/2002/01/xforms" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <brreg:tittel brreg:lang="NOB">RF-1030-B: Preutfylt selvangivelse - beregningsgrunnlag foreldrefradrag</brreg:tittel>
    <brreg:hode>
        <xforms:model>

            <xforms:schema xlink:href="melding-991-4584.xsd"/>

            <xforms:bind readOnly="true" ref="/Skjema/Foreldrefradrag-grp-4884/OppgavegiverFodselsnummer-datadef-26"/>
            <xforms:bind readOnly="true" ref="/Skjema/Foreldrefradrag-grp-4884/BarnAntallPreutfylt-datadef-22568"/>
        </xforms:model>
    </brreg:hode>
    <brreg:kropp>
        <xforms:group ref="/Skjema">
            <xforms:caption brreg:lang="NOB">

3.2.10 Foreldrefradrag - Beregningsgrunnlag

            </xforms:caption>
            <xforms:caption brreg:lang="NON">

3.2.10 Foreldrefrådrag - Utrekningsgrunnlag

            </xforms:caption>
            <xforms:group ref="/Skjema/Foreldrefradrag-grp-4884">
                <brreg:sensitivitet type="Sensitiv"/>
                <xforms:caption brreg:lang="NOB">

3.2.10 Foreldrefradrag (kostnader til barnehage mv)

                </xforms:caption>
                <xforms:help brreg:lang="NOB">

Har du barn som er 11 år eller yngre (født i 1994 eller senere), kan  du ha krav på foreldrefradrag. Det samme gjelder hvis barnet er 12 år  eller eldre, hvis det har særskilt behov for omsorg og pleie.  Kostnadene reduseres
                        med skattefri stønad til barnetilsyn fra  folketrygden. I enkelte tilfeller må kostnader til pass og stell av  barn dokumenteres. Se rettledningen for mer informasjon. Husk å føre  på navn og fødselsnummer (11 siffer) på
                        dokumentasjonen som skal  sendes inn.

Ektefeller og samboere med felles barn kan til sammen kreve fradrag  for 25 000 kr for ett barn, 30 000 kr for to barn, 35 000 kr for tre  barn og ytterligere 5 000 kr pr barn deretter. Dette gjelder selv om  de også har
                        særkullsbarn.

For samboere (også meldepliktige) som ikke har felles barn, gjelder  maksimumsbeløpet for hver av dem. To samboere som hver har to  særkullsbarn, men uten felles barn, kan altså kreve inntil 30 000 kr  hver i foreldrefradrag.

Forhåndsutfylt beløp er hentet fra årsoppgave fra barnehage, dagmamma  eller skolefritidsordning. Ektefeller og samboere med felles barn kan  selv velge hvordan de vil fordele fradraget mellom seg. Ikke alle  barnehager eller
                        dagmammaer har plikt til å levere oppgaver til  skattemyndighetene. Du må kontrollere og eventuelt føre opp riktig  fradrag.

Det er ikke nødvendig å oppgi noen grunn for endringen i post 5.0  Tilleggsopplysninger.

                </xforms:help>
                <xforms:caption brreg:lang="NON">

3.2.10 Foreldrefrådrag (kostnader til barnehage o.a.)

                </xforms:caption>
                <xforms:help brreg:lang="NON">

Har du barn som er 11 år eller yngre (fødde i 1994 eller seinare), kan  du ha krav på foreldrefrådrag. Det same gjeld viss barnet er over 11  år, viss det har særskilt behov for omsorg og pleie. Kostnadene skal  reduserast med
                        skattefri stønad til barnetilsyn frå folketrygda. I  enkelte tilfelle må kostnader til pass og stell av barn  dokumenterast. Sjå rettleiinga for meir informasjon. Hugs å føre på  namn og fødselsnummer (11 siffer) på
                        dokumentasjonen som skal sendast  inn.

Ektefellar og sambuarar med felles barn kan til saman krevje frådrag  for 25 000 kr for eitt barn, 30 000 kr for to barn, 35 000 kr for tre  barn og 5 000 kr per barn deretter. Dette gjeld sjølv om dei også har  særkullsbarn.

For sambuarar (også meldepliktige) som ikkje har felles barn, gjeld  maksimumsbeløpet for kvar av dei. To sambuarar som kvar har to  særkullsbarn, men ingen felles barn, kan såleis krevje inntil 30 000  kr kvar i
                        foreldrefrådrag.

Førehandsutfylt beløp er henta frå årsoppgåve frå barnehage, dagmamma  eller skulefritidsordning.  Ektefellar og sambuarar med felles barn  kan sjølv velje kven som skal krevje frådraget. Ikkje alle barnehagar  eller dagmammaer
                        har plikt til  å levere oppgåver til skatteetaten.  Du må kontrollere og eventuelt føre opp rett frådrag.

Det er ikkje nødvendig å gi opp nokon grunn for endringa i post 5.0  Tilleggsopplysningar.

                </xforms:help>
                <xforms:input ref="/Skjema/Foreldrefradrag-grp-4884/OppgavegiverFodselsnummer-datadef-26">
                    <brreg:preutfyll/>
                    <brreg:sensitivitet type="Sensitiv"/>
                    <brreg:kontroll type="Modulus 11"/>
                    <xforms:caption brreg:lang="NOB">

Fnr.

                    </xforms:caption>
                    <xforms:alert brreg:lang="NOB">

Ugyldig fødselsnummer

                    </xforms:alert>
                    <xforms:caption brreg:lang="NON">

Fnr.

                    </xforms:caption>
                    <xforms:alert brreg:lang="NON">

Ugyldig fødselsnummer

                    </xforms:alert>
                </xforms:input>
                <xforms:input ref="/Skjema/Foreldrefradrag-grp-4884/BarnAntallPreutfylt-datadef-22568">
                    <brreg:preutfyll/>
                    <brreg:sensitivitet type="Sensitiv"/>
                    <xforms:caption brreg:lang="NOB">

Antall barn under 12 år

                    </xforms:caption>
                    <xforms:caption brreg:lang="NON">

Tal barn under 12 år

                    </xforms:caption>
                </xforms:input>
                <xforms:selectOne ref="/Skjema/Foreldrefradrag-grp-4884/BarnAntall-datadef-21613">
                    <xforms:choices>
                        <xforms:item>
                            <xforms:value>1</xforms:value>
                            <xforms:caption brreg:lang="NOB">

1

                            </xforms:caption>
                        </xforms:item>
                        <xforms:item>
                            <xforms:value>2</xforms:value>
                            <xforms:caption brreg:lang="NOB">

2

                            </xforms:caption>
                        </xforms:item>
                        <xforms:item>
                            <xforms:value>3</xforms:value>
                            <xforms:caption brreg:lang="NOB">

3

                            </xforms:caption>
                        </xforms:item>
                        <xforms:item>
                            <xforms:value>4</xforms:value>
                            <xforms:caption brreg:lang="NOB">

4

                            </xforms:caption>
                        </xforms:item>
                        <xforms:item>
                            <xforms:value>5</xforms:value>
                            <xforms:caption brreg:lang="NOB">

5

                            </xforms:caption>
                        </xforms:item>
                        <xforms:item>
                            <xforms:value>6</xforms:value>
                            <xforms:caption brreg:lang="NOB">

6

                            </xforms:caption>
                        </xforms:item>
                        <xforms:item>
                            <xforms:value>7</xforms:value>
                            <xforms:caption brreg:lang="NOB">

7

                            </xforms:caption>
                        </xforms:item>
                        <xforms:item>
                            <xforms:value>8</xforms:value>
                            <xforms:caption brreg:lang="NOB">

8

                            </xforms:caption>
                        </xforms:item>
                        <xforms:item>
                            <xforms:value>9</xforms:value>
                            <xforms:caption brreg:lang="NOB">

9

                            </xforms:caption>
                        </xforms:item>
                        <xforms:item>
                            <xforms:value>10</xforms:value>
                            <xforms:caption brreg:lang="NOB">

10

                            </xforms:caption>
                        </xforms:item>
                        <xforms:item>
                            <xforms:value>11</xforms:value>
                            <xforms:caption brreg:lang="NOB">

11

                            </xforms:caption>
                        </xforms:item>
                        <xforms:item>
                            <xforms:value>12</xforms:value>
                            <xforms:caption brreg:lang="NOB">

12

                            </xforms:caption>
                        </xforms:item>
                        <xforms:item>
                            <xforms:value>13</xforms:value>
                            <xforms:caption brreg:lang="NOB">

13

                            </xforms:caption>
                        </xforms:item>
                        <xforms:item>
                            <xforms:value>14</xforms:value>
                            <xforms:caption brreg:lang="NOB">

14

                            </xforms:caption>
                        </xforms:item>
                        <xforms:item>
                            <xforms:value>15</xforms:value>
                            <xforms:caption brreg:lang="NOB">

15

                            </xforms:caption>
                        </xforms:item>
                        <xforms:item>
                            <xforms:value>16</xforms:value>
                            <xforms:caption brreg:lang="NOB">

16

                            </xforms:caption>
                        </xforms:item>
                    </xforms:choices>
                    <brreg:preutfyll/>
                    <brreg:sensitivitet type="Sensitiv"/>
                    <xforms:caption brreg:lang="NOB">

Antall barn under 12 år

                    </xforms:caption>
                    <xforms:hint brreg:lang="NOB">

(maks fradrag 25 000 kr)

(maks fradrag 30 000 kr)

                    </xforms:hint>
                    <xforms:caption brreg:lang="NON">

Tal barn under 12 år

                    </xforms:caption>
                    <xforms:hint brreg:lang="NON">

(maks frådrag kr 25 000)

(maks frådrag kr 30 000)

                    </xforms:hint>
                </xforms:selectOne>
                <xforms:repeat id="repeat_Foreldrefradrag-grp-4495" nodeset="/Skjema/Foreldrefradrag-grp-4884/Foreldrefradrag-grp-4495">
                    <xforms:group ref="/Skjema/Foreldrefradrag-grp-4884/Foreldrefradrag-grp-4495">
                        <brreg:sensitivitet type="Sensitiv"/>
                        <xforms:input ref="/Skjema/Foreldrefradrag-grp-4884/Foreldrefradrag-grp-4495/ForeldrefradragBeskrivelse-datadef-14108">
                            <brreg:preutfyll/>
                            <brreg:sensitivitet type="Sensitiv"/>
                            <xforms:caption brreg:lang="NOB">

Betalt til

                            </xforms:caption>
                            <xforms:caption brreg:lang="NON">

Betalt til

                            </xforms:caption>
                        </xforms:input>
                        <xforms:input ref="/Skjema/Foreldrefradrag-grp-4884/Foreldrefradrag-grp-4495/ForeldrefradragBelop-datadef-20993">
                            <brreg:preutfyll/>
                            <brreg:sensitivitet type="Sensitiv"/>
                            <xforms:caption brreg:lang="NOB">

Innbetalt beløp

                            </xforms:caption>
                            <xforms:caption brreg:lang="NON">

Innbetalt beløp

                            </xforms:caption>
                        </xforms:input>
                    </xforms:group>
                </xforms:repeat>
                <xforms:input ref="/Skjema/Foreldrefradrag-grp-4884/ForeldrefradragRedusertStonadTilBarnetilsynPreutfylt-datadef-21368">
                    <brreg:preutfyll/>
                    <brreg:sensitivitet type="Sensitiv"/>
                    <xforms:caption brreg:lang="NOB">

Redusert med stønad til barnetilsyn

                    </xforms:caption>
                    <xforms:caption brreg:lang="NON">

Redusert med stønad til barnetilsyn

                    </xforms:caption>
                </xforms:input>
                <xforms:input ref="/Skjema/Foreldrefradrag-grp-4884/ForeldrefradragSumInnbetalt-datadef-21367">
                    <brreg:preutfyll/>
                    <brreg:sensitivitet type="Sensitiv"/>
                    <xforms:caption brreg:lang="NOB">

Totalt til fradrag

                    </xforms:caption>
                    <xforms:caption brreg:lang="NON">

Totalt til frådrag

                    </xforms:caption>
                </xforms:input>
                <xforms:input ref="/Skjema/Foreldrefradrag-grp-4884/Foreldrefradrag-datadef-2698">
                    <brreg:benevnelse type="kr"/>
                    <brreg:sensitivitet type="Sensitiv"/>
                    <xforms:caption brreg:lang="NOB">

Til fradrag

                    </xforms:caption>
                    <xforms:help brreg:lang="NOB">

Alle kostnader til stell og pass av barn skal fremgå av feltene  Innbetalt beløp.Hvis du tilføyer/endrer innbetalt beløp eller antall  barn, og denne endringen medfører endring av feltet Totalt til  fradrag, vil feltet Til
                            fradrag også bli endret tilsvarende.

For ektefeller skal fradraget i utgangspunktet fordeles med en  halvpart på hver av ektefellene. Hvis det ønskes en annen fordeling  av fradraget mellom ektefeller/samboere, kan du kan endre beløpet i  feltet Til fradrag.
                            Endringer må i så fall gjøres i begges  selvangivelser.

                    </xforms:help>
                    <xforms:hint brreg:lang="NOB">

Eventuelle endringer som påvirker feltet Totalt til fradrag, vil  oppdatere feltet Til fradrag nedenfor.

For ektefeller er beløpet i Totalt til fradrag fordelt mellom  ektefellene. Din del av beløpet står i feltet Til fradrag.

Dersom det ønskes en annen fordeling må begge ektefeller endre beløpet  i Til fradrag. Summen må ikke overstige maksimumsbeløpet.

                    </xforms:hint>
                    <xforms:alert brreg:lang="NOB">

Maksbeløp i denne posten er 30 000 kr. Se ? for ytterligere  informasjon.

                    </xforms:alert>
                    <xforms:caption brreg:lang="NON">

Til frådrag

                    </xforms:caption>
                    <xforms:help brreg:lang="NON">

Alle kostnader til stell og pass av barn skal gå fram av felta  Innbetalt beløp. Viss du legg til/endrar innbetalt beløp eller talet  på barn, og denne endringa medfører endring av feltet Totalt til  frådrag, blir feltet
                            Til frådrag òg endra tilsvarande.

For ektefellar skal frådraget i utgangspunktet fordelast med ein  halvpart på kvar av ektefellane. Viss du ønskjer ei anna fordeling av  frådraget mellom ektefellar/sambuarar, kan du endre beløpet i feltet  Til frådrag.
                            Endringar må i så fall gjerast i sjølvmeldingane til  begge to.

                    </xforms:help>
                    <xforms:hint brreg:lang="NON">

Eventuelle endringar som påverkar feltet Totalt til frådrag,  oppdaterer feltet Til frådrag nedanfor.

For ektefellar er beløpet i Totalt til frådrag fordelt mellom  ektefellane. Din del av beløpet står i feltet Til frådrag.

Dersom de ønskjer ei anna fordeling, må begge ektefellar endre beløpet  i Til frådrag. Summen må ikkje gå over maksimumsbeløpet.

                    </xforms:hint>
                    <xforms:alert brreg:lang="NON">

Maksbeløp i denne posten er 30 000 kr. Sjå ? for meir informasjon.

                    </xforms:alert>
                </xforms:input>
                <xforms:selectOne ref="/Skjema/Foreldrefradrag-grp-4884/ForeldrefradragEndringArsak-datadef-21307">
                    <xforms:choices>
                        <xforms:item>
                            <xforms:value>Overført_til_fra_ektefelle_samboer</xforms:value>
                            <xforms:caption brreg:lang="NOB">

Overført til/fra ektefelle/samboer

                            </xforms:caption>
                            <xforms:caption brreg:lang="NON">

Overført til/frå ektefelle/sambuar

                            </xforms:caption>
                        </xforms:item>
                        <xforms:item>
                            <xforms:value>Manglende_innberetning</xforms:value>
                            <xforms:caption brreg:lang="NOB">

Manglende innberetning

                            </xforms:caption>
                            <xforms:caption brreg:lang="NON">

Manglande innrapportering

                            </xforms:caption>
                        </xforms:item>
                    </xforms:choices>
                    <brreg:sensitivitet type="Sensitiv"/>
                    <xforms:caption brreg:lang="NOB">

Årsak til endring

                    </xforms:caption>
                    <xforms:caption brreg:lang="NON">

Årsak til endring

                    </xforms:caption>
                </xforms:selectOne>
            </xforms:group>
        </xforms:group>
    </brreg:kropp>
</brreg:skjema>


text:
package de.danoeh.antennapod.core.storage;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import de.danoeh.antennapod.model.feed.Chapter;
import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.model.feed.FeedMedia;
import de.danoeh.antennapod.parser.feed.element.SimpleChapter;
import de.danoeh.antennapod.core.util.comparator.FeedItemPubdateComparator;

import static org.junit.Assert.assertTrue;

/**
 * Utility methods for DB* tests.
 */
abstract class DbTestUtils {

    /**
     * Use this method when tests don't involve chapters.
     */
    public static List<Feed> saveFeedlist(int numFeeds, int numItems, boolean withMedia) {
        return saveFeedlist(numFeeds, numItems, withMedia, false, 0);
    }

    /**
     * Use this method when tests involve chapters.
     */
    public static List<Feed> saveFeedlist(int numFeeds, int numItems, boolean withMedia,
                                          boolean withChapters, int numChapters) {
        if (numFeeds <= 0) {
            throw new IllegalArgumentException("numFeeds<=0");
        }
        if (numItems < 0) {
            throw new IllegalArgumentException("numItems<0");
        }

        List<Feed> feeds = new ArrayList<>();
        PodDBAdapter adapter = PodDBAdapter.getInstance();
        adapter.open();
        for (int i = 0; i < numFeeds; i++) {
            Feed f = new Feed(0, null, "feed " + i, "link" + i, "descr", null, null,
                    null, null, "id" + i, null, null, "url" + i, false);
            f.setItems(new ArrayList<>());
            for (int j = 0; j < numItems; j++) {
                FeedItem item = new FeedItem(0, "item " + j, "id" + j, "link" + j, new Date(),
                        FeedItem.PLAYED, f, withChapters);
                if (withMedia) {
                    FeedMedia media = new FeedMedia(item, "url" + j, 1, "audio/mp3");
                    item.setMedia(media);
                }
                if (withChapters) {
                    List<Chapter> chapters = new ArrayList<>();
                    item.setChapters(chapters);
                    for (int k = 0; k < numChapters; k++) {
                        chapters.add(new SimpleChapter(k, "item " + j + " chapter " + k,
                                "http://example.com", "http://example.com/image.png"));
                    }
                }
                f.getItems().add(item);
            }
            Collections.sort(f.getItems(), new FeedItemPubdateComparator());
            adapter.setCompleteFeed(f);
            assertTrue(f.getId() != 0);
            for (FeedItem item : f.getItems()) {
                assertTrue(item.getId() != 0);
            }
            feeds.add(f);
        }
        adapter.close();

        return feeds;
    }
}


text:
<?php

Prado::using('System.Web.UI.ActiveControls.TTriggeredCallback');

/**
 * TEventTriggeredCallback Class
 *
 * Triggers a new callback request when a particular {@link setEventName EventName}
 * on a control with ID given by {@link setControlID ControlID} is raised.
 *
 * The default action of the event on the client-side can be prevented when
 * {@link setPreventDefaultAction PreventDefaultAction} is set to true.
 *
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
 * @version $Id$
 * @package System.Web.UI.ActiveControls
 * @since 3.1
 */
class TEventTriggeredCallback extends TTriggeredCallback
{
	/**
	 * @return string The client-side event name the trigger listens to.
	 */
	public function getEventName()
	{
		return $this->getViewState('EventName', '');
	}

	/**
	 * Sets the client-side event name that fires the callback request.
	 * @param string The client-side event name the trigger listens to.
	 */
	public function setEventName($value)
	{
		$this->setViewState('EventName', $value, '');
	}

	/**
	 * @param boolean true to prevent/stop default event action.
	 */
	public function setPreventDefaultAction($value)
	{
		$this->setViewState('StopEvent', TPropertyValue::ensureBoolean($value), false);
	}

	/**
	 * @return boolean true to prevent/stop default event action.
	 */
	public function getPreventDefaultAction()
	{
		return $this->getViewState('StopEvent', false);
	}

	/**
	 * @return array list of timer options for client-side.
	 */
	protected function getTriggerOptions()
	{
		$options = parent::getTriggerOptions();
		$name = preg_replace('/^on/', '', $this->getEventName());
		$options['EventName'] = strtolower($name);
		$options['StopEvent'] = $this->getPreventDefaultAction();
		return $options;
	}

	/**
	 * Registers the javascript code for initializing the active control.
	 * @param THtmlWriter the renderer.
	 */
	public function render($writer)
	{
		parent::render($writer);
		$this->getActiveControl()->registerCallbackClientScript(
			$this->getClientClassName(), $this->getTriggerOptions());
	}

	/**
	 * @return string corresponding javascript class name for TEventTriggeredCallback.
	 */
	protected function getClientClassName()
	{
		return 'Prado.WebUI.TEventTriggeredCallback';
	}
}


text:
id: vm-runtime
title: MoveVM Runtime
custom_edit_url: https://github.com/diem/diem/edit/main/language/move-binary-format/vm-runtime/README.md
---

# MoveVM Runtime

The MoveVM runtime is the verification and execution engine for the Move
bytecode format. The runtime is imported and loaded in 2 modes:
verification mode (by the [admission control](../../admission_control)
and [mempool](../../mempool) components) and execution mode (by the
[execution](../../execution) component).

## Overview

The MoveVM runtime is a stack machine. The VM runtime receives as input a
*block* which is a list of *transaction scripts* and a *data view*. The
data view is a **read only** snapshot of the data and code in the blockchain at
a given version (i.e., block height). At the time of startup, the runtime
does not have any code or data loaded. It is effectively *"empty"*.

Every transaction executes within the context of a [Diem
account](../diem-framework/modules/diem_account.mvir)---specifically the transaction
submitter's account.  The execution of every transaction consists of three
parts: the account prologue, the transaction itself, and the account
epilogue. This is the only transaction flow known to the runtime, and it is
the only flow the runtime executes. The runtime is responsible to load the
individual transaction from the block and execute the transaction flow:

1. ***Transaction Prologue*** - in verification mode the runtime runs the
   bytecode verifier over the transaction script and executes the
   prologue defined in the [Diem account
   module](../diem-framework/modules/diem_account.mvir). The prologue is responsible
   for checking the structure of the transaction and
   rejecting obviously bad transactions. In verification mode, the runtime
   returns a status of either `success` or `failure` depending upon the
   result of running the prologue. No updates to the blockchain state are
   ever performed by the prologue.
2. ***Transaction Execution*** - in execution mode, and after verification,
   the runtime starts executing transaction-specific/client code.  A typical
   code performs updates to data in the blockchain. Execution of the
   transaction by the VM runtime produces a write set that acts as an
   atomic state change from the current state of the blockchain---received
   via the data view---to a new version that is the result of applying the
   write set.  Importantly, on-chain data is _never_ changed during the
   execution of the transaction. Further, while the write set is produced as the
   result of executing the bytecode, the changes are not applied to the global
   blockchain state by the VM---this is the responsibility of the
   [execution module](../../../execution/).
3. ***Transaction Epilogue*** - in execution mode the epilogue defined in
   the [Diem account module](../diem-framework/modules/diem_account.mvir) is
   executed to perform actions based upon the result of the execution of
   the user-submitted transaction. One example of such an action is
   debiting the gas fee for the transaction from the submitting account's
   balance.

During execution, the runtime resolves references to code by loading the
referenced code via the data view. One can think of this process as similar
to linking. Then, within the context of a block of transactions---a list of
transactions coupled with a data view---the runtime caches code and
linked and imported modules across transactions within the block.
The runtime tracks state changes (data updates) from one transaction
to the next within each block of transactions; the semantics of the
execution of a block specify that transactions are sequentially executed
and, as a consequence, state changes of previous transactions must be
visible to subsequent transactions within each block.

## Implementation Details

* The runtime top level structs are in `runtime` and `diem vm` related
  code.
* The transaction flow is implemented in the [`process_txn`](./src/process_txn.rs)
  module.
* Code caching logic and policies are defined under the [code
  cache](../../move-vm/runtime/src/code_cache/) directory.
* Runtime loaded code and the type system view for the runtime is defined
  under the [loaded data](src/loaded_data/) directory.
* The data representation of values, and logic for write set generation can
  be found under the [value](./src/value.rs) and [data
  cache](./src/data_cache.rs) files.

## Folder Structure

```
.
├── src                 # VM Runtime files
│   ├── code_cache      # VM Runtime code cache
│   ├── loaded_data     # VM Runtime loaded data types, runtime caches over code
│   ├── unit_tests      # unit tests
├── vm-cache-map        # abstractions for the code cache
```

## This Module Interacts With

This crate is mainly used in two parts: AC and mempool use it to determine
if it should accept a transaction or not; the Executor runs the MoveVM
runtime to execute the program field in a SignedTransaction and convert
it into a TransactionOutput, which contains a writeset that the
executor need to patch to the blockchain as a side effect of this
transaction.


text:
package magick

// #include <stdlib.h>
// extern void * gif_encode(void *im, int single, int *size);
// #cgo LDFLAGS: -lgif
import "C"

import (
	"bytes"
	"errors"
	"fmt"
	"os/exec"
	"unsafe"
)

var (
	gifsicleCmd          string
	errNoGifsicle        = errors.New("error decoding GIF image: Corrupt data. Install gifsicle to try to fix it.")
	errCouldNotEncodeGif = errors.New("error encoding GIF")
	maxGifTries          = 1
)

func looksLikeGif(data []byte) bool {
	return bytes.HasPrefix(data, []byte{'G', 'I', 'F'})
}

func runGifsicle(data []byte, args []string) ([]byte, error) {
	cmd := exec.Command(gifsicleCmd, args...)
	cmd.Stdin = bytes.NewReader(data)
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		return nil, fmt.Errorf("error running gifsicle: %s", err)
	}
	return out.Bytes(), nil
}

func fixAndDecodeGif(data []byte, try int) (*Image, error) {
	if gifsicleCmd == "" {
		return nil, errNoGifsicle
	}
	args := []string{"--careful", "--unoptimize", "--colors=256"}
	data, err := runGifsicle(data, args)
	if err != nil {
		return nil, err
	}
	return decodeData(data, try+1)
}

// GifEncode encodes the Image as GIF using giflib
// rather than ImageMagick or GraphicksMagick. While this
// will result in a lower quality GIF, encoding is 9-10x
// faster and produces files ~20% smaller.
func (im *Image) GifEncode() ([]byte, error) {
	if !im.coalesced {
		coalesced, err := im.Coalesce()
		if err != nil {
			return nil, err
		}
		coalesced.parent = im.parent
		defer coalesced.Dispose()
		im = coalesced
	}
	var size C.int
	var single C.int
	if im.parent != nil {
		single = 1
	}
	res := C.gif_encode(unsafe.Pointer(im.image), single, &size)
	if res != nil {
		p := unsafe.Pointer(res)
		b := C.GoBytes(p, size)
		C.free(p)
		return b, nil
	}
	return nil, errCouldNotEncodeGif
}

func init() {
	gifsicleCmd, _ = exec.LookPath("gifsicle")
}


text:
@interface MPAbstractABTestDesignerMessage : NSObject <MPABTestDesignerMessage>

@property (nonatomic, copy, readonly) NSString *type;

+ (instancetype)messageWithType:(NSString *)type payload:(NSDictionary *)payload;

- (instancetype)initWithType:(NSString *)type;
- (instancetype)initWithType:(NSString *)type payload:(NSDictionary *)payload NS_DESIGNATED_INITIALIZER;

- (void)setPayloadObject:(id)object forKey:(NSString *)key;
- (id)payloadObjectForKey:(NSString *)key;
- (NSDictionary *)payload;

- (NSData *)JSONData;

@end


text:
using Newtonsoft.Json;

namespace TMDbLib.Objects.Languages
{
    public class Language
    {
        [JsonProperty("iso_639_1")]
        public string Iso_639_1 { get; set; }

        [JsonProperty("english_name")]
        public string EnglishName { get; set; }

        [JsonProperty("name")]
        public string Name { get; set; }
    }
}


text:
'use strict';
let Joi = require('joi');
let $http = require('http-as-promised');
let _ = require('lodash');
let Promise = require('bluebird');
let request = require('supertest');
let harvester = require('../lib/harvester');

// todo we need a better strategy to stand up test harvesterjs instances
// listening on hard coded free ports and duplicating harvesterjs options is not very robust and DRY

const harvesterOptions = require('./config').harvester.options;

describe('remote link', function() {
  describe(
    "given 2 resources : 'posts', 'people' ; defined on distinct harvesterjs servers " +
      "and posts has a remote link 'author' defined to people",
    function() {
      var app1Port = 8011;
      var app2Port = 8012;
      var app1BaseUrl = 'http://localhost:' + app1Port;
      var app2BaseUrl = 'http://localhost:' + app2Port;

      before(function() {
        var that = this;
        that.timeout(20000);

        that.harvesterApp1 = harvester(harvesterOptions)
          .resource('post', {
            title: Joi.string(),
            links: {
              author: {
                ref: 'person',
                baseUri: 'http://localhost:' + app2Port,
              },
              comments: ['comment'],
              topic: 'topic',
            },
          })
          .resource('topic', {
            name: Joi.string(),
          })
          .resource('comment', {
            body: Joi.string(),
          })
          .listen(app1Port);

        that.harvesterApp2 = harvester(harvesterOptions)
          .resource('person', {
            firstName: Joi.string(),
            lastName: Joi.string(),
            links: {
              country: 'country',
            },
          })
          .resource('country', {
            code: Joi.string(),
          })
          .listen(app2Port);

        // todo move into utility class or upgrade to latest version of mongoose which returns a promise
        function removeCollection(model) {
          return new Promise(function(resolve, reject) {
            model.collection.remove(function(err, result) {
              if (err) {
                reject(err);
              }
              resolve(result);
            });
          });
        }

        return removeCollection(that.harvesterApp1.adapter.model('post'))
          .then(function() {
            return removeCollection(that.harvesterApp2.adapter.model('person'));
          })
          .then(function() {
            // todo come up with a consistent pattern for seeding
            // as far as I can see we are mixing supertest, chai http and http-as-promised
            return $http({
              uri: app2BaseUrl + '/countries',
              method: 'POST',
              json: { countries: [{ code: 'US' }] },
            });
          })
          .spread(function(res, body) {
            that.countryId = body.countries[0].id;
            return $http({
              uri: app2BaseUrl + '/people',
              method: 'POST',
              json: {
                people: [
                  {
                    firstName: 'Tony',
                    lastName: 'Maley',
                    links: { country: that.countryId },
                  },
                ],
              },
            });
          })
          .spread(function(res, body) {
            that.authorId = body.people[0].id;
            return $http({
              uri: app1BaseUrl + '/posts',
              method: 'POST',
              json: {
                posts: [
                  { title: 'Nodejs rules !', links: { author: that.authorId } },
                ],
              },
            });
          })
          .spread(function(res, body) {
            that.postId = body.posts[0].id;
            return $http({
              uri: app1BaseUrl + '/comments',
              method: 'POST',
              json: {
                comments: [{ body: "That's crazy talk, Ruby is the best !" }],
              },
            });
          })
          .spread(function(res, body) {
            that.commentId = body.comments[0].id;
            return $http({
              uri: app1BaseUrl + '/posts/' + that.postId,
              method: 'PUT',
              json: { posts: [{ links: { comments: [that.commentId] } }] },
            });
          });
      });

      describe('fetch posts and include author', function() {
        it('should respond with a compound document with people included', function(
          done
        ) {
          var that = this;
          // todo come up with a consistent pattern for assertions
          request(app1BaseUrl)
            .get('/posts?include=author')
            .expect(200)
            .end(function(error, response) {
              var body = response.body;
              _.pluck(body.linked.people, 'id').should.eql([that.authorId]);
              done();
            });
        });
      });

      describe('fetch posts include author.country', function() {
        it('should respond with a compound document with people and countries included', function(
          done
        ) {
          var that = this;
          // todo come up with a consistent pattern for assertions
          request(app1BaseUrl)
            .get('/posts?include=author.country')
            .expect(200)
            .end(function(error, response) {
              var body = response.body;
              _.pluck(body.linked.people, 'id').should.eql([that.authorId]);
              _.pluck(body.linked.countries, 'id').should.eql([that.countryId]);
              done();
            });
        });
      });

      describe('fetch posts include topic, author, author.country and comments', function() {
        it('should respond with a compound document with people, countries and comments included', function(
          done
        ) {
          var that = this;
          // todo come up with a consistent pattern for assertions
          request(app1BaseUrl)
            .get('/posts?include=topic,comments,author,author.country')
            .expect(200)
            .end(function(error, response) {
              var body = response.body;
              _.pluck(body.linked.people, 'id').should.eql([that.authorId]);
              _.pluck(body.linked.countries, 'id').should.eql([that.countryId]);
              _.pluck(body.linked.comments, 'id').should.eql([that.commentId]);
              done();
            });
        });
      });
    }
  );
});