code:
/*
 * © Copyright 2017 The BiOpenly Community
 *
 * This program is free software and is provided to you under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation, and any use by you of this program is subject to the terms
 * of such GNU license.
 *
 * A copy of the licence is included with the program, and can also be obtained
 * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301, USA.
 *
 */

#ifndef __PANDRIVER_H__
#define __PANDRIVER_H__

#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#ifdef HAVE_USER_H
#include <sys/user.h>
#endif

#include <mali-ioctl.h>
#include <jobs.h>
#include <chai-notes.h>

/* TODO: Find non-hackish memory allocator */

void init_cbma(int fd);
void* galloc(size_t sz);
void gfree(void* ptr);

/* Integer types used in the shim. */

typedef int8_t s8;
typedef int16_t s16;
typedef int32_t s32;
typedef int64_t s64;

typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;

/* We don't have PAGE_SIZE at all, provide our own */
#ifndef PAGE_SIZE
#define PAGE_SHIFT	12
#define PAGE_SIZE 	(1 << PAGE_SHIFT)
#define PAGE_MASK 	(~(PAGE_SIZE - 1))
#else
/* Android bionic doesn't have PAGE_SHIFT, define it using __builtin_ffs() if
 * possible, otherwise fallback to slightly slower stdlib ffs
 */
#ifndef PAGE_SHIFT
#ifdef HAVE_BUILTIN_FFS
#define PAGE_SHIFT (__builtin_ffs(PAGE_SIZE) - 1)
#else
#include <strings.h>
#define PAGE_SHIFT (ffs(PAGE_SIZE) - 1)
#endif /* HAVE_BUILTIN_FFS */
#endif /* PAGE_SHIFT */
#endif /* PAGE_SIZE */

/* Thin wrappers around ioctls */

int open_kernel_module();
uint64_t alloc_gpu_pages(int fd, int pages, int e_flags);
uint64_t alloc_gpu_heap(int fd, int pages);
void free_gpu(int fd, uint64_t addr);
void sync_gpu(int fd, uint8_t* cpu, uint64_t gpu, size_t size);
void submit_job(int fd, struct mali_jd_atom_v2 atom);
void flush_job_queue(int fd);
uint8_t* mmap_gpu(int fd, uint64_t addr, int page_count);
void stream_create(int fd, char *stream);
void query_gpu_props(int fd);

/* Raw command stream generation */

struct job_descriptor_header* set_value_helper(uint64_t out);

uint64_t make_mfbd(bool tiler, uint64_t heap_free_address,
		   uint64_t scratchpad);

uint32_t job_chain_fragment(int fd, uint64_t framebuffer,
			    uint64_t heap_free_address, uint64_t scratchpad);

uint64_t import_shader(int fd, uint8_t *shader, size_t sz, bool frag);
uint32_t upload_vertices(float *vertices, size_t sz);

struct job_descriptor_header* vertex_tiler_helper(int fd, bool tiler,
						  uint32_t fbd,
						  uint32_t vertex_buffer,
						  uint32_t zero_buffer,
						  uint32_t mode,
						  void *shader,
						  size_t shader_size);

uint32_t job_chain_vertex_tiler(int fd, float *vertices, size_t vertex_size,
				int mode,
				void *vertex_shader, size_t vs_sz,
				void *fragment_shader, size_t fs_sz,
				uint64_t heap_free_address,
				uint64_t scratchpad);

void job_chain_replay(int fd, uint32_t tiler_jc, uint32_t fragment_jc,
		      uint64_t heap_free_address, uint64_t framebuffer);

#endif


code:
/*
 * © Copyright 2017 The BiOpenly Community
 *
 * This program is free software and is provided to you under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation, and any use by you of this program is subject to the terms
 * of such GNU licence.
 *
 * A copy of the licence is included with the program, and can also be obtained
 * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301, USA.
 *
 */

/**
 * Miscellanious utilities
 */

#ifndef __PANLOADER_UTIL_H__
#define __PANLOADER_UTIL_H__

#include <inttypes.h>

typedef uint8_t  u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;

typedef int8_t  s8;
typedef int16_t s16;
typedef int32_t s32;
typedef int64_t s64;

#define ASSERT_SIZEOF_TYPE(type__, size__)       \
	_Static_assert(sizeof(type__) == size__, \
                       #type__ " does not match expected size " #size__)

#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

#define YES_NO(b) ((b) ? "Yes" : "No")

#endif /* __PANLOADER_UTIL_H__ */

repo_name: cafe/pantry

license: mit


code:
void *fetch_mapped_gpu(u64 gpu_addr, size_t sz);
void chai_trace_atom(const struct mali_jd_atom_v2 *v);


code:
project(panwrap)

set(SRCS panwrap-syscall.c panwrap-util.c)

add_library(panwrap SHARED ${SRCS})
target_link_libraries(panwrap driver decoder)


code:
/*
 * © Copyright 2017 The BiOpenly Community
 *
 * This program is free software and is provided to you under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation, and any use by you of this program is subject to the terms
 * of such GNU licence.
 *
 * A copy of the licence is included with the program, and can also be obtained
 * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301, USA.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <linux/ioctl.h>
#include <math.h>
#include <sys/mman.h>
#include <stdarg.h>

#include <mali-ioctl.h>
#include <list.h>
#include "panwrap.h"

static pthread_mutex_t l = PTHREAD_MUTEX_INITIALIZER;

#define LOCK()   pthread_mutex_lock(&l)
#define UNLOCK() pthread_mutex_unlock(&l)

#define IOCTL_CASE(request) (_IOWR(_IOC_TYPE(request), _IOC_NR(request), \
				   _IOC_SIZE(request)))

struct ioctl_info {
	const char *name;
};

struct device_info {
	const char *name;
	const struct ioctl_info info[MALI_IOCTL_TYPE_COUNT][_IOC_NR(0xffffffff)];
};

struct allocated_memory {
	u64 gpu_va;
	bool same_va;
	struct list node;
};

struct mapped_memory {
	size_t length;

	void *addr;
	u64 gpu_va;

	struct list node;
};

typedef void* (mmap_func)(void *, size_t, int, int, int, loff_t);
typedef int (open_func)(const char *, int flags, ...);

#define IOCTL_TYPE(type) [type - MALI_IOCTL_TYPE_BASE] =
#define IOCTL_INFO(n) [_IOC_NR(MALI_IOCTL_##n)] = { .name = #n }
static struct device_info mali_info = {
	.name = "mali",
	.info = {
		IOCTL_TYPE(0x80) {
			IOCTL_INFO(GET_VERSION),
		},
		IOCTL_TYPE(0x82) {
			IOCTL_INFO(MEM_ALLOC),
			IOCTL_INFO(MEM_IMPORT),
			IOCTL_INFO(MEM_COMMIT),
			IOCTL_INFO(MEM_QUERY),
			IOCTL_INFO(MEM_FREE),
			IOCTL_INFO(MEM_FLAGS_CHANGE),
			IOCTL_INFO(MEM_ALIAS),
			IOCTL_INFO(SYNC),
			IOCTL_INFO(POST_TERM),
			IOCTL_INFO(HWCNT_SETUP),
			IOCTL_INFO(HWCNT_DUMP),
			IOCTL_INFO(HWCNT_CLEAR),
			IOCTL_INFO(GPU_PROPS_REG_DUMP),
			IOCTL_INFO(FIND_CPU_OFFSET),
			IOCTL_INFO(GET_VERSION_NEW),
			IOCTL_INFO(SET_FLAGS),
			IOCTL_INFO(SET_TEST_DATA),
			IOCTL_INFO(INJECT_ERROR),
			IOCTL_INFO(MODEL_CONTROL),
			IOCTL_INFO(KEEP_GPU_POWERED),
			IOCTL_INFO(FENCE_VALIDATE),
			IOCTL_INFO(STREAM_CREATE),
			IOCTL_INFO(GET_PROFILING_CONTROLS),
			IOCTL_INFO(SET_PROFILING_CONTROLS),
			IOCTL_INFO(DEBUGFS_MEM_PROFILE_ADD),
			IOCTL_INFO(JOB_SUBMIT),
			IOCTL_INFO(DISJOINT_QUERY),
			IOCTL_INFO(GET_CONTEXT_ID),
			IOCTL_INFO(TLSTREAM_ACQUIRE_V10_4),
			IOCTL_INFO(TLSTREAM_TEST),
			IOCTL_INFO(TLSTREAM_STATS),
			IOCTL_INFO(TLSTREAM_FLUSH),
			IOCTL_INFO(HWCNT_READER_SETUP),
			IOCTL_INFO(SET_PRFCNT_VALUES),
			IOCTL_INFO(SOFT_EVENT_UPDATE),
			IOCTL_INFO(MEM_JIT_INIT),
			IOCTL_INFO(TLSTREAM_ACQUIRE),
		},
	},
};
#undef IOCTL_INFO
#undef IOCTL_TYPE

static inline const struct ioctl_info *
ioctl_get_info(unsigned long int request)
{
	return &mali_info.info[_IOC_TYPE(request) - MALI_IOCTL_TYPE_BASE]
	                      [_IOC_NR(request)];
}

static int mali_fd = 0;
static LIST_HEAD(allocations);
static LIST_HEAD(mmaps);

extern FILE *ioctl_fp;

#define FLAG_INFO(flag) { MALI_MEM_##flag, #flag }
static const struct panwrap_flag_info mem_flag_info[] = {
	FLAG_INFO(PROT_CPU_RD),
	FLAG_INFO(PROT_CPU_WR),
	FLAG_INFO(PROT_GPU_RD),
	FLAG_INFO(PROT_GPU_WR),
	FLAG_INFO(PROT_GPU_EX),
	FLAG_INFO(GROW_ON_GPF),
	FLAG_INFO(COHERENT_SYSTEM),
	FLAG_INFO(COHERENT_LOCAL),
	FLAG_INFO(CACHED_CPU),
	FLAG_INFO(SAME_VA),
	FLAG_INFO(NEED_MMAP),
	FLAG_INFO(COHERENT_SYSTEM_REQUIRED),
	FLAG_INFO(SECURE),
	FLAG_INFO(DONT_NEED),
	FLAG_INFO(IMPORT_SHARED),
	{}
};
#undef FLAG_INFO

#define FLAG_INFO(flag) { MALI_JD_REQ_##flag, #flag }
static const struct panwrap_flag_info jd_req_flag_info[] = {
	FLAG_INFO(FS),
	FLAG_INFO(CS),
	FLAG_INFO(T),
	FLAG_INFO(CF),
	FLAG_INFO(V),
	FLAG_INFO(FS_AFBC),
	FLAG_INFO(EVENT_COALESCE),
	FLAG_INFO(COHERENT_GROUP),
	FLAG_INFO(PERMON),
	FLAG_INFO(EXTERNAL_RESOURCES),
	FLAG_INFO(ONLY_COMPUTE),
	FLAG_INFO(SPECIFIC_COHERENT_GROUP),
	FLAG_INFO(EVENT_ONLY_ON_FAILURE),
	FLAG_INFO(EVENT_NEVER),
	FLAG_INFO(SKIP_CACHE_START),
	FLAG_INFO(SKIP_CACHE_END),
	{}
};
#undef FLAG_INFO

#define FLAG_INFO(flag) { flag, #flag }
static const struct panwrap_flag_info mmap_prot_flag_info[] = {
	FLAG_INFO(PROT_EXEC),
	FLAG_INFO(PROT_READ),
	FLAG_INFO(PROT_WRITE),
	{}
};

/* Fix issue building for Linux */

#ifndef MAP_UNINITIALIZED
#define MAP_UNINITIALIZED 0xDEADBEEF
#endif

static const struct panwrap_flag_info mmap_flags_flag_info[] = {
	FLAG_INFO(MAP_SHARED),
	FLAG_INFO(MAP_PRIVATE),
	FLAG_INFO(MAP_ANONYMOUS),
	FLAG_INFO(MAP_DENYWRITE),
	FLAG_INFO(MAP_FIXED),
	FLAG_INFO(MAP_GROWSDOWN),
	FLAG_INFO(MAP_HUGETLB),
	FLAG_INFO(MAP_LOCKED),
	FLAG_INFO(MAP_NONBLOCK),
	FLAG_INFO(MAP_NORESERVE),
	FLAG_INFO(MAP_POPULATE),
	FLAG_INFO(MAP_STACK),
	FLAG_INFO(MAP_UNINITIALIZED),
	{}
};

static const struct panwrap_flag_info external_resources_access_flag_info[] = {
	FLAG_INFO(MALI_EXT_RES_ACCESS_SHARED),
	FLAG_INFO(MALI_EXT_RES_ACCESS_EXCLUSIVE),
	{}
};

static const struct panwrap_flag_info mali_jd_dep_type_flag_info[] = {
	FLAG_INFO(MALI_JD_DEP_TYPE_DATA),
	FLAG_INFO(MALI_JD_DEP_TYPE_ORDER),
	{}
};
#undef FLAG_INFO

static struct mapped_memory *find_mapped_mem(void *addr)
{
	struct mapped_memory *pos = NULL;

	list_for_each_entry(pos, &mmaps, node) {
		if (pos->addr == addr)
			return pos;
	}

	return NULL;
}

static struct mapped_memory *find_gpu_mapped_mem(uint64_t addr)
{
	struct mapped_memory *pos = NULL;

	list_for_each_entry(pos, &mmaps, node) {
		printf("Candidate (%llx, %llx) for %llx\n", pos->gpu_va, pos->gpu_va + pos->length, addr);
		if (addr >= pos->gpu_va && addr <= pos->gpu_va + pos->length)
			return pos;
	}

	return NULL;
}

void *fetch_mapped_gpu(u64 gpu_addr, size_t sz)
{
	if (!gpu_addr) {
		panwrap_log("Tried to dereference GPU null!\n");
		return NULL;
	}

	struct mapped_memory *mem = find_gpu_mapped_mem(gpu_addr);

	if (!mem) {
		panwrap_log("Unmapped GPU mem %llx\n", gpu_addr);

		return NULL;
	}

	/* Sanity bounds check */
	if (gpu_addr - mem->gpu_va + sz > mem->length) {
		panwrap_log("GPU memory overflow @ %llX\n", gpu_addr);
		return NULL;
	}

	return mem->addr + (gpu_addr - mem->gpu_va);
}

static inline const char *
ioctl_decode_coherency_mode(enum mali_ioctl_coherency_mode mode)
{
	switch (mode) {
	case COHERENCY_ACE_LITE: return "ACE_LITE";
	case COHERENCY_ACE:      return "ACE";
	case COHERENCY_NONE:     return "None";
	default:                 return "???";
	}
}

static inline const char *
ioctl_decode_jd_prio(mali_jd_prio prio)
{
	switch (prio) {
	case MALI_JD_PRIO_LOW:    return "Low";
	case MALI_JD_PRIO_MEDIUM: return "Medium";
	case MALI_JD_PRIO_HIGH:   return "High";
	default:                  return "???";
	}
}

/*
 * Decodes the jd_core_req flags and their real meanings
 * See mali_kbase_jd.c
 */
static inline const char *
ioctl_get_job_type_from_jd_core_req(mali_jd_core_req req)
{
	if (req & MALI_JD_REQ_SOFT_JOB)
		return "Soft job";
	if (req & MALI_JD_REQ_ONLY_COMPUTE)
		return "Compute Shader Job";

	switch (req & (MALI_JD_REQ_FS | MALI_JD_REQ_CS | MALI_JD_REQ_T)) {
	case MALI_JD_REQ_DEP:
		return "Dependency only job";
	case MALI_JD_REQ_FS:
		return "Fragment shader job";
	case MALI_JD_REQ_CS:
		return "Vertex/Geometry shader job";
	case MALI_JD_REQ_T:
		return "Tiler job";
	case (MALI_JD_REQ_FS | MALI_JD_REQ_CS):
		return "Fragment shader + vertex/geometry shader job";
	case (MALI_JD_REQ_FS | MALI_JD_REQ_T):
		return "Fragment shader + tiler job";
	case (MALI_JD_REQ_CS | MALI_JD_REQ_T):
		return "Vertex/geometry shader job + tiler job";
	case (MALI_JD_REQ_FS | MALI_JD_REQ_CS | MALI_JD_REQ_T):
		return "Fragment shader + vertex/geometry shader job + tiler job";
	}

	return "???";
}

#define SOFT_FLAG(flag)                                  \
	case MALI_JD_REQ_SOFT_##flag:                    \
		panwrap_log_cont("%s)", "SOFT_" #flag); \
		break
/* Decodes the actual jd_core_req flags, but not their meanings */
static inline void
ioctl_log_decoded_jd_core_req(mali_jd_core_req req)
{
	if (req & MALI_JD_REQ_SOFT_JOB) {
		panwrap_log_cont("0x%010x (", req);

		switch (req) {
		SOFT_FLAG(DUMP_CPU_GPU_TIME);
		SOFT_FLAG(FENCE_TRIGGER);
		SOFT_FLAG(FENCE_WAIT);
		SOFT_FLAG(REPLAY);
		SOFT_FLAG(EVENT_WAIT);
		SOFT_FLAG(EVENT_SET);
		SOFT_FLAG(EVENT_RESET);
		SOFT_FLAG(DEBUG_COPY);
		SOFT_FLAG(JIT_ALLOC);
		SOFT_FLAG(JIT_FREE);
		SOFT_FLAG(EXT_RES_MAP);
		SOFT_FLAG(EXT_RES_UNMAP);
		default: panwrap_log_cont("???" ")"); break;
		}
	} else {
		panwrap_log_decoded_flags(jd_req_flag_info, req);
	}
}
#undef SOFT_FLAG

static void
ioctl_decode_pre_mem_alloc(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_mem_alloc *args = ptr;

	panwrap_log("\tva_pages = %lld\n", args->va_pages);
	panwrap_log("\tcommit_pages = %lld\n", args->commit_pages);
	panwrap_log("\textent = 0x%llx\n", args->extent);

	panwrap_log("\tflags = ");
	panwrap_log_decoded_flags(mem_flag_info, args->flags);
	panwrap_log_cont("\n");
}

static void
ioctl_decode_pre_mem_import(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_mem_import *args = ptr;
	const char *type;

	switch (args->type) {
	case MALI_MEM_IMPORT_TYPE_UMP:         type = "UMP"; break;
	case MALI_MEM_IMPORT_TYPE_UMM:         type = "UMM"; break;
	case MALI_MEM_IMPORT_TYPE_USER_BUFFER: type = "User buffer"; break;
	default:                               type = "Invalid"; break;
	}

	panwrap_log("\tphandle = 0x%llx\n", args->phandle);
	panwrap_log("\ttype = %d (%s)\n", args->type, type);

	panwrap_log("\tflags = ");
	panwrap_log_decoded_flags(mem_flag_info, args->flags);
	panwrap_log_cont("\n");
}

static void
ioctl_decode_pre_mem_commit(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_mem_commit *args = ptr;

	panwrap_log("\tgpu_addr = 0x%llx\n", args->gpu_addr);
	panwrap_log("\tpages = %lld\n", args->pages);
}

static void
ioctl_decode_pre_mem_query(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_mem_query *args = ptr;
	char *query_name;

	switch (args->query) {
	case MALI_MEM_QUERY_COMMIT_SIZE: query_name = "Commit size"; break;
	case MALI_MEM_QUERY_VA_SIZE:     query_name = "VA size"; break;
	case MALI_MEM_QUERY_FLAGS:       query_name = "Flags"; break;
	default:                         query_name = "???"; break;
	}

	panwrap_log("\tgpu_addr = 0x%llx\n", args->gpu_addr);
	panwrap_log("\tquery = %d (%s)\n", args->query, query_name);
}

static void
ioctl_decode_pre_mem_free(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_mem_free *args = ptr;

	panwrap_log("\tgpu_addr = 0x%llx\n", args->gpu_addr);
}

static void
ioctl_decode_pre_mem_flags_change(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_mem_flags_change *args = ptr;

	panwrap_log("\tgpu_va = 0x%llx\n", args->gpu_va);
	panwrap_log("\tflags = ");
	panwrap_log_decoded_flags(mem_flag_info, args->flags);
	panwrap_log_cont("\n");
	panwrap_log("\tmask = 0x%llx\n", args->mask);
}

static void
ioctl_decode_pre_mem_alias(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_mem_alias *args = ptr;

	panwrap_log("\tflags = ");
	panwrap_log_decoded_flags(mem_flag_info, args->flags);
	panwrap_log_cont("\n");
	panwrap_log("\tstride = %lld\n", args->stride);
	panwrap_log("\tnents = %lld\n", args->nents);
	panwrap_log("\tai = 0x%llx\n", args->ai);
}

static inline void
ioctl_decode_pre_sync(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_sync *args = ptr;
	const char *type;
	struct mapped_memory *mem = find_mapped_mem((void*) (uintptr_t) args->handle);

	switch (args->type) {
	case MALI_SYNC_TO_DEVICE: type = "device <- CPU"; break;
	case MALI_SYNC_TO_CPU:    type = "device -> CPU"; break;
	default:                  type = "???"; break;
	}

	if (mem) {
		panwrap_log("\thandle = %p (end=%p, len=%zu)\n",
			    (void*) (uintptr_t) args->handle,
			    (void*) (uintptr_t) args->handle + mem->length,
			    mem->length);
		panwrap_log("\tuser_addr = %p - %p (offset=%llu)\n",
			    args->user_addr, args->user_addr + args->size,
			    (u64) (uintptr_t) args->user_addr - (u64) (uintptr_t) args->handle);
	} else {
		panwrap_log("\tERROR! Unknown handle specified\n");
		panwrap_log("\thandle = 0x%p\n", (void*) (uintptr_t) args->handle);
		panwrap_log("\tuser_addr = %p - %p\n",
			    args->user_addr, args->user_addr + args->size);
	}
	panwrap_log("\tsize = %lld\n", args->size);
	panwrap_log("\ttype = %d (%s)\n", args->type, type);

	if (args->type == MALI_SYNC_TO_DEVICE) {
		panwrap_log("\tDumping memory being synced to device:\n");
		panwrap_log_hexdump(args->user_addr, args->size, "\t\t");
	}
}

static void
ioctl_decode_pre_set_flags(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_set_flags *args = ptr;

	panwrap_log("\tcreate_flags = %08x\n", args->create_flags);
}

static inline void
ioctl_decode_pre_stream_create(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_stream_create *args = ptr;

	panwrap_log("\tname = %s\n", args->name);
}

struct mapped_dump {
	u64 gpu_va;
	u64 length;
	/* Followed by buffer itself */
};

static void
dump_mapped_memory() {
	/* Anything that is mapped? Dump it to a file.
	 * Should be called once at the end of a frame in a single-frame
	 * render.
	 * Useful for replay, offline decode, etc.
	 */

	FILE *fp = fopen("memory-dump.bin", "wb");

	struct mapped_memory *pos = NULL;

	list_for_each_entry(pos, &mmaps, node) {
		struct mapped_dump dump = {
			.gpu_va = pos->gpu_va,
			.length = pos->length
		};

		/* We don't care about endianness, LE everywhere */

		if (pos->addr && pos->gpu_va) {
			fwrite(&dump, 1, sizeof(dump), fp);

			if (pos->length) {
				fwrite(pos->addr, 1, pos->length, fp);
			}
		} else {
			printf("Warning, NULL mmap skipped in dump\n");
		}
	}

	fclose(fp);
}

/* TODO: Decode offline */
#define __PANWRAP
#include <pantrace.h>

static inline void
ioctl_decode_pre_job_submit(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_job_submit *args = ptr;
	const struct mali_jd_atom_v2 *atoms = args->addr;

	panwrap_log("\taddr = %p\n", args->addr);
	panwrap_log("\tnr_atoms = %d\n", args->nr_atoms);
	panwrap_log("\tstride = %d\n", args->stride);

	/* The stride should be equivalent to the length of the structure,
	 * if it isn't then it's possible we're somehow tracing one of the
	 * legacy job formats
	 */
	if (args->stride != sizeof(*atoms)) {
		panwrap_log("\tSIZE MISMATCH (stride should be %zd, was %d)\n",
			    sizeof(*atoms), args->stride);
		panwrap_log("\tCannot dump atoms :(, maybe it's a legacy job format?\n");
		return;
	}

	panwrap_log("\tAtoms:\n");
	for (unsigned int i = 0; i < args->nr_atoms; i++) {
		const struct mali_jd_atom_v2 *a = &atoms[i];
		uint64_t core_req;

		panwrap_log("\t\tudata = [0x%llx, 0x%llx]\n",
			    a->udata.blob[0], a->udata.blob[1]);
		panwrap_log("\t\tnr_ext_res = %d\n", a->nr_ext_res);

		if (a->ext_res_list) {
			panwrap_log("\t\text_res_list.count = %lld\n",
				    a->ext_res_list->count);
			panwrap_log("\t\tExternal resources:\n");

			for (unsigned int j = 0; j < a->nr_ext_res; j++)
			{
				panwrap_log("\t\t\t");
				panwrap_log_decoded_flags(
					external_resources_access_flag_info,
					a->ext_res_list[j].ext_resource[0]);
				panwrap_log_cont("\n");
			}
		} else {
			panwrap_log("\t\t<no external resources>\n");
		}

		core_req = a->core_req | a->compat_core_req;

		panwrap_log("\t\tcompat_core_req = 0x%x\n", a->compat_core_req);
		panwrap_log("\t\tcore_req = 0x%x\n", a->core_req);

		panwrap_log("\t\tPre-dependencies:\n");
		for (unsigned int j = 0; j < ARRAY_SIZE(a->pre_dep); j++) {
			panwrap_log("\t\t\tatom_id = %d flags == ",
				    a->pre_dep[i].atom_id);
			panwrap_log_decoded_flags(
			    mali_jd_dep_type_flag_info,
			    a->pre_dep[i].dependency_type);
			panwrap_log_cont("\n");
		}

		panwrap_log("\t\tatom_number = %d\n", a->atom_number);
		panwrap_log("\t\tprio = %d (%s)\n",
			    a->prio, ioctl_decode_jd_prio(a->prio));
		panwrap_log("\t\tdevice_nr = %d\n", a->device_nr);

		panwrap_log("\t\tJob type = %s\n",
			    ioctl_get_job_type_from_jd_core_req(core_req));
		panwrap_log("\t\tdecoded_core_req = ");
		ioctl_log_decoded_jd_core_req(core_req);
		panwrap_log_cont("\n");

		dump_mapped_memory();
		fflush(ioctl_fp);

		chai_trace_atom(a);

	}
}

static void
ioctl_decode_pre(unsigned long int request, void *ptr)
{
	switch (IOCTL_CASE(request)) {
	case IOCTL_CASE(MALI_IOCTL_MEM_ALLOC):
		ioctl_decode_pre_mem_alloc(request, ptr);
		break;
	case IOCTL_CASE(MALI_IOCTL_MEM_IMPORT):
		ioctl_decode_pre_mem_import(request, ptr);
		break;
	case IOCTL_CASE(MALI_IOCTL_MEM_COMMIT):
		ioctl_decode_pre_mem_commit(request, ptr);
		break;
	case IOCTL_CASE(MALI_IOCTL_MEM_QUERY):
		ioctl_decode_pre_mem_query(request, ptr);
		break;
	case IOCTL_CASE(MALI_IOCTL_MEM_FREE):
		ioctl_decode_pre_mem_free(request, ptr);
		break;
	case IOCTL_CASE(MALI_IOCTL_MEM_FLAGS_CHANGE):
		ioctl_decode_pre_mem_flags_change(request, ptr);
		break;
	case IOCTL_CASE(MALI_IOCTL_MEM_ALIAS):
		ioctl_decode_pre_mem_alias(request, ptr);
		break;
	case IOCTL_CASE(MALI_IOCTL_SYNC):
		ioctl_decode_pre_sync(request, ptr);
		break;
	case IOCTL_CASE(MALI_IOCTL_SET_FLAGS):
		ioctl_decode_pre_set_flags(request, ptr);
		break;
	case IOCTL_CASE(MALI_IOCTL_STREAM_CREATE):
		ioctl_decode_pre_stream_create(request, ptr);
		break;
	case IOCTL_CASE(MALI_IOCTL_JOB_SUBMIT):
		ioctl_decode_pre_job_submit(request, ptr);
		break;
	default:
		break;
	}
}

static void
ioctl_decode_post_get_version(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_get_version *args = ptr;

	panwrap_log("\tmajor = %3d\n", args->major);
	panwrap_log("\tminor = %3d\n", args->minor);
}

static void
ioctl_decode_post_mem_alloc(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_mem_alloc *args = ptr;
	struct allocated_memory *new = malloc(sizeof(*new));

	panwrap_log("\tgpu_va = 0x%llx\n", args->gpu_va);
	panwrap_log("\tva_alignment = %d\n", args->va_alignment);

	panwrap_log("\tflags = %llx", args->flags);

	new->gpu_va = args->gpu_va;
	new->same_va = args->flags & MALI_MEM_SAME_VA;
	list_add(&new->node, &allocations);

	panwrap_log_cont("\n");
}

static void
ioctl_decode_post_mem_import(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_mem_import *args = ptr;

	panwrap_log("\tgpu_va = 0x%llx\n", args->gpu_va);
	panwrap_log("\tva_pages = %lld\n", args->va_pages);
	panwrap_log("\tflags = ");
	panwrap_log_decoded_flags(mem_flag_info, args->flags);
	panwrap_log_cont("\n");
}

static void
ioctl_decode_post_mem_commit(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_mem_commit *args = ptr;

	panwrap_log("\tresult_subcode = %d\n", args->result_subcode);

	struct allocated_memory *new = malloc(sizeof(*new));
	new->gpu_va = args->gpu_addr;
	new->same_va = false;
	list_add(&new->node, &allocations);
}

static void
ioctl_decode_post_mem_query(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_mem_query *args = ptr;

	panwrap_log("\tvalue = 0x%llx\n", args->value);
}

static void
ioctl_decode_post_mem_alias(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_mem_alias *args = ptr;

	panwrap_log("\tgpu_va = 0x%llx\n", args->gpu_va);
	panwrap_log("\tva_pages = %lld\n", args->va_pages);
}

static inline void
ioctl_decode_post_sync(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_sync *args = ptr;

	if (args->type != MALI_SYNC_TO_CPU)
		return;

	panwrap_log("\tDumping memory from device:\n");
	panwrap_log_hexdump(args->user_addr, args->size, "\t\t");
}

static void
ioctl_decode_post_gpu_props_reg_dump(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_gpu_props_reg_dump *args = ptr;
	const char *implementation;

	switch (args->thread.impl_tech) {
	case MALI_GPU_IMPLEMENTATION_UNKNOWN: implementation = "Unknown"; break;
	case MALI_GPU_IMPLEMENTATION_SILICON: implementation = "Silicon"; break;
	case MALI_GPU_IMPLEMENTATION_FPGA:    implementation = "FPGA"; break;
	case MALI_GPU_IMPLEMENTATION_SW:      implementation = "Software"; break;
	}

	panwrap_log("\tcore:\n");
	panwrap_log("\t\tProduct ID: %d\n", args->core.product_id);
	panwrap_log("\t\tVersion status: %d\n", args->core.version_status);
	panwrap_log("\t\tMinor revision: %d\n", args->core.minor_revision);
	panwrap_log("\t\tMajor revision: %d\n", args->core.major_revision);
	panwrap_log("\t\tGPU speed (?): %dMHz\n", args->core.gpu_speed_mhz);
	panwrap_log("\t\tGPU frequencies (?): %dKHz-%dKHz\n",
		    args->core.gpu_freq_khz_min, args->core.gpu_freq_khz_max);
	panwrap_log("\t\tShader program counter size: %.lf MB\n",
		    pow(2, args->core.log2_program_counter_size) / 1024 / 1024);

	panwrap_log("\t\tTexture features:\n");
	for (unsigned int i = 0; i < ARRAY_SIZE(args->core.texture_features); i++)
		panwrap_log("\t\t\t%010x\n", args->core.texture_features[i]);

	panwrap_log("\t\tAvailable memory: %lld bytes\n",
		    args->core.gpu_available_memory_size);

	panwrap_log("\tL2 cache:\n");
	panwrap_log("\t\tLine size: %.lf (bytes, words?)\n",
		    pow(2, args->l2.log2_line_size));
	panwrap_log("\t\tCache size: %.lf KB\n",
		    pow(2, args->l2.log2_cache_size) / 1024);
	panwrap_log("\t\tL2 slice count: %d\n", args->l2.num_l2_slices);

	panwrap_log("\tTiler:\n");
	panwrap_log("\t\tBinary size: %d bytes\n",
		    args->tiler.bin_size_bytes);
	panwrap_log("\t\tMax active levels: %d\n",
		    args->tiler.max_active_levels);

	panwrap_log("\tThreads:\n");
	panwrap_log("\t\tMax threads: %d\n", args->thread.max_threads);
	panwrap_log("\t\tMax threads per workgroup: %d\n",
		    args->thread.max_workgroup_size);
	panwrap_log("\t\tMax threads allowed for synchronizing on simple barrier: %d\n",
		    args->thread.max_barrier_size);
	panwrap_log("\t\tMax registers available per-core: %d\n",
		    args->thread.max_registers);
	panwrap_log("\t\tMax tasks that can be sent to a core before blocking: %d\n",
		    args->thread.max_task_queue);
	panwrap_log("\t\tMax allowed thread group split value: %d\n",
		    args->thread.max_thread_group_split);
	panwrap_log("\t\tImplementation type: %d (%s)\n",
		    args->thread.impl_tech, implementation);

	panwrap_log("\tRaw props:\n");
	panwrap_log("\t\tShader present? %s\n", YES_NO(args->raw.shader_present));
	panwrap_log("\t\tTiler present? %s\n", YES_NO(args->raw.tiler_present));
	panwrap_log("\t\tL2 present? %s\n", YES_NO(args->raw.l2_present));
	panwrap_log("\t\tStack present? %s\n", YES_NO(args->raw.stack_present));
	panwrap_log("\t\tL2 features: 0x%010x\n", args->raw.l2_features);
	panwrap_log("\t\tSuspend size: %d\n", args->raw.suspend_size);
	panwrap_log("\t\tMemory features: 0x%010x\n", args->raw.mem_features);
	panwrap_log("\t\tMMU features: 0x%010x\n", args->raw.mmu_features);
	panwrap_log("\t\tAS (what is this?) present? %s\n",
		    YES_NO(args->raw.as_present));

	panwrap_log("\t\tJS (what is this?) present? %s\n",
		    YES_NO(args->raw.js_present));
	panwrap_log("\t\tJS features:\n");
	for (unsigned int i = 0; i < ARRAY_SIZE(args->raw.js_features); i++)
		panwrap_log("\t\t\t%010x\n", args->raw.js_features[i]);

	panwrap_log("\t\tTiler features: %010x\n", args->raw.tiler_features);

	panwrap_log("\t\tGPU ID: 0x%x\n", args->raw.gpu_id);
	panwrap_log("\t\tThread features: 0x%x\n", args->raw.thread_features);
	panwrap_log("\t\tCoherency mode: 0x%x (%s)\n",
		    args->raw.coherency_mode,
		    ioctl_decode_coherency_mode(args->raw.coherency_mode));

	panwrap_log("\tCoherency info:\n");
	panwrap_log("\t\tNumber of groups: %d\n", args->coherency_info.num_groups);
	panwrap_log("\t\tNumber of core groups (coherent or not): %d\n",
		    args->coherency_info.num_core_groups);
	panwrap_log("\t\tFeatures: 0x%x\n", args->coherency_info.coherency);
	panwrap_log("\t\tGroups:\n");
	for (unsigned int i = 0; i < args->coherency_info.num_groups; i++) {
		panwrap_log("\t\t\t- Core mask: %010llx\n",
			    args->coherency_info.group[i].core_mask);
		panwrap_log("\t\t\t  Number of cores: %d\n",
			    args->coherency_info.group[i].num_cores);
	}
}

static inline void
ioctl_decode_post_stream_create(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_stream_create *args = ptr;

	panwrap_log("\tfd = %d\n", args->fd);
}

static inline void
ioctl_decode_post_get_context_id(unsigned long int request, void *ptr)
{
	const struct mali_ioctl_get_context_id *args = ptr;

	panwrap_log("\tid = 0x%llx\n", args->id);
}

static void
ioctl_decode_post(unsigned long int request, void *ptr)
{
	switch (IOCTL_CASE(request)) {
	case IOCTL_CASE(MALI_IOCTL_GET_VERSION):
	case IOCTL_CASE(MALI_IOCTL_GET_VERSION_NEW):
		ioctl_decode_post_get_version(request, ptr);
		break;
	case IOCTL_CASE(MALI_IOCTL_MEM_ALLOC):
		ioctl_decode_post_mem_alloc(request, ptr);
		break;
	case IOCTL_CASE(MALI_IOCTL_MEM_IMPORT):
		ioctl_decode_post_mem_import(request, ptr);
		break;
	case IOCTL_CASE(MALI_IOCTL_MEM_COMMIT):
		ioctl_decode_post_mem_commit(request, ptr);
		break;
	case IOCTL_CASE(MALI_IOCTL_MEM_QUERY):
		ioctl_decode_post_mem_query(request, ptr);
		break;
	case IOCTL_CASE(MALI_IOCTL_MEM_ALIAS):
		ioctl_decode_post_mem_alias(request, ptr);
		break;
	case IOCTL_CASE(MALI_IOCTL_SYNC):
		ioctl_decode_post_sync(request, ptr);
		break;
	case IOCTL_CASE(MALI_IOCTL_GPU_PROPS_REG_DUMP):
		ioctl_decode_post_gpu_props_reg_dump(request, ptr);
		break;
	case IOCTL_CASE(MALI_IOCTL_STREAM_CREATE):
		ioctl_decode_post_stream_create(request, ptr);
		break;
	case IOCTL_CASE(MALI_IOCTL_GET_CONTEXT_ID):
		ioctl_decode_post_get_context_id(request, ptr);
		break;
	default:
		break;
	}
}

/**
 * Overriden libc functions start here
 */
int
panwrap_open_wrap(open_func *orig_open, const char *path, int flags, va_list args)
{
	mode_t mode = 0;
	int ret;

	if (flags & O_CREAT) {
		mode = (mode_t) va_arg(args, int);
		ret = orig_open(path, flags, mode);
	} else {
		ret = orig_open(path, flags);
	}

	LOCK();
	if (ret != -1) {
		if (strcmp(path, "/dev/mali0") == 0) {
			panwrap_log("/dev/mali0 fd == %d\n", ret);
			mali_fd = ret;
		} else if (strstr(path, "/dev/")) {
			panwrap_log("Unknown device %s opened at fd %d\n",
				    path, ret);
		}
	}
	UNLOCK();

	return ret;
}

int
open(const char *path, int flags, ...)
{
	PROLOG(open);
	va_list args;
	va_start(args, flags);
	int o = panwrap_open_wrap(orig_open, path, flags, args);
	va_end(args);
	return o;
}

int
open64(const char *path, int flags, ...)
{
	PROLOG(open64);
	va_list args;
	va_start(args, flags);
	int o = panwrap_open_wrap(orig_open64, path, flags, args);
	va_end(args);
	return o;
}

int
close(int fd)
{
	PROLOG(close);

	LOCK();
	if (fd > 0 && fd == mali_fd) {
		panwrap_log("/dev/mali0 closed\n");
		mali_fd = 0;
	}
	UNLOCK();

	return orig_close(fd);
}

/* XXX: Android has a messed up ioctl signature */
int ioctl(int fd, unsigned long request, ...)
{
	const char *name;
	union mali_ioctl_header *header;
	PROLOG(ioctl);
	int ioc_size = _IOC_SIZE(request);
	int ret;
	uint32_t func;
	void *ptr;

	if (ioc_size) {
		va_list args;

		va_start(args, request);
		ptr = va_arg(args, void *);
		va_end(args);
	} else {
		ptr = NULL;
	}

	if (fd && fd != mali_fd)
		return orig_ioctl(fd, request, ptr);

	LOCK();
	panwrap_freeze_time();
	header = ptr;

	name = ioctl_get_info(request)->name;
	if (!name)
		name = "???";

	if (!ptr) { /* All valid mali ioctl's should have a specified arg */
		panwrap_log("<%-20s> (%02lu) (%08lx), has no arguments? Cannot decode :(\n",
			    name, _IOC_NR(request), request);

		panwrap_unfreeze_time();
		ret = orig_ioctl(fd, request, ptr);
		panwrap_freeze_time();

		panwrap_log("\t= %02d\n", ret);
		goto out;
	}

	/* Dump to ioctl file */
	fwrite(&request, 1, sizeof(request), ioctl_fp);
	fwrite(ptr, 1, _IOC_SIZE(request), ioctl_fp);

	func = header->id;
	panwrap_log("<%-20s> (%02lu) (%08lx) (%04lu) (%03d)\n",
		    name, _IOC_NR(request), request, _IOC_SIZE(request), func);
	ioctl_decode_pre(request, ptr);

	panwrap_unfreeze_time();
	ret = orig_ioctl(fd, request, ptr);
	panwrap_freeze_time();

	panwrap_log("\t= %02d, %02d\n",
		    ret, header->rc);
	ioctl_decode_post(request, ptr);

out:
	panwrap_unfreeze_time();
	UNLOCK();
	return ret;
}

static inline void *panwrap_mmap_wrap(mmap_func *func,
				      void *addr, size_t length, int prot,
				      int flags, int fd, loff_t offset)
{
	struct allocated_memory *pos = NULL;
	struct mapped_memory *new;
	void *ret;
	bool found = false;
	bool same_va = false;

	if (!mali_fd || fd != mali_fd)
		return func(addr, length, prot, flags, fd, offset);

	LOCK();
	ret = func(addr, length, prot, flags, fd, offset);

	panwrap_freeze_time();

	new = calloc(sizeof(*new), 1);
	new->length = length;
	new->addr = ret;

	list_for_each_entry(pos, &allocations, node) {
		/* The kernel driver uses the offset to specify which GPU VA
		 * we're mapping */
		if (pos->gpu_va == (u64) offset) {
			found = true;
			same_va = pos->same_va;
			list_del(&pos->node);
			free(pos);
			break;
		}
	}

	if (found) {
		new->gpu_va = same_va ? (u64) (uintptr_t) ret : (u64) offset;
		panwrap_log("GPU memory 0x%llx mapped to %p - %p length=%zu\n",
			    offset, ret, ret + length, length);
	} else {
		panwrap_log("Unknown memory mapping %p - %p: offset=%lld length=%zu prot = ",
			    ret, ret + length, offset, length);
		panwrap_log_decoded_flags(mmap_prot_flag_info, prot);
		panwrap_log_cont(" flags = ");
		panwrap_log_decoded_flags(mmap_flags_flag_info, flags);
		panwrap_log_cont("\n");
	}
	list_add(&new->node, &mmaps);
	panwrap_unfreeze_time();
	UNLOCK();
	return ret;
}

void *mmap64(void *addr, size_t length, int prot, int flags, int fd,
	     loff_t offset)
{
	PROLOG(mmap64);

	return panwrap_mmap_wrap(orig_mmap64, addr, length, prot, flags, fd,
				 offset);
}

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
{
#ifdef __LP64__
	PROLOG(mmap);

	return panwrap_mmap_wrap(orig_mmap, addr, length, prot, flags, fd,
							offset);
#else
	return mmap64(addr, length, prot, flags, fd, (loff_t) offset);
#endif
}

int munmap(void *addr, size_t length)
{
	int ret;
	struct mapped_memory *mem;
	PROLOG(munmap);

	LOCK();
	ret = orig_munmap(addr, length);

	panwrap_freeze_time();

	mem = find_mapped_mem(addr);
	if (!mem)
		goto out;

	/* Was it memory mapped from the GPU? */
	if (mem->gpu_va)
		panwrap_log("Unmapped GPU memory 0x%llx@%p\n",
			    mem->gpu_va, mem->addr);
	else
		panwrap_log("Unmapped unknown memory %p\n",
			    mem->addr);

	list_del(&mem->node);
	free(mem);
out:
	panwrap_unfreeze_time();
	UNLOCK();
	return ret;
}


code:
/*
 * © Copyright 2017 The BiOpenly Community
 *
 * This program is free software and is provided to you under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation, and any use by you of this program is subject to the terms
 * of such GNU licence.
 *
 * A copy of the licence is included with the program, and can also be obtained
 * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301, USA.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <ctype.h>
#include "panwrap.h"

#define HEXDUMP_COL_LEN  4
#define HEXDUMP_ROW_LEN 16

static bool enable_timestamps = false,
	    enable_hexdump_trimming = true;

static bool time_is_frozen = false;
static struct timespec start_time;
static struct timespec total_time_frozen, start_freeze_time, frozen_timestamp;
static FILE *log_output;
FILE *ioctl_fp;

void
panwrap_log_decoded_flags(const struct panwrap_flag_info *flag_info,
			  u64 flags)
{
	bool decodable_flags_found = false;

	panwrap_log_cont("0x%llx", flags);

	for (int i = 0; flag_info[i].name; i++) {
		if ((flags & flag_info[i].flag) != flag_info[i].flag)
			continue;

		if (!decodable_flags_found) {
			decodable_flags_found = true;
			panwrap_log_cont(" (");
		} else {
			panwrap_log_cont(" | ");
		}

		panwrap_log_cont("%s", flag_info[i].name);

		flags &= ~flag_info[i].flag;
	}

	if (decodable_flags_found) {
		if (flags)
			panwrap_log_cont(" | 0x%llx", flags);

		panwrap_log_cont(")");
	}
}

void
panwrap_log_hexdump(const void *data, size_t size, const char *indent)
{
	unsigned char *buf = (void *) data;
	char alpha[HEXDUMP_ROW_LEN + 1];
	unsigned int i;

	if (!data) {
		panwrap_log("NULL pointer dereference(hexdump)\n");
		return;
	}

	for (i = 0; i < size; i++) {
		if (!(i % HEXDUMP_ROW_LEN))
			panwrap_log("%s%08X", indent, (unsigned int) i);
		if (!(i % HEXDUMP_COL_LEN))
			panwrap_log_cont(" ");

		if (((void *) (buf + i)) < ((void *) data)) {
			panwrap_log_cont("   ");
			alpha[i % HEXDUMP_ROW_LEN] = '.';
		} else {
			panwrap_log_cont(" %02x", buf[i]);

			if (isprint(buf[i]) && (buf[i] < 0xA0))
				alpha[i % HEXDUMP_ROW_LEN] = buf[i];
			else
				alpha[i % HEXDUMP_ROW_LEN] = '.';
		}

		if ((i % HEXDUMP_ROW_LEN) == HEXDUMP_ROW_LEN - 1) {
			alpha[HEXDUMP_ROW_LEN] = 0;
			panwrap_log_cont("\t|%s|\n", alpha);
		}
	}

	if (i % HEXDUMP_ROW_LEN) {
		for (i %= HEXDUMP_ROW_LEN; i < HEXDUMP_ROW_LEN; i++) {
			panwrap_log_cont("   ");
			alpha[i] = '.';

			if (i == HEXDUMP_ROW_LEN - 1) {
				alpha[HEXDUMP_ROW_LEN] = 0;
				panwrap_log_cont("\t|%s|\n", alpha);
			}
		}
	}
}

/**
 * Same as panwrap_log_hexdump, but trims off sections of the memory that look
 * empty
 */
void
panwrap_log_hexdump_trimmed(const void *data, size_t size, const char *indent)
{
	const char *d = data;
	off_t trim_offset;
	size_t trim_size = size;
	bool trimming = false;

	if (!enable_hexdump_trimming)
		goto out;

	if (!data) {
		panwrap_log("NULL pointer dereference(hexdump)\n");
		return;
	}

	/*
	 * Find the last byte of the memory region that looks initialized,
	 * starting from the end
	 */
	for (trim_offset = size - 1; trim_offset != -1; trim_offset--) {
		if (d[trim_offset] != 0)
			break;
	}
	if (trim_offset < 0)
		goto out;

	trimming = true;
	trim_size = trim_offset + 1;
out:
	panwrap_log_hexdump(data, trim_size, indent);
	if (trimming)
		panwrap_log("%s<0 repeating %zu times>\n",
			    indent, size - trim_size);
}

/* glibc libraries are versioned. bionic libraries are not. If you use
 * something else, define it here.
 */

#ifdef __GLIBC__
#define LIBC_NAME "libc.so.6"
#else
#define LIBC_NAME "libc.so"
#endif

/**
 * Grab the location of a symbol from the system's libc instead of our
 * preloaded one
 */
void *
__rd_dlsym_helper(const char *name)
{
	static void *libc_dl;
	void *func;

	if (!libc_dl)
		libc_dl = dlopen(LIBC_NAME, RTLD_LAZY);
	if (!libc_dl) {
		fprintf(stderr, "Failed to dlopen libc: %s\n", dlerror());
		exit(-1);
	}

	func = dlsym(libc_dl, name);
	if (!func) {
		fprintf(stderr, "Failed to find %s: %s\n", name, dlerror());
		exit(-1);
	}

	return func;
}

static void
timespec_add(struct timespec *tp, const struct timespec *value)
{
	tp->tv_sec += value->tv_sec;
	tp->tv_nsec += value->tv_nsec;

	if (tp->tv_nsec >= 1e+9) {
		tp->tv_sec++;
		tp->tv_nsec -= 1e+9;
	}
}

static void
timespec_subtract(struct timespec *tp, const struct timespec *value)
{
	tp->tv_sec -= value->tv_sec;
	tp->tv_nsec -= value->tv_nsec;

	if (tp->tv_nsec < 0) {
		tp->tv_sec--;
		tp->tv_nsec = 1e+9 + tp->tv_nsec;
	}
}

static inline void
__get_monotonic_time(const char *file, int line, struct timespec *tp)
{
	if (clock_gettime(CLOCK_MONOTONIC, tp)) {
		fprintf(stderr, "%s:%d:Failed to call clock_gettime: %s\n",
			file, line, strerror(errno));
		exit(1);
	}
}
#define get_monotonic_time(tp) __get_monotonic_time(__FILE__, __LINE__, tp);

/*
 * When logging information to the console (or whatever our output is), we
 * obviously spend a good bit of time just outputting logs.  The offsets in
 * timestamps that can be caused by this can cause the time difference between
 * one operation the driver performed and another to be rather misleading.
 *
 * So, in order to avoid this we "freeze time" whenever we have panwrap code
 * executing with a overhead that's noticeable between logging lines, so that
 * our timestamps never reflect the amount of time an application spent in
 * panwrap's code.
 *
 * tl;dr: any time that passes while frozen is removed from timestamps
 */
void
panwrap_freeze_time()
{
	if (!enable_timestamps)
		return;

	get_monotonic_time(&start_freeze_time);
	time_is_frozen = true;

	/*
	 * Calculate the actual timestamp using the time where we first froze,
	 * since we know it won't change until we unfreeze time
	 */
	frozen_timestamp = start_freeze_time;
	timespec_subtract(&frozen_timestamp, &start_time);
	timespec_subtract(&frozen_timestamp, &total_time_frozen);
}

void
panwrap_unfreeze_time()
{
	struct timespec time_spent_frozen;

	if (!enable_timestamps || !time_is_frozen)
		return;

	time_is_frozen = false;
	get_monotonic_time(&time_spent_frozen);

	timespec_subtract(&time_spent_frozen, &start_freeze_time);
	timespec_add(&total_time_frozen, &time_spent_frozen);
}

static inline void
timestamp_get(struct timespec *tp)
{
	if (time_is_frozen) {
		*tp = frozen_timestamp;
		return;
	}

	get_monotonic_time(tp);
	timespec_subtract(tp, &start_time);
	timespec_subtract(tp, &total_time_frozen);
}

void
panwrap_log(const char *format, ...)
{
	struct timespec tp;
	va_list ap;

	if (enable_timestamps) {
		timestamp_get(&tp);
		fprintf(log_output,
			"panwrap [%.8lf]: ", tp.tv_sec + tp.tv_nsec / 1e+9F);
	} else {
		fprintf(log_output, "panwrap: ");
	}

	va_start(ap, format);
	vfprintf(log_output, format, ap);
	va_end(ap);
}

/* Eventually this function might do more */
void
panwrap_log_cont(const char *format, ...)
{
	va_list ap;

	va_start(ap, format);
	vfprintf(log_output, format, ap);
	va_end(ap);
}

static bool
parse_env_bool(const char *env, bool def)
{
	const char *val = getenv(env);

	if (!val)
		return def;

	if (strcmp(val, "1") == 0)
		return true;
	else if (strcmp(val, "0") == 0)
		return false;

	fprintf(stderr,
		"Invalid value for %s: %s\n"
		"Valid values are 0 or 1\n",
		env, val);
	exit(1);
}

static void __attribute__((constructor))
panwrap_util_init()
{
	const char *env;

	if (parse_env_bool("PANWRAP_ENABLE_TIMESTAMPS", false)) {
		enable_timestamps = true;
		if (clock_gettime(CLOCK_MONOTONIC, &start_time)) {
			fprintf(stderr,
				"Failed to call clock_gettime: %s\n",
				strerror(errno));
			exit(1);
		}
	}

	enable_hexdump_trimming = parse_env_bool("PANWRAP_ENABLE_HEXDUMP_TRIM",
						 true);
	env = getenv("PANWRAP_OUTPUT");
	if (env) {
		/* Don't try to reopen stderr or stdout, that won't work */
		if (strcmp(env, "/dev/stderr") == 0) {
			log_output = stderr;
		} else if (strcmp(env, "/dev/stdout") == 0) {
			log_output = stdout;
		} else {
			log_output = fopen(env, "w+");
			if (!log_output) {
				fprintf(stderr, "Failed to open %s: %s\n",
					env, strerror(errno));
				exit(1);
			}
		}
	} else {
		log_output = stdout;
	}

	srand(time(NULL));

	ioctl_fp = fopen("ioctls.bin", "wb");
}


code:
/*
 * © Copyright 2017 The BiOpenly Community
 *
 * This program is free software and is provided to you under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation, and any use by you of this program is subject to the terms
 * of such GNU license.
 *
 * A copy of the license is included with the program, and can also be obtained
 * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301, USA.
 *
 */

/*
 * Various bits and pieces of this borrowed from the freedreno project, which
 * borrowed from the lima project.
 */

#ifndef __WRAP_H__
#define __WRAP_H__

#include <dlfcn.h>
#include <panloader-util.h>

struct panwrap_flag_info {
	u64 flag;
	const char *name;
};

#define PROLOG(func)					\
	static typeof(func) *orig_##func = NULL;	\
	if (!orig_##func)				\
		orig_##func = __rd_dlsym_helper(#func);	\

void __attribute__((format (printf, 1, 2))) panwrap_log(const char *format, ...);
void __attribute__((format (printf, 1, 2))) panwrap_log_cont(const char *format, ...);

void panwrap_freeze_time();
void panwrap_unfreeze_time();

void panwrap_log_decoded_flags(const struct panwrap_flag_info *flag_info,
			       u64 flags);
void panwrap_log_hexdump(const void *data, size_t size, const char *indent);
void panwrap_log_hexdump_trimmed(const void *data, size_t size, const char *ident);

void * __rd_dlsym_helper(const char *name);

#endif /* __WRAP_H__ */


code:
project(prototype)

set(SRCS prototype.c)

if(PRECOMPILED_SHADERS)
	add_definitions("-DPRECOMPILED_SHADERS")
endif()

add_executable(prototype ${SRCS})
target_link_libraries(prototype m dl driver)


code:
#!/bin/sh
arm-linux-gnueabi-gcc prototype.c shim.c memory.c synthesise.c \
	-Wl,-Bdynamic -lc -ldl -lm \
	-I../../panloader/include \
	-Wall -Werror -Wextra -Wno-missing-braces -D_FILE_OFFSET_BITS=64


code:
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <sys/mman.h>
#include <stdbool.h>
#include <unistd.h>

#include <pandriver.h>

/* If present, the prototype will use external precompiled shaders.
 * It is unclear if these shaders (generated by the proprietary
 * compiler) can be distributed. If they are not present, a dummy shader
 * will be used instead.
 *
 * TODO: Integrate with the assembler.
 *
 */

#ifdef PRECOMPILED_SHADERS
#include "../../shader_hex.h"
#else
uint32_t sample_fragment[16] = { 0x11 };
uint32_t sample_vertex[16] = { 0x11 };
#endif

int main()
{
	float vertices[] = {
		0.0, 0.0, 0.0,
		1.0, 0.0, 0.0,
		1.0, 1.0, 0.0,
		0.0, 1.0, 0.0
	};
	uint32_t tiler_jc, fragment_jc;
	uint64_t scratchpad, heap_free_address, framebuffer;
	int fd = open_kernel_module();

	query_gpu_props(fd);

	init_cbma(fd);
	stream_create(fd, "malitl_339_0x53ae8");
	stream_create(fd, "malitl_339_0x53f78");

	scratchpad = alloc_gpu_pages(fd, 8, 0xC);
	heap_free_address = alloc_gpu_heap(fd, 0x8000);

	printf("Allocated what we need..\n");

	// size_t fb_size = 29 * 16 * 45 * 16 * 4 * 2;
	// uint64_t framebuffer = (uint64_t) (uint32_t) galloc(fb_size);

	/* Fake framebuffer to trap accesses */
	framebuffer = 0x1CAFE0000;

	printf("Tiling...\n");

	tiler_jc = job_chain_vertex_tiler(
	    fd, vertices, sizeof(vertices),
	    CHAI_TRIANGLE_FAN,
	    sample_vertex, sizeof(sample_vertex),
	    sample_fragment, sizeof(sample_fragment),
	    heap_free_address, scratchpad);

	fragment_jc = job_chain_fragment(fd, framebuffer, heap_free_address,
					 scratchpad);

	job_chain_replay(fd, tiler_jc, fragment_jc, heap_free_address, framebuffer);
	flush_job_queue(fd);

	sleep(3);

	/* Dump framebuffer to a file */
	/*uint8_t *fb = (uint8_t*) (uint32_t) framebuffer;
	FILE *fp = fopen("framebuffer.bin", "wb");
	fwrite(fb, 1, fb_size, fp);
	fclose(fp);*/

	/* Hang to prevent the tracer from going bananas */

	while(1);

	return 0;
}


code:
project(replay)

set(SRCS replay.c)

add_executable(replay ${SRCS})
target_link_libraries(replay dl m)


code:
/*
 *
 * Copyright (C) 2017 Cafe Beverage. All rights reserved.
 *
 * This program is free software and is provided to you under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation, and any use by you of this program is subject to the terms
 * of such GNU licence.
 *
 * A copy of the licence is included with the program, and can also be obtained
 * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301, USA.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <fcntl.h>

struct ioctl_buffer {
	unsigned long request;
	void *ptr;
};

struct ioctl_buffer *ioctls = NULL;
int ioctl_count = 0;

struct mmap_buffer {
	uint64_t gpu_va;
	uint64_t length;
	void *buffer;
};

struct mmap_buffer *mmaps = NULL;
int mmap_count = 0;

int main(int argc, const char **argv)
{
	if (argc != 3) {
		printf("Usage: ./replay ioctl.bin memory.bin\n");
		return 1;
	}

	FILE *fp;

	/* Read and decode ioctls in a blocky way */
	fp = fopen(argv[1], "rb");
	unsigned long request;

	while(fread(&request, 1, sizeof(request), fp) == sizeof(request)) {
		ioctls = realloc(ioctls, sizeof(struct ioctl_buffer) * (++ioctl_count));
		struct ioctl_buffer* buffer = &ioctls[ioctl_count - 1];

		buffer->request = request;

		size_t s = _IOC_SIZE(buffer->request);

		void *arg = malloc(s);
		printf("malloc(%d) = %p\n", s, arg);
		buffer->ptr = arg;
		fread(arg, 1, s, fp);

		printf("Request: %lx\n", buffer->request);
	}

	fclose(fp);

#if 0
	/* Read and decode memory */
	fp = fopen(argv[2], "rb");

	uint64_t gpu_va;
	while(fread(&gpu_va, 1, sizeof(gpu_va), fp) == sizeof(gpu_va)) {
		mmaps = realloc(mmaps, sizeof(struct mmap_buffer) * (++mmap_count));
		struct mmap_buffer buffer = mmaps[mmap_count - 1];

		buffer->gpu_va = gpu_va;
		fread(&buffer->length, 1, sizeof(buffer->length), fp);

		buffer->buffer = malloc(buffer->length);
		fread(buffer->buffer, 1, buffer->length, fp);
	}
#endif

	/* Open a context with the kernel */
	int fd = open("/dev/mali0", O_RDWR | O_CLOEXEC);

	/* Walk the ioctl tree */
	for(int i = 0; i < ioctl_count; ++i) {
		struct ioctl_buffer io = ioctls[i];
		printf("(%lx, %p)\n", io.request, io.ptr);
		ioctl(fd, io.request, io.ptr);
	}

	/* TODO: Put in memory at the right places */
	return 1;
}


code:
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]

# C extensions
*.so

# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.cache
nosetests.xml
coverage.xml

# Translations
*.mo
*.pot

# Django stuff:
*.log

# Sphinx documentation
docs/_build/

# PyBuilder
target/
/.idea
/venv
/venv-jupyter

# Jupyter checkpoints
.ipynb_checkpoints/
.vscode/

path: .gitignore

license: unknown


code:
"""
Task 1

Write a function called oops that explicitly raises an IndexError exception when called. Then write another function
that calls oops inside a try/except statement to catch the error. What happens if you change oops to raise KeyError
instead of IndexError?
"""

def oops():
    raise IndexError

def catch_index_error():
    try:
        oops()
    except (IndexError):
        print("IndexError catches successfully")

if __name__ == '__main__':
    catch_index_error()
    oops()


code:
"""
Task 2

Write a function that takes in two numbers from the user via input(), call the numbers a and b, and then returns the
value of squared a divided by b, construct a try-except block which raises an exception if the two values given by
the input function were not numbers, and if value b was zero (cannot divide by zero).
"""

def function_1():
    a, b = map(str, input("Enter two numbers separated by comma: ").split(','))
    try:
        print(f"Result: {(float(a) * float(a)) / float(b)}")
    except ValueError:
        print("Enter valid numbers")
    except ZeroDivisionError:
        print("The second number can't be zero")

if __name__ == '__main__':
    function_1()


code:
"""

Створити функцію, яка приймає на вхід список та число n. Вхідний список потрібно розбити на n максимально рівномірних
підсписків. Додатково можна зробити аргумент, який дозволить перевернути кожен із підсписків. chunks([1, 2, 3, 4, 5,
6, 7], 3) -> [[1, 2], [3, 4], [5, 6, 7]]

"""

def chunks(integers_list: list, n: int = 2) -> list:
    if n == len(integers_list):
        returned_list = integers_list

    print(list(returned_list))

if __name__ == "__main__":
    chunks([1, 2, 3, 4, 5, 6, 7], 3)
    chunks([1, 2, 3, 4, 5, 6, 7])

# slice or recursion


cell_type: markdown

source: There are (at least) two distinguishable kinds of errors: syntax errors and exceptions

cell_type: code

traceback:
  Cell In [1], line 1
    while True print('Hello world')
               ^
SyntaxError: invalid syntax

source: Even if a statement or an expression is syntactically correct, it may cause an error when an attempt is made to execute it. Errors detected during execution are called `exceptions` and are not unconditionally fatal: you will soon learn how to handle them in Python programs. However, most exceptions are not handled by programs and result in error messages as shown here.

traceback: ZeroDivisionError                         Traceback (most recent call last)

evalue: can only concatenate str (not "int") to str

traceback: TypeError                                 Traceback (most recent call last)

traceback: TypeError: can only concatenate str (not "int") to str

traceback: IndexError                                Traceback (most recent call last)

stdout

text: imposible operation

source:
try:
1 / 0
except ZeroDivisionError:
print('imposible operation')

source: - First, the `try` clause (the statement(s) between the `try` and `except` keywords) is executed.

source: - If no exception occurs, the except clause is skipped and execution of the `try` statement is finished.

source: - If an exception occurs during the execution of the `try` clause, the rest of the clause is skipped. Then if its type matches the exception named after the except keyword, the except clause is executed, and then the execution continues after the `try` statement.

source: - If an exception occurs but does not match the exception named in the except clause, it is passed on to outer `try` statements; if no handler is found, it is an unhandled exception and the execution stops with a message as shown above.

source: An except clause may name multiple exceptions as a parenthesized tuple, for example

source: except (RuntimeError, TypeError, NameError):

source:
try:
[1,2,3][4]
except TypeError:
print("oops ham")
except ZeroDivisionError:
print("oops spam")
except:
print("Unexpected error!")
raise

source: The `try … except` statement has an optional else clause, which, when present, must follow all except clauses. It is useful for code that must be executed if the try clause does not raise an exception. For example:

source:
x = [1,2,3,4,0]
for i in x:
try:
print(10 / i)
except ZeroDivisionError:
print('wrong operations')
else:
print('good operation')

source:
try:
1 / 0
except ZeroDivisionError:
print(1)
except ZeroDivisionError:
print(2)

source: The except clause may specify a variable after the exception name. The variable is bound to an exception instance with the arguments stored in instance.args.

source: print(type(inst))    # the exception instance

source: print(inst.args)     # arguments stored in .args

source: print(inst)          # __str__ allows args to be printed directly,

source: # but may be overridden in exception subclasses

source:
try:
raise NameError
except NameError:
print('oops')
raise

source:
x = 0 # 1
try:
#     1/x
raise ValueError()
except ZeroDivisionError:
print('handle')
finally:
print('run anyway')

source: If a finally clause is present, the finally clause will be executed as the last task before the try statement completes. The finally clause checks whether or not the try statement produces an exception. The following points explain some more complex cases when an exception occurs:

source: - If an exception occurs during the execution of the `try` clause, the exception may be handled by an `except` clause. If the exception is not handled by an `except` clause, the exception is re-raised after the `finally` clause has been executed.

source: - An exception could occur during the execution of an `except` or `else` clause. Again, the exception is re-raised after the `finally` clause has been executed.

source: - If the `try` statement reaches a `break`, `continue` or `return` statement, the `finally` clause will be executed just prior to the `break`, `continue` or `return` statement’s execution.

source: - If a `finally` clause includes a return statement, the `finally` clause’s return statement will be executed before, and instead of, the return statement in a try clause.

source:
def test():
try:
1/0
except ZeroDivisionError:
return 1
finally:
return 0

display_name: Python 3

python

file_extension: .py

mimetype: text/x-python

nbconvert_exporter: python


code:
Hello file world!
Script triggered from root folder


code:
Hello file world!
Script triggered from homework folder


code:
"""
Task 1

Files

Write a script that creates a new output file called myfile.txt and writes the string "Hello file world!" in it.
Then write another script that opens myfile.txt, and reads and prints its contents.
Run your two scripts from the system command line.

Does the new file show up in the directory where you ran your scripts?
- Yes
What if you add a different directory path to the filename passed to open?
- It will create or open a file in specified directory if it exists

Note: file write methods do not add newline characters to your strings; add an explicit ‘\n’ at the end of the
string if you want to fully terminate the line in the file.
"""
import os

directory_path = os.getcwd()
folder_name = os.path.basename(directory_path)

if folder_name == "Beetroot_20220728_PY_Ivan_Samchuk":
    # write to file
    with open("lesson_11_work_with_files_json/homework/myfile1.txt", "w") as file:
        file.write("Hello file world!\nScript triggered from root folder \n")
    # read file
    with open("lesson_11_work_with_files_json/homework/myfile1.txt") as file:
        print([text.rstrip() for text in file])

if folder_name == "homework":
    # write to file
    with open("myfile2.txt", "w") as file:
        file.write("Hello file world!\nScript triggered from homework folder \n")
    # read file
    with open("myfile2.txt") as file:
        print([text.rstrip() for text in file])


code:
"""
Task 2

Extend Phonebook application

Functionality of Phonebook application:

    Add new entries
    Search by first name
    Search by last name
    Search by full name
    Search by telephone number
    Search by city or state
    Delete a record for a given telephone number
    Update a record for a given telephone number
    An option to exit the program

The first argument to the application should be the name of the phonebook. Application should load JSON data, if it is
present in the folder with application, else raise an error. After the user exits, all data should be saved
to loaded JSON
"""

import json

def create_contact_dict(first_name, last_name, phone_number, city):
    contact_dict = {
        "firstname:": first_name,
        "lastname": last_name,
        "phone_number": phone_number,
        "city": city

    }
    return contact_dict

empty_contact = create_contact_dict("", "", "", "")

phonebook_name = input("Enter phonebook name: ")
with open(phonebook_name + ".json", "w") as phonebook:
    json.dump(empty_contact, phonebook)


code:
from pprint import pprint

with open("weekdays.txt") as file:
    weekdays = [day.rstrip() for day in file.readlines()]

pprint(weekdays)


code:
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday


code:
# hellohellohello____worldworldworld
print("hello" * 3, "world" * 3, sep="____")

# Python is amazing!
print("Python", "is", "amazing", sep=" ", end="!\n")


source: The Python interpreter has a number of built-in functions and types that are always available. In this lesson, we will discuss in depth the `print` function and also mention the `help` function.

source: print('Another line of code, which will be executed by python interpreter')

source: We can use `print` for any built-in data type

source: We can print a few values using `print` by passing arguments separated by commas.

source: We can pass an argument `sep` to print, which will be used as a separator for printing to stream or sys.stdout

source: By default every print ends with a special symbol `\n` - end of line, thus every print statement will be printed on a new line

source:
print('First line')
print('Second line')

source: We can change the default behavior by passing an argument to `end` in the print

source:
print('First Line', end=' ')
print('Second Line', end='\n\n\n')
print('Third Line', end='!')

source: For complete documentation of print you can use special instruction `help(print)` or as an alternative in Jupyter notebook - just type in cell `print?`

display_name: Python 3 (ipykernel)


stdout

text: The Zen of Python, by Tim Peters

text: Beautiful is better than ugly.

text: Explicit is better than implicit.

text: Simple is better than complex.

text: Complex is better than complicated.

text: Flat is better than nested.

text: Sparse is better than dense.

text: Readability counts.

text: Special cases aren't special enough to break the rules.

text: Although practicality beats purity.

text: Errors should never pass silently.

text: Unless explicitly silenced.

text: In the face of ambiguity, refuse the temptation to guess.

text: There should be one-- and preferably only one --obvious way to do it.

text: Although that way may not be obvious at first unless you're Dutch.

text: Now is better than never.

text: Although never is often better than *right* now.

text: If the implementation is hard to explain, it's a bad idea.

text: If the implementation is easy to explain, it may be a good idea.

text: Namespaces are one honking great idea -- let's do more of those!


code:
"""
Task 1 Make a program that has your name and the current day of the week stored as separate variables and then
prints a message like this "Good day <name>! <day> is a perfect day to learn some python."
"""
from datetime import datetime

name = str(input("Enter your name: "))
day = datetime.today().strftime('%A')
print(f"Good day {name}! {day} is a perfect day to learn some python.")

"""
Task 2
Save your first and last name as separate variables, then use string concatenation to add them together with a
white space in between and print a greeting.
"""
first_name = "Ivan"
last_name = "Samchuk"
print(first_name, last_name, sep=" ")
print(first_name + " " + last_name)
print(f"{first_name} {last_name}")
print("{1} {0}".format(last_name, first_name))

"""
Task 3
Make a program with 2 numbers saved in separate variables a and b, then print the result for each of the following:

    Addition
    Subtraction
    Division
    Multiplication
    Exponent (Power)
    Modulus
    Floor division

"""
a = float(input("Enter a: "))
b = float(input("Enter b: "))
print("Add ", a + b)
print("Sub ", a - b)
print("Div ", a / b)
print("Mul ", a * b)
print("Pow ", a ** b)
print("Mod", a % b)
print("Flo", a // b)

"""
Task 4*
Зробіть форматування так щоб отримати ось таке

"000012 Василий 110110 32.10"

"""

print("{0:06d} {1} {2:b} {3:.2f}".format(12, "Василий", 54, 32.1))

"""
Task 5*
Спробуйте "зібрати" зі слова "Корован" слово "ворона"

print(s1[4]+s1[1]+s1[2] +... <-  можливий але не самий цікавий варіант.
"""
s1 = "Корован"
print(s1[4:0:-1]+s1[6:4:-1])


source: # Built-in data types: Integers and Floats

source: Python has two main built-in numeric types - int and float, which represent integers and floats respectively.

source: We can get the type of a python object by passing it to special built-in function `type`.

source:
print(1, type(1))
print(2.0, type(1.0))

source: We can use standard arithmetic operations +, -, *, /, ** (exponentiation) and modulo % with integer division //

source:
print(13 / 5)
print(type(12 / 4))

source: We can also change numbers from negative to positive and vice versa, using `-` for negation. As for `+` it leaves the number unchanged

source: To get the absolute value of a number we can use built-in function `abs`.

source: To transform an integer to a float and in reverse order, we can use built-in functions `int`, `float`.

source: As in math, we have arithmetic order in python. Here is an example by precedence (From lowest to highest): `+`, `-`, `*`, `/`, `//`, `%`, `-` (negation), `+` (unchanged), `abs`, `int`, `float`, `**`.

source: In case you have a very long statement, you can use brackets to be sure in the right order.

path: lesson_3_variables_and_datatypes/jupyter/Built-in types Int and Float.ipynb


source: Strings represent some amount of characters and in general represent texts. Strings can be created by using quotation marks: `'`, `"` and `"""`.

text:
ghghghghgh jfjjfjdfjdjf
jhdjfgdjfdfgj
gjjgghjhghg

source:
s = """ghghghghgh jfjjfjdfjdjf
jhdjfgdjfdfgj
gjjgghjhghg
"""
print(s)

text: hellohello

source:
s = 'hello\
hello'
print(s)

source:
s = 'hello, "New York"'
print(s)

source:
s = 'hello, \'New York\''
print(s)

source:
s = ''
type(s)

source: Every string has its length, which could be accessed by using built-in function: <b>len</b>

source:
print(len("foo "))
print(len("b"))
print(len(''))

source: We can concatenate strings using `+` instruction.

source: There are a bunch of methods associated with strings in Python (for now thinking about methods as special instructions/actions/operations which are bound to the object, in our case to a string; more information related to this subject will be given in the next lessons).

source: To count the number of specific characters in a string we can use `count`.

source:
s = s + ' world'
print(s)

source:
s = s.upper()
print(s)

source:
s = s.lower()
print(s)

source: We can also check whether a substring is part of a string using the `in` operator.

source:
print('he' in 'hello')
print('x' in 'hello')

source: print(hello_str.index('h')) # to get index of substring

source: As you can see, in python indexing starts from zero, thus the first element of a string is located at index 0. To access elements of the string by index we have to use `[ ]` .

source: print(hello_str[0], hello_str[1], hello_str[2], hello_str[3], hello_str[4], sep='')

source: An attempt to access an element of the string by index beyond the string length will raise an Error.

source: We can slice a string using `[ ]` `string[x: y]`, which will return a substring from index `x(inclusively)` to `y(exclusively)`

source: print(our_str[:6]) # as shortcut, if no first parameter has been passed slice will be from the begining of the string

source: print(our_str[6:]) # same for upper bound in slicing, if no paratemer passed slice to the end of the string

source: print(our_str[:]) # whole string as slice

source: There are several types of string formatting available in python. Let's look at some of them

source:
name = 'Batman'
super_power = 'Intellect'
enemy = 'Joker'

text: Superhero's name is Batman, his super power - INTELLECT, his enemy - Jo.

source: print(f'Superhero\'s name is {name}, his super power - {super_power.upper()}, his enemy - {enemy[:2]}.')

source: res = f'Superhero\'s name is {name}, his super power - {super_power.upper()}, his enemy - {enemy[:2]}.'

text/plain: "Superhero's name is Batman, his super power - INTELLECT, his enemy - Jo."

text: Super hero is Intellect, his super power is Batman.

source: s = 'Super hero is {}, his super power is {}.'

text: Superhero name is Joker, his super power - Intellect, his enemy - Batman

source: print('Superhero name is {1}, his super power - {0}, his enemy - {2}'.format(super_power, enemy, name))

text: Superhero name is Batman, his super power - Intellect, his enemy - Joker

source: print('Superhero name is %s, his super power - %s, his enemy - %s' % (name, super_power, enemy))

text: this is cool number 3

text: this is cool number 3.141593

text: this is cool number 3.14


source: You can use any word as the name for your variable except those, which are reserved by Python (`print`, `type` etc).

source: The variable name should start with a letter and/or an underscore and contain only letters, numbers, and underscores.

source: By convention variable names should start with lowercase letters splitted by an underscore to enhance readability.

source:
a = 1
print(a)

source:
a = 3
b = 5
print(a + b)

source:
a = "s"
print(a)

source:
a, b = 3, 5
c = a + b
print(c)

source:
my_name = 'Batman'
my_age = 33
print("My name:", my_name)
print("My age: ", my_age)

source:
x += 1
print(x)

source:
q = 2
q **= 3
print(q)


code:
"""
Task 1
Write a Python program to get a string made of the first 2 and the last 2 chars from a given string. If the
string length is less than 2, return instead of the empty string.
"""

"""
Task 2
The valid phone number program. Make a program that checks if a string is in the right format for a phone
number. The program should check that the string contains only numerical characters and is only 10 characters long.
Print a suitable message depending on the outcome of the string evaluation.
"""

"""
Task 3
The math quiz program.

Write a program that asks the answer for a mathematical expression, checks whether
the user is right or wrong, and then responds with a message accordingly.
"""

"""
Task 4
The name check.

Write a program that has a variable with your name stored (in lowercase) and then asks for your name as input. The
program should check if your input is equal to the stored name even if the given name has another case, e.g.,
if your input is “Anton” and the stored name is “anton”, it should return True
"""

"""
Вхідні дані для всіх завдань можна отримувати двома способами: функція input(), або аргументи програми sys.argv

Task 5*
Write a Python program to construct the following pattern, using a while loop

*
* *
* * *
* * * *
* * * * *
* * * *
* * *
* *
*

Плюс за можливість динамічно змінити максимальну кількість зірочок в одному рядку (в прикладі 5)

"""

"""
Task 6*

Write a python program, which sums all digits in a python string.

Examples, input - ‘1234’, output - 10
"""

"""
Task 7* Write a Python program that accepts a string and calculate the number of digits, letters and other
characters in the input string
"""


code:
"""
Task 1
Write a Python program to get a string made of the first 2 and the last 2 chars from a given string. If the
string length is less than 2, return instead of the empty string.
"""

input_string = input("Enter you string: ")
if len(input_string) < 2:
    print("")
else:
    print("{0}{1}".format(input_string[:2], input_string[-2:]))


code:
"""
Task 2
The valid phone number program.
Make a program that checks if a string is in the right format for a phone
number. The program should check that the string contains only numerical characters and is only 10 characters long.
Print a suitable message depending on the outcome of the string evaluation.
"""
input_number = input("Enter phone number: ")

if len(input_number) != 10:
    print("Entered number's length is less than 10 characters")
elif not input_number.isdigit():
    print("Entered number contain not only numerical characters")
else:
    print("You entered a valid phone number")


code:
"""
Task 3
The math quiz program.

Write a program that asks the answer for a mathematical expression, checks whether
the user is right or wrong, and then responds with a message accordingly.
"""
from random import randint
random_numer_1 = randint(0, 10)
random_numer_2 = randint(0, 10)
answer = ""
correct_answer = random_numer_1 + random_numer_2
while answer == "":
    answer = input(f"Enter correct answer {0} + {1} = ".format(random_numer_1, random_numer_2))
if int(answer) == correct_answer:
    print("You're right")
else:
    print(f"You're wrong, correct answer is {correct_answer}")


code:
"""
Task 4

The name check.

Write a program that has a variable with your name stored (in lowercase) and then asks for your name as input. The program should check if your input is equal
to the stored name even if the given name has another case, e.g.,
if your input is “Anton” and the stored name is “anton”, it should return True
"""

NAME = "Ivan"
entered_name = input("Enter correct name: ")
if NAME.lower() == entered_name.lower().strip():
    print("True")


code:
"""
Task 5*
Write a Python program to construct the following pattern, using a while loop

*
* *
* * *
* * * *
* * * * *
* * * *
* * *
* *
*

Плюс за можливість динамічно змінити максимальну кількість зірочок в одному рядку (в прикладі 5)

"""

triangle_max_size = int(input("Enter pyramid size: "))

current_row = 1
while current_row < triangle_max_size + 1:
    print("*" * current_row)
    current_row += 1

current_row = triangle_max_size - 1
while current_row > 0:
    print("*" * current_row)
    current_row -= 1


code:
"""
Task 6*

Write a python program, which sums all digits in a python string.

Examples, input - `1234`, output - 10
"""

entered_int = input("Enter your number: ")
i = 0
sum = 0
while i != len(entered_int):
    sum += int(entered_int[i])
    i += 1
print(sum)


code:
"""
Task 1

The Guessing Game.

Write a program that generates a random number between 1 and 10 and lets the user guess what number was generated.
The result should be sent back to the user via a print statement.
"""
from random import randint
random_number = randint(1,10)
entered_number = int(input("Guess a number from 1 to 10: "))
if random_number == entered_number:
    print("you guessed the number")
else:
    print(f"No. Correct number is {random_number}")


code:
"""
Task 2

The birthday greeting program.

Write a program that takes your name as input, and then your age as input and greets you with the following:

“Hello <name>, on your next birthday you`ll be <age+1> years”
"""
entered_name = input("Enter your name: ")
entered_age = int(input("Enter your age: "))
print(f"Hello {entered_name}, on your next birthday you`ll be {entered_age+1} years")


code:
"""
Task 3

Words combination

Create a program that reads an input string and then creates and prints 5 random strings from characters of the input string.

For example, the program obtained the word `hello`, so it should print 5 random strings(words) that combine characters

'h', 'e', 'l', 'l', 'o' -> 'hlelo', 'olelh', 'loleh' …

Tips: Use random module to get random char from string)
"""
from random import randint

def random_string(entered_string):
    new_string = ""
    while len(entered_string) > 0:
        random_index = randint(0, len(entered_string)-1)
        new_string += entered_string[random_index]
        entered_string = entered_string[:random_index] + entered_string[random_index+1:]
    return(new_string)

n = 0
entered_string = input("Enter your string: ")
while n < 5:
    print(random_string(entered_string))
    n += 1

# Improvement comment - use random.shuffle() method


text: Help on method raw_input in module ipykernel.kernelbase:

text: raw_input(prompt='') method of ipykernel.ipkernel.IPythonKernel instance

text: Forward raw_input to frontends

text: Raises

text: StdinNotImplentedError if active frontend doesn't support stdin.

text: Give me smt: hello

text: Give me smt: 123

text: Give me some int pls: 123

text: <class 'str'>

source: print(num) print(type(num))

text:
Give me some int pls: 1234
1234
<class 'int'>
Thank you

source: num = int(input("Give me some int pls: "))


code:
import random

def get_deck():
    suits = ("♣","♠","♥","♦")
    cards = ("6","7","8","9","10","Jack","Queen","King","Ace")
    weight = (6,7,8,9,10,2,3,4,11)
    deck = []
    for suit in suits:
        for idx, name in enumerate(cards):
            card_weight = weight[idx]
            deck.append((card_weight, suit, name))
    return(deck)

game_deck = get_deck()
random.shuffle(game_deck)
print(game_deck)

def want_play():
    ...


code:
"""
Task 1

The greatest number

Write a Python program to get the largest number from a list of random numbers with the length of 10

Constraints: use only while loop and random module to generate numbers
"""

from random import randint

random_generated_list = []

min_range = ""
max_range = ""

while not min_range.isdigit() or not max_range.isdigit():
    min_range = input("Input min range value: ").strip()
    max_range = input("Input max range value: ").strip()

min_range = int(min_range)
max_range = int(max_range)

while len(random_generated_list) < 10:
    random_generated_list.append(randint(min_range,max_range))
print(random_generated_list)
print(max(random_generated_list))


code:
"""
Task 2

Exclusive common numbers.

Generate 2 lists with the length of 10 with random integers from 1 to 10, and make a third list containing the common
integers between the 2 initial lists without any duplicates.

Constraints: use only while loop and random module to generate numbers
"""
from random import randint
LENGTH = 10
list_1 = []
list_2 = []
list_3 = []
for i in range(LENGTH):
    list_1.append(randint(1, LENGTH))
    list_2.append(randint(1, LENGTH))
print(list_1)
print(list_2)
for item in list_1:
    if item in list_2:
        list_3.append(item)
print(list_3)
print(f"The common numbers list is: {list(set(list_3))}")


code:
"""
Task 3

Extracting numbers.

Make a list that contains all integers from 1 to 100, then find all integers from the list that are divisible by 7
but not a multiple of 5, and store them in a separate list. Finally, print the list.

Constraint: use only while loop for iteration
"""
integers_list = []
final_integers_list = []
i = 1
while i <= 100:
    integers_list.append(i)
    i += 1
print(integers_list)
j = 0
while j < len(integers_list):
    if integers_list[j] % 5 != 0 and integers_list[j] % 7 == 0:
        final_integers_list.append(integers_list[j])
    j += 1
print(final_integers_list)


source: There are three basic sequence types: `lists`, `tuples`, and `range` objects.

source: It is worth mentioning that `strings` are also a sequence type in Python.

source: Besides that, python also has unordered collections - `sets` and `dictionaries`.

source:
our_first_tuple = (1, 2, 3)
another_tuple = (1, '1', 3.0)

source: ## Common operations for lists and tuples

source:
print(x in our_first_list)
print(y in another_tuple)
print(x not in our_first_list)

source: print((0,) * 5) # pay attention, in order to init tuple with one element

source: print('Length of our list', len(our_first_list))

source: print('Max element in list', max(our_first_list))

source: print('Min element in list', min(our_first_list))

source: print('Number of 6 digits in list: ', test_list.count(6))

source: print('Index of first accurance of digit 3 in list: ', test_list.index(3))

source: In a nutshell, a mutable object can be changed after it is created, and an immutable object can’t.

source:
l.append([5, 6])
print(l)

source:
l.extend((8, 9))
print(l)

source:
x = l.pop()
print(l)

source:
l.insert(0, 1)
print(l)

source: `Ranges` implement all of the common sequence operations except concatenation and repetition (due to the fact that range objects can only represent sequences that follow a strict pattern, and repetition and concatenation would usually violate that pattern).

source:
r = range(10)
print(r[0])
print(list(r[1: 5]))

source:
range_len = 10
range_obj = range(range_len)
i = 0
t = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
while i < range_len:
print(range_obj[i], t[i])
i += 1

source: Python buil-in function `range()` and generated `range` objects are generally used to iterate over with for loop, which will be mentioned in future lesson about `for-in` loop

source:
l = [1,2,3,4]
for i in range(len(l)):
print(l[i])

source: A `set` object is an unordered collection of distinct objects.

source: Common uses include membership testing, removing duplicates from a sequence, and computing mathematical operations such as intersection, union, difference, and symmetric difference

source:
print(len(s))
print(s)
print(10 in s)

source:
for it in s:
print(it)

source: `set` operations in Python can be performed in two different ways: by operator or by method

source:
a = {1, 2, 3}
b = {3, 4}
print(a - b)
print((a - b) == a.difference(b))

source:
print(a | b)
print(a.union(b))
print((a & b) == (a.intersection(b)))

source: ## More about mutable/immutable objects and internal implementation of sequences

source:
x = x + (5,)
print(id(x), x)

source:
a = ['a', 'b', 'c']
b = a
print(a, b)
print(a == b)
print(id(a), id(b))

source:
b[0] = 'A'
print(a, b)

source:
print('sorted', sorted(x))
print('original', x)

source:
y = (10, 1.0, 4, 0, -5)
print(sorted(y), type(sorted(y)))
print(y)

source:
c = a.copy()
print(c)

source:
c[0] = 'GOOD'
print(c, a, sep='\n')

source: l = [1,3,4, ['hello', 'nested', 'list', [True, False]]]

source:
c = [True, False]
b = ['hello', 'nested', 'list', c]
a = [1,2,4, b]
print(a)

source:
new_a = a.copy()
c[0] = 'HELLO'
print(new_a)
print(a)


code:
"""
Task 1

Make a program that has some sentence (a string) on input and returns a dict
containing all unique words as keys and the number of occurrences as values.
"""

sentence = input("Enter your sentence: ")
words_list = list(sentence.split(' '))

words_dict = dict()
for word in words_list:
    if word in words_dict:
        words_dict[word] += 1
    else:
        words_dict[word] = 1
print(words_dict)


code:
"""
Task 2

Input data:

stock = {
    "banana": 6,
    "apple": 0,
    "orange": 32,
    "pear": 15
}
prices = {
    "banana": 4,
    "apple": 2,
    "orange": 1.5,
    "pear": 3
}

Compute the total price of the stock where the total price is the sum of the
price of an item multiplied by the quantity of this exact item.
"""

stock = {
    "banana": 6,
    "apple": 0,
    "orange": 32,
    "pear": 15,
    "eggs": 9,
    "potato": 0}
prices = {
    "banana": 4,
    "apple": 2,
    "orange": 1.5,
    "pear": 3,
    "potato": 10
}
intersection_keys = list(set(stock.keys()).intersection(prices))
sum = 0
for key in intersection_keys:
    sum += stock.get(key) * prices.get(key)
print(f"total price is {sum}")


code:
"""
Task 3

List comprehension exercise

Use a list comprehension to make a list containing tuples (i, j)
where `i` goes from 1 to 10 and `j` is corresponding to `i` squared.
"""
print([(i, i*i) for i in range(1, 11)])


code:
"""
Task 4

    Створити лист із днями тижня.
    В один рядок (ну або як завжди) створити словник виду: {1: “Monday”, 2:...
    Також в один рядок або як вдасться створити зворотний словник {“Monday”: 1,

"""
weekdays = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
weekdays_dict = dict([(i, weekdays[i - 1]) for i in range(1, len(weekdays) + 1)])
weekdays_dict_reversed = dict([(weekdays_dict.get(i), i) for i in range(1, len(weekdays) + 1)])

print(weekdays_dict)
print(weekdays_dict_reversed)


source:
i = 0
while i < len(a_list):
print(a_list[i])
i += 1

source:
for item in a_list:
print(item)

text:
0 1
1 2
2 3
3 4
4 5

source:
for ind, item in enumerate(a_list):
print(ind, item)

source:
for item in a_list:
if item == 2:
continue
print(item)

text: ok

source:
for item in a_list:
if item == 10:
break
print(item)
else:
print("ok")


source: `List comprehensions` provide a concise way to create lists. Common applications are used to make new lists where each element is the result of some operations applied to each member of another sequence or iterable, or to create a subsequence of those elements that satisfy a certain condition.

source:
squares = []
for x in range(10):
squares.append(x**2)

source: print('Varaible `x` still exists after loop', x)

source: squares = list(map(lambda x: x**2, range(10)))

source: A list comprehension consists of brackets containing an expression followed by a for clause, then zero or more for or if clauses. The result will be a new list resulting from evaluating the expression in the context of the for and if clauses which follow it. For example, this listcomp combines the elements of two lists if they are not equal:

source:
res = []
for x in [1,2,3]:
for y in [3,1,4]:
res.append((x, y))

source: The initial expression in a list comprehension can be any arbitrary expression, including another list comprehension, thus we can create nested list comprehensions

source: [[row[i] for row in matrix] for i in range(4)]

source:
transposed = []
for i in range(4):
transposed_row = []
for row in matrix:
transposed_row.append(row[i])
transposed.append(transposed_row)
transposed

source: x = {i ** 2 for i in range(10)} # set comp

source: x = {key: value for key in ['a', 'b', 'c'] for value in [1,2,3]} # dict comp

source: x = (i ** 3 for i in range(10)) # returns generator


source: Dictionaries are sometimes found in other languages as “associative memories” or “associative arrays”

source: Unlike sequences, which are indexed by a range of numbers, dictionaries are indexed by keys, which can be any immutable type; strings and numbers can always be keys. Tuples can be used as keys if they contain only strings, numbers, or tuples; if a tuple contains any mutable object either directly or indirectly, it cannot be used as a key

source:
a_list = []
a_dict = {}

source:
a_list = list()
a_dict = dict()

source: a_dict = {'hello': 'world', 'hello': 'world'}

text: {'hello': 'world'}

source:
a_dict = dict(
hello='world'
)

text: {'hello': 'world'}

traceback: KeyError                                  Traceback (most recent call last)

traceback:
<ipython-input-12-ea03f8443866> in <module>
----> 1 a_dict['hello1']

source:
x = a_dict.get('hello1', '1')
x

text: {'hello': 'world', 'hello1': 'world1'}

text: {'hello': 'WORLD', 'hello1': 'world1'}

text: {'hello': 'WORLD', 'hello1': 'world1', 1: 2}

traceback: KeyError                                  Traceback (most recent call last)

traceback:
<ipython-input-26-6f6d78b4f2fe> in <module>
----> 1 a_dict.pop(1)

text: {'hello': 'WORLD'}

text: WORLD

text: WORLD

source:
for value in a_dict.values():
print(value)

text: hello WORLD

source:
for key, value in a_dict.items():
print(key, value)


code:
import random

MAX_WIDTH = 8
MAX_HIGHT = 8
MINES = 10

mines_list = []
for i in range(0, MINES):
    mines_list.append((random.randint(0, MAX_WIDTH - 1),
                       random.randint(0, MAX_HIGHT - 1)))

print(mines_list)

user_session = []

while True:
    print(' ', [str(i) for i in range(MAX_WIDTH)], sep = ' ')
    for i in range(MAX_WIDTH):
        line = []
        for j in range(MAX_WIDTH):
            if (j, i) not in user_session:
                line.append('*')
            else:
                line.append(' ')
        print(i, line)

    input_value = input('Введіть координати x y: ')
    x, y = input_value.split()

    if not x.isdigit() or not y.isdigit():
        continue

    x, y = int(x), int(y)
    if (x, y) in mines_list:
        print("You lose")
        break

    user_session.append((x, y))


code:
"""
Task 1

A simple function.

Create a simple function called favorite_movie, which takes a string containing the name of your favorite movie. The
function should then print “My favorite movie is named {name}”.
"""

def favourite_movie(name):
    print(f"My favorite movie is named {name}")

if __name__ == "__main__":
    entered_name = input("Enter the name of your favourite movie: ")
    favourite_movie(entered_name)


code:
"""
Task 2

Creating a dictionary.

Create a function called make_country, which takes in a country’s name and capital as parameters. Then create a
dictionary from those two, with ‘name’ as a key and ‘capital’ as a parameter. Make the function print out the values
of the dictionary to make sure that it works as intended.
"""

def make_country(country_name, capital):
    country_dict = {country_name: capital}
    print(country_dict)

if __name__ == "__main__":
    entered_country = list(input("Enter country name and the capital: ").split(" "))
    make_country(entered_country[0], entered_country[1])


code:
"""
Task 3

A simple calculator.

Create a function called make_operation, which takes in a simple arithmetic operator as a first parameter (to keep
things simple let it only be ‘+’, ‘-’ or ‘*’) and an arbitrary number of arguments (only numbers) as the second
parameter. Then return the sum or product of all the numbers in the arbitrary parameter. For example:

    the call make_operation(‘+’, 7, 7, 2) should return 16
    the call make_operation(‘-’, 5, 5, -10, -20) should return 30
    the call make_operation(‘*’, 7, 6) should return 42
"""

def make_operation(operator, *args):
    if operator == "+":
        return sum(args)
    if operator == "*":
        result = 1
        for argument in args:
            result *= argument
        return result
    if operator == "-":
        result = args[0]
        for i in range(1, len(args)):
            result -= args[i]
        return result

if __name__ == "__main__":
    assert (make_operation("+", 7, 7, 2) == 16)
    assert (make_operation("-", 5, 5, -10, -20) == 30)
    assert (make_operation("*", 7, 6) == 42)


code:
"""
Task 4

Write a function that takes on an input random ints (between 1 and 10) and
returns the longest consecutive run and the length of that run of elements
of the list.

Ex.  def task1(1,2,3,4,4,4,4,4,4,5,6,7,4,2,2,5) -> 6, 4
 def task1(1) -> 1, 1
 def task1() -> 0, None

Then create another function which takes on input result of function from the previous step and prints Informative
message about the longest consecutive run, something like - “Longest run is 6 of integers - 4”
"""

# Порада - використовуй дебаг
# Порада - цей кейс розбирався в суботу 13 серпня
from random import randint

randint(1, 10)

def return_largest_run(*args):
    result_dict = {}
    temp_dict = {}
    count = 0
    for i in range(len(args)):
        current_number = args[i]
        # add first value in demp dict
        if not temp_dict:
            count += 1
            temp_dict[current_number] = count
            continue
        # generate temp dict
        if list(temp_dict.keys())[0] == current_number:
            count += 1
            temp_dict[current_number] = count
            continue
        if list(temp_dict.keys())[0] != current_number:
            if args[i - 1] not in result_dict or result_dict.get(args[i - 1]) < temp_dict.get(args[i - 1]):
                result_dict[args[i - 1]] = temp_dict.get(args[i - 1])
                count = 1
                temp_dict = {}
                temp_dict[current_number] = count
                continue

    print(temp_dict),
    print(result_dict)

if __name__ == "__main__":
    return_largest_run(1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 2, 2)


code:
"""
Task 5

Create a function that takes on an input random ints (between 1 and 10)
and returns the list, without duplicates.
Try to create two versions of this function - first with usage set
and list constructors and second only using for-in loops.

def task2(1,2,34,2,3,2,4) -> 1, 2, 34, 3, 4
"""


code:
from .module_2 import get_count_a, get_last_character, get_item_length

def word_statistic(word):
    print(
        f"The length or word \"{word}\" is {get_item_length(word)}, and last character is {get_last_character(word)} and count "
        f"of 'a' is {get_count_a(word)} !")


code:
def get_item_length(item):
    count = 0
    for _ in item:
        count += 1
    return count

def get_last_character(item):
    return item[-1]

def get_count_a(item):
    return item.count("a")

if __name__ == '__main__':
    print(get_item_length("Hello world"))
    print(get_last_character("abcde"))
    print(get_count_a("abade"))


code:
"""
Task 1

Imports practice

 Make a directory with 2 modules; make a function in one of them; then import this function in the other module and
 use that in your script of choice. """
from directory_with_modules.module_1 import word_statistic

word_statistic("Hello world")
word_statistic("Aliens are here")
word_statistic("Ok, google!")


code:
"""
Task 2

The sys module.

 The “sys.path” list is initialized from the PYTHONPATH environment variable. Is it possible to change it from within
 Python? If so, does it affect where Python looks for module files? Run some interactive tests to find it out. """

import sys, os
from pprint import pprint

def main():
    print("There are a list of sys.path")
    print(f"Sys path length: {len(sys.path)}")
    pprint(sys.path)
    print("Now let's try to import module from task_1 folder")
    task_1_module_import()

    sys.path.append(os.path.abspath("task_1/directory_with_modules"))
    print("\nThere are enlarged list of sys.path")
    print(f"Sys path new length: {len(sys.path)}")
    pprint(sys.path)
    print("Now let's try to import module from task_1 folder")
    task_1_module_import()

def task_1_module_import():
    try:
        import module_2
        print("Module imported successfully")
    except:
        print("Module not imported")

if __name__ == '__main__':
    main()


code:
def count_lines(name) -> int:
    with open(name, 'r') as f:
        print(f"count of lines in file {name}: {len(f.readlines())}")

def count_chars(name) -> int:
    with open(name, 'r') as f:
        result = f.read().replace('\n', '')
        print(f"count of lines in file {name}: {len(result)}")

def test(name):
    count_lines(name)
    count_chars(name)

if __name__ == "__main__":
    test("test_file.txt")


code:
from mymod import test
test("test_file.txt")
test("text_file.txt")


code:
# fibonacci: 0, 1, 1, 2, 3, 5, 8, 13 ...

def fib(n):
    a, b = 0, 1
    for i in range(n):
        a, b = b, a + b
    return a

def main():
    print(fib(int(input("What fib do you want?: "))))

if __name__ == '__main__':
    main()


code:
from fibonacci import fib

print(f'The 12th fibonacci number is: {fib(12)}')


repo_name: icanrealizeum/videospeed


code:
# The science of accelerated playback

**TL;DR: faster playback translates to quick progress, better engagement, and retention.**

Average adult reads prose text at [250 to 300 words per minute](http://www.paperbecause.com/PIOP/files/f7/f7bb6bc5-2c4a-466f-9ae7-b483a2c0dca4.pdf) (wpm). By contrast, the average rate of speech for English speakers is ~150 wpm, with slide presentations often closer to 100 wpm. As a result, when given the choice, many viewers [speed up video playback to ~1.3~1.5 its recorded rate](http://research.microsoft.com/en-us/um/redmond/groups/coet/compression/chi99/paper.pdf) to compensate for the difference.

Many viewers report that [accelerated viewing keeps their attention longer](http://www.enounce.com/docs/BYUPaper020319.pdf): faster delivery keeps the viewer more engaged with the content. In fact, with a little training many end up watching videos at 2x+ the recorded speed. Some studies report that after being exposed to accelerated playback, [listeners become uncomfortable](http://xenia.media.mit.edu/~barons/html/avios92.html#beasleyalteredspeech) if they are forced to return to normal rate of presentation.

## Faster HTML5 Video

HTML5 video provides a native API to accelerate playback of any video. The problem is, many players either hide, or limit this functionality. For best results playback speed adjustments should be easy and frequent to match the pace and content being covered: we don't read at a fixed speed, and similarly, we need an easy way to accelerate the video, slow it down, and quickly rewind the last point to listen to it a few more times.

![Player](https://lh5.googleusercontent.com/ubqr74funulW1oj_SEDFQBpj_hE26j3aR5G9wfoAZlo1u029_vM9_tlV_f27AvTVWXcB2Hfy81I=s640)

#### *[Install Chrome Extension](https://chrome.google.com/webstore/detail/video-speed-controller/nffaoalbilbmmfgbnbgppjihopabppdk)*

Once the extension is installed simply navigate to any page that offers HTML5 video ([example](http://www.youtube.com/watch?v=E9FxNzv1Tr8)), and you'll see a speed indicator in top left corner. Hover over the indicator to reveal the controls to accelerate, slowdown, and quickly rewind or advance the video. Or, even better, simply use your keyboard:

* **S** - decrease playback speed.
* **D** - increase playback speed.
* **R** - reset playback speed.
* **Z** - rewind video by 10 seconds.
* **X** - advance video by 10 seconds.
* **V** - show/hide the controller.

Note that you can customize these shortcuts in the extension settings page. Also, a few tips for enabling and forcing HTML5 video:

 * YouTube: make sure you [enable the HTML5 opt-in experiment](http://www.youtube.com/html5).
 * If you're adventurous, try disabling the Flash plugin in Chrome in chrome://plugins/
 * If viewing a video on Wistia, right click to switch to HTML5 video, refresh the page, and the controls will appear.

### FAQ

**The video controls are not showing up?** This extension is only compatible with HTML5 video. If you don't see the controls showing up, chances are you are viewing a Flash video. If you want to confirm, try right-clicking on the video and inspect the menu: if it mentions flash, then that's the issue. That said, most sites will fallback to HTML5 if they detect that Flash it not available. You can try manually disabling Flash plugin in Chrome:

* In a new tab, navigate to `chrome://plugins`
* Disable "Adobe Flash Player"
* Restart your browser and try playing your video again

**The speed controls are not showing up for local videos?** To enable playback of local media (e.g. File > Open File), you need to grant additional permissions to the extension.

* In a new tab, navigate to `chrome://extensions`
* Find "Video Speed Controller" extension in the list and enable "Allow access to file URLs"
* Open a new tab and try opening a local file, the controls should show up

### License

(MIT License) - Copyright (c) 2014 Ilya Grigorik


code:
.vsc-hidden { display: none !important; }
.vsc-manual {
  visibility: visible !important;
  opacity: 1.0 !important;
}

/* Origin specific overrides */
/* YouTube player */
.ytp-hide-info-bar .vsc-controller {
  position: relative;
  top: 10px;
}

.ytp-autohide .vsc-controller {
  visibility: hidden;
  transition: opacity .25s cubic-bezier(0.4,0,0.2,1);
  opacity: 0;
}

.ytp-autohide .vcs-show {
  visibility: visible;
  opacity: 1.0;
}

/* YouTube embedded player */
/* e.g. https://www.igvita.com/2012/09/12/web-fonts-performance-making-pretty-fast/ */
.full-frame .html5-video-player:not(.ytp-fullscreen) .vsc-controller {
  position: relative;
  top: 45px;
}

.ytp-fullscreen .vsc-controller {
  display: block;
  position: relative;
  top: 60px;
}

/* shift controller on vine.co */
/* e.g. https://vine.co/v/OrJj39YlL57 */
.video-container .vine-video-container .vsc-controller {
  margin-left: 40px;
}

/* shift YT 3D controller down */
/* e.g. https://www.youtube.com/watch?v=erftYPflJzQ */
.ytp-webgl-spherical-control {
  top: 50px !important;
}

.ytp-fullscreen .ytp-webgl-spherical-control {
  top: 100px !important;
}

/* disable Vimeo video overlay */
div.video-wrapper + div.target {
  height: 0;
}

/* Fix black overlay on Kickstarter */
div.video-player.has_played.vertically_center:before, div.legacy-video-player.has_played.vertically_center:before {
  content: none !important;
}

/* Fix black overlay on openai.com */
.Shared-Video-player > .vsc-controller {
  height: 0;
}