Example #1
0
void loadLocations(cJSON *node)
{
	int active;
	Location *l;

	if (node)
	{
		node = node->child;

		while (node)
		{
			l = malloc(sizeof(Location));
			memset(l, 0, sizeof(Location));
			battle.locationTail->next = l;
			battle.locationTail = l;

			STRNCPY(l->name, cJSON_GetObjectItem(node, "name")->valuestring, MAX_NAME_LENGTH);
			l->x = (cJSON_GetObjectItem(node, "x")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_WIDTH;
			l->y = (cJSON_GetObjectItem(node, "y")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_HEIGHT;
			l->size = cJSON_GetObjectItem(node, "size")->valueint;
			l->active = active = getJSONValue(node, "active", 1);

			l->x += (SCREEN_WIDTH / 2);
			l->y += (SCREEN_HEIGHT / 2);
			

			node = node->next;
		}
	}
}
Example #2
0
static void loadTrophyData(char *filename)
{
	cJSON *root, *node;
	char *text;
	Trophy *t, *tail;
	int count[TROPHY_MAX];

	SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Loading %s", filename);

	text = readFile(filename);
	root = cJSON_Parse(text);

	tail = &game.trophyHead;
	
	memset(count, 0, sizeof(int) * TROPHY_MAX);

	for (node = root->child ; node != NULL ; node = node->next)
	{
		if (cJSON_GetObjectItem(node, "id")->valuestring[0] != '_')
		{
			t = malloc(sizeof(Trophy));
			memset(t, 0, sizeof(Trophy));

			STRNCPY(t->id, cJSON_GetObjectItem(node, "id")->valuestring, MAX_NAME_LENGTH);
			STRNCPY(t->title, _(cJSON_GetObjectItem(node, "title")->valuestring), MAX_DESCRIPTION_LENGTH);
			STRNCPY(t->description, _(cJSON_GetObjectItem(node, "description")->valuestring), MAX_DESCRIPTION_LENGTH);
			t->value = lookup(cJSON_GetObjectItem(node, "value")->valuestring);
			t->hidden = getJSONValue(node, "hidden", 0);
			
			t->stat = -1;
			
			/* can't use the getJSONValue here, as it could lead to false positives */
			if (cJSON_GetObjectItem(node, "stat"))
			{
				t->stat = lookup(cJSON_GetObjectItem(node, "stat")->valuestring);
				t->statValue = cJSON_GetObjectItem(node, "statValue")->valueint;
			}
			
			count[t->value]++;
			count[TROPHY_UNEARNED]++;

			tail->next = t;
			tail = t;
		}
	}
	
	SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Trophies (%d) [Bronze=%d, Silver=%d, Gold=%d, Platinum=%d]", count[TROPHY_UNEARNED], count[TROPHY_BRONZE], count[TROPHY_SILVER], count[TROPHY_GOLD], count[TROPHY_PLATINUM]);

	cJSON_Delete(root);
	free(text);
}
Example #3
0
static void loadGuns(Entity *parent, cJSON *guns)
{
	Entity *e;
	cJSON *gun;

	if (guns)
	{
		gun = guns->child;

		while (gun)
		{
			e = malloc(sizeof(Entity));
			memset(e, 0, sizeof(Entity));
			defTail->next = e;
			defTail = e;

			e->active = 1;

			e->type = ET_COMPONENT_GUN;
			e->health = e->maxHealth = cJSON_GetObjectItem(gun, "health")->valueint;
			e->reloadTime = cJSON_GetObjectItem(gun, "reloadTime")->valueint;
			e->offsetX = cJSON_GetObjectItem(gun, "x")->valueint;
			e->offsetY = cJSON_GetObjectItem(gun, "y")->valueint;
			e->texture = getTexture(cJSON_GetObjectItem(gun, "texture")->valuestring);
			e->guns[0].type = lookup(cJSON_GetObjectItem(gun, "type")->valuestring);
			e->missiles = getJSONValue(gun, "missiles", 0);

			if (cJSON_GetObjectItem(gun, "flags"))
			{
				e->flags = flagsToLong(cJSON_GetObjectItem(gun, "flags")->valuestring, NULL);
			}

			if (cJSON_GetObjectItem(gun, "aiFlags"))
			{
				e->aiFlags = flagsToLong(cJSON_GetObjectItem(gun, "aiFlags")->valuestring, NULL);
			}

			SDL_QueryTexture(e->texture, NULL, NULL, &e->w, &e->h);

			e->systemPower = MAX_SYSTEM_POWER;

			e->action = gunThink;
			e->die = gunDie;

			e->owner = parent;

			gun = gun->next;
		}
	}
}
Example #4
0
static bool storeMessage(char * line, size_t len)
{
    char *s, *e = 0, *e2;
    Message * m;
    int i, idx, k;
    int src, dst, prn = 0;
    Pgn * pgn;
    time_t now;
    char * key2 = 0;
    int valid;
    char value[16];

    now = time(0);

    logDebug("storeMessage(\"%s\",%u)\n", line, len);

    if (!strstr(line, "\"fields\":"))
    {
        logDebug("Ignore: pgn %u without fields\n", prn);
        return false;
    }
    if (memcmp(line, "{\"timestamp", 11) != 0)
    {
        logDebug("Ignore: no timestamp: '%s'\n", line);
        return false;
    }
    if (memcmp(line + len - 2, "}}", 2) != 0)
    {
        logDebug("Ignore: no line end: '%s'\n", line);
        return false;
    }

    if (getJSONValue(line, "src", value, sizeof(value)))
    {
        sscanf(value, "%d", &src);
    }

    if (getJSONValue(line, "dst", value, sizeof(value)))
    {
        sscanf(value, "%d", &dst);
    }

    if (getJSONValue(line, "pgn", value, sizeof(value)))
    {
        sscanf(value, "%d", &prn);
    }

    idx = PrnToIdx(prn);
    logDebug("src=%d dst=%d prn=%d idx=%d\n", src, dst, prn, idx);
    if (idx < 0)
    {
        logError("Ignore: prn %d: '%s'\n", prn, line);
        return false;
    }

    /* Look for a secondary key */
    for (k = 0; k < ARRAYSIZE(secondaryKeyList); k++)
    {
        s = strstr(line, secondaryKeyList[k]);
        if (s)
        {
            logDebug("Found 2nd key %d = %s\n", k, secondaryKeyList[k]);
            s += strlen(secondaryKeyList[k]);
            while (strchr(SKIP_CHARACTERS, *s))
            {
                s++;
            }

            e = strchr(s, ' ');
            e2 = strchr(s, '"');
            if (!e || e2 < e)
            {
                e = e2;
            }
            if (!e)
            {
                e = s + strlen(s);
            }
            if (e > s && e[-1] == ',')
            {
                e--;
            }
            key2 = malloc(e - s + 1);
            if (!key2)
            {
                logAbort("Out of memory allocating %u bytes", e - s);
            }
            memcpy(key2, s, e - s);
            key2[e - s] = 0;
            break;
        }
    }

    pgn = pgnIdx[idx];
    if (!pgn)
    {
        if (maxPgnList == ARRAYSIZE(pgnList))
        {
            logAbort("Too many PGNs\n");
        }

        pgn = calloc(1, sizeof(Pgn) + sizeof(Message));
        if (!pgn)
        {
            logAbort("Out of memory allocating %u bytes", sizeof(Pgn) + sizeof(Message));
        }
        pgnIdx[idx] = pgn;
        pgnList[maxPgnList++] = &pgnIdx[idx];
        logDebug("Storing new PGN %d in index %u\n", prn, idx);
    }

    if (!pgn->p_description)
    {
        pgn->p_prn = prn;
        s = strstr(line, "\"description\":");
        if (s)
        {
            s = s + sizeof("\"description\":");
            e = strchr(s, ':');
            e2 = strchr(s, '"');
            if (!e || e2 < e)
            {
                e = e2;
            }
            if (!e)
            {
                logDebug("Cannot find end of description in %s\n", s);
                return false;
            }
            logDebug("New PGN '%.*s'\n", e - s, s);
            pgn->p_description = malloc(e - s + 1);
            if (!pgn->p_description)
            {
                logAbort("Out of memory allocating %u bytes", e - s);
            }
            memcpy(pgn->p_description, s, e - s);
            pgn->p_description[e - s] = 0;
        }
    }

    /* Find existing key */
    for (i = 0; i < pgn->p_maxSrc; i++)
    {
        if (pgn->p_message[i].m_src == src)
        {
            if (pgn->p_message[i].m_key2)
            {
                if (key2 && strcmp(pgn->p_message[i].m_key2, key2) == 0)
                {
                    break;
                }
            }
            else
            {
                break;
            }
        }
    }

    /* Reuse expired key ? */
    if (i == pgn->p_maxSrc)
    {
        for (i = 0; i < pgn->p_maxSrc; i++)
        {
            if (pgn->p_message[i].m_time < now)
            {
                pgn->p_message[i].m_src = (uint8_t) src;
                if (pgn->p_message[i].m_key2)
                {
                    free(pgn->p_message[i].m_key2);
                }
                pgn->p_message[i].m_key2 = key2;
                key2 = 0;
                break;
            }
        }
    }

    /* Create new key */
    if (i == pgn->p_maxSrc)
    {
        size_t newSize;

        pgn->p_maxSrc++;
        newSize = sizeof(Pgn) + pgn->p_maxSrc * sizeof(Message);
        pgn = realloc(pgnIdx[idx], newSize);
        if (!pgn)
        {
            logAbort("Out of memory allocating %u bytes", newSize);
        }
        pgnIdx[idx] = pgn;
        pgn->p_message[i].m_src = (uint8_t) src;
        pgn->p_message[i].m_key2 = key2;
        key2 = 0;
        pgn->p_message[i].m_text = 0;
    }

    m = &pgn->p_message[i];
    if (m->m_text)
    {
        m->m_text = realloc(m->m_text, len + 2);
    }
    else
    {
        m->m_text = malloc(len + 2);
    }
    if (!m->m_text)
    {
        logAbort("Out of memory allocating %u bytes", len + 1);
    }
    memcpy(m->m_text, line, len);
    m->m_text[len] = '\n';
    m->m_text[len + 1] = 0;

    if (prn == 60928 || prn == 126996)
    {
        valid = CLAIM_TIMEOUT;
    }
    else if (prn == 130816)
    {
        valid = SONICHUB_TIMEOUT;
    }
    else
    {
        valid = secondaryKeyTimeout[k];
    }
    logDebug("stored prn %d timeout=%d 2ndKey=%d\n", prn, valid, k);
    if (key2)
    {
        free(key2);
    }
    m->m_time = now + valid;
    return true;
}
Example #5
0
void loadCapitalShips(cJSON *node)
{
	Entity *e;
	char **types, *name, *groupName, *type;
	int side, scatter, number, active;
	int i, numTypes, addFlags;
	long flags;
	float x, y;

	if (node)
	{
		node = node->child;

		while (node)
		{
			name = NULL;
			groupName = NULL;
			flags = -1;

			types = toTypeArray(cJSON_GetObjectItem(node, "types")->valuestring, &numTypes);
			side = lookup(cJSON_GetObjectItem(node, "side")->valuestring);
			x = (cJSON_GetObjectItem(node, "x")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_WIDTH;
			y = (cJSON_GetObjectItem(node, "y")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_HEIGHT;
			name = getJSONValueStr(node, "name", NULL);
			groupName = getJSONValueStr(node, "groupName", NULL);
			number = getJSONValue(node, "number", 1);
			scatter = getJSONValue(node, "scatter", 1);
			active = getJSONValue(node, "active", 1);

			if (cJSON_GetObjectItem(node, "flags"))
			{
				flags = flagsToLong(cJSON_GetObjectItem(node, "flags")->valuestring, &addFlags);
			}

			for (i = 0 ; i < number ; i++)
			{
				type = types[rand() % numTypes];

				e = spawnCapitalShip(type, x, y, side);

				if (scatter > 1)
				{
					e->x += (rand() % scatter) - (rand() % scatter);
					e->y += (rand() % scatter) - (rand() % scatter);
				}

				e->active = active;

				if (name)
				{
					STRNCPY(e->name, name, MAX_NAME_LENGTH);
				}

				if (groupName)
				{
					STRNCPY(e->groupName, groupName, MAX_NAME_LENGTH);
				}

				if (flags != -1)
				{
					if (addFlags)
					{
						e->flags |= flags;
					}
					else
					{
						e->flags = flags;

						SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, "Flags for '%s' (%s) replaced", e->name, e->defName);
					}
				}
				
				updateCapitalShipComponentProperties(e, flags);
				
				SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, "%s (%d / %d)", e->name, e->health, e->maxHealth);
			}

			node = node->next;

			for (i = 0 ; i < numTypes ; i++)
			{
				free(types[i]);
			}

			free(types);
		}
	}
}
Example #6
0
void loadFighters(cJSON *node)
{
	Entity *e;
	char **types, *name, *groupName, *type, *strpos;
	int side, scatter, number, active;
	int i, numTypes, addFlags, addAIFlags, id;
	long flags, aiFlags;
	float x, y;

	if (node)
	{
		id = 0;
		
		node = node->child;

		while (node)
		{
			name = NULL;
			groupName = NULL;
			flags = -1;
			aiFlags = -1;

			types = toTypeArray(cJSON_GetObjectItem(node, "types")->valuestring, &numTypes);
			side = lookup(cJSON_GetObjectItem(node, "side")->valuestring);
			x = (cJSON_GetObjectItem(node, "x")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_WIDTH;
			y = (cJSON_GetObjectItem(node, "y")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_HEIGHT;
			name = getJSONValueStr(node, "name", NULL);
			groupName = getJSONValueStr(node, "groupName", NULL);
			number = getJSONValue(node, "number", 1);
			scatter = getJSONValue(node, "scatter", 1);
			active = getJSONValue(node, "active", 1);

			if (cJSON_GetObjectItem(node, "flags"))
			{
				flags = flagsToLong(cJSON_GetObjectItem(node, "flags")->valuestring, &addFlags);
			}

			if (cJSON_GetObjectItem(node, "aiFlags"))
			{
				aiFlags = flagsToLong(cJSON_GetObjectItem(node, "aiFlags")->valuestring, &addAIFlags);
			}

			for (i = 0 ; i < number ; i++)
			{
				type = types[rand() % numTypes];

				e = spawnFighter(type, x, y, side);

				if (scatter > 1)
				{
					e->x += (rand() % scatter) - (rand() % scatter);
					e->y += (rand() % scatter) - (rand() % scatter);
				}

				e->active = active;

				if (flags != -1)
				{
					if (addFlags)
					{
						e->flags |= flags;
					}
					else
					{
						e->flags = flags;

						SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, "Flags for '%s' (%s) replaced", e->name, e->defName);
					}
					
					if (e->flags & EF_DISABLED)
					{
						e->speed = 0;
					}
				}

				if (aiFlags != -1)
				{
					if (addAIFlags)
					{
						e->aiFlags |= aiFlags;
					}
					else
					{
						e->aiFlags = aiFlags;

						SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, "AI Flags for '%s' (%s) replaced", e->name, e->defName);
					}
				}

				if (name)
				{
					STRNCPY(e->name, name, MAX_NAME_LENGTH);
					
					/* update 'name #?' to 'name #1', etc. */
					strpos = strstr(e->name, "#?");
					
					if (strpos)
					{
						*(++strpos) = ('0' + ++id);
					}
				}

				if (groupName)
				{
					STRNCPY(e->groupName, groupName, MAX_NAME_LENGTH);
				}
			}

			node = node->next;

			for (i = 0 ; i < numTypes ; i++)
			{
				free(types[i]);
			}

			free(types);
		}
	}
}
Example #7
0
static void loadFighterDef(char *filename)
{
	cJSON *root, *node;
	char *text;
	Entity *e;
	int i;

	SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Loading %s", filename);

	text = readFile(filename);

	root = cJSON_Parse(text);

	if (root)
	{
		e = malloc(sizeof(Entity));
		memset(e, 0, sizeof(Entity));
		defTail->next = e;
		defTail = e;

		e->type = ET_FIGHTER;
		e->active = 1;

		STRNCPY(e->name, cJSON_GetObjectItem(root, "name")->valuestring, MAX_NAME_LENGTH);
		STRNCPY(e->defName, e->name, MAX_NAME_LENGTH);
		e->health = e->maxHealth = cJSON_GetObjectItem(root, "health")->valueint;
		e->shield = e->maxShield = getJSONValue(root, "shield", 0);
		e->speed = cJSON_GetObjectItem(root, "speed")->valuedouble;
		e->reloadTime = getJSONValue(root, "reloadTime", 0);
		e->shieldRechargeRate = getJSONValue(root, "shieldRechargeRate", 0);
		e->texture = getTexture(cJSON_GetObjectItem(root, "texture")->valuestring);

		SDL_QueryTexture(e->texture, NULL, NULL, &e->w, &e->h);

		if (cJSON_GetObjectItem(root, "guns"))
		{
			i = 0;

			for (node = cJSON_GetObjectItem(root, "guns")->child ; node != NULL ; node = node->next)
			{
				e->guns[i].type = lookup(cJSON_GetObjectItem(node, "type")->valuestring);
				e->guns[i].x = cJSON_GetObjectItem(node, "x")->valueint;
				e->guns[i].y = cJSON_GetObjectItem(node, "y")->valueint;

				i++;

				if (i >= MAX_FIGHTER_GUNS)
				{
					printf("ERROR: cannot assign more than %d guns to a fighter\n", MAX_FIGHTER_GUNS);
					exit(1);
				}
			}

			e->combinedGuns = getJSONValue(root, "combinedGuns", 0);
		}

		e->selectedGunType = e->guns[0].type;

		e->missiles = getJSONValue(root, "missiles", 0);

		if (cJSON_GetObjectItem(root, "flags"))
		{
			e->flags = flagsToLong(cJSON_GetObjectItem(root, "flags")->valuestring, NULL);
		}

		if (cJSON_GetObjectItem(root, "aiFlags"))
		{
			e->aiFlags = flagsToLong(cJSON_GetObjectItem(root, "aiFlags")->valuestring, NULL);
		}

		if (cJSON_GetObjectItem(root, "deathType"))
		{
			e->deathType = lookup(cJSON_GetObjectItem(root, "deathType")->valuestring);
		}
		
		if (e->flags & EF_COMMON_FIGHTER)
		{
			addFighterStat(e->name);
		}

		e->separationRadius = MAX(e->w, e->h) * 3;

		e->systemPower = MAX_SYSTEM_POWER;

		cJSON_Delete(root);
	}
	else
	{
		SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, "Failed to load '%s'", filename);
	}

	free(text);
}
Example #8
0
RenderPass RenderStage::createRenderPassFromJson(const JSONValue& renderPassJSON)
{
    GraphicSystem& graphicSystem = renderer.getGraphicSystem();

    RenderPass renderPass;
    auto clearColorJSON = renderPassJSON.getJSONValue("clearColor");
    auto colorWriteJSON = renderPassJSON.getJSONValue("colorWrite");
    auto depthWriteJSON = renderPassJSON.getJSONValue("depthWrite");
    auto renderTargetLayerJSON = renderPassJSON.getJSONValue("renderTargetLayer");
    auto flagsJSON = renderPassJSON.getJSONValue("flags");

    if(!clearColorJSON.isNull())
        renderPass.clearColor = clearColorJSON.getVector4();
    if(!colorWriteJSON.isNull())
        renderPass.colorWrite = colorWriteJSON.getBool();
    if(!depthWriteJSON.isNull())
        renderPass.depthWrite = depthWriteJSON.getBool();
    if(!renderTargetLayerJSON.isNull())
        renderPass.renderTargetLayer = renderTargetLayerJSON.getInt();
    if(!flagsJSON.isNull())
    {
        unsigned int flags = 0;
        for(unsigned int i = 0; i < flagsJSON.getSize(); ++i)
        {
            if(flagsJSON.getJSONArrayItem(i).getString().compare("CLEAR_COLOR") == 0)
                flags |= CLEAR_COLOR;
            if(flagsJSON.getJSONArrayItem(i).getString().compare("CLEAR_DEPTH") == 0)
                flags |= CLEAR_DEPTH;
        }
        renderPass.flags = flags;
    }

    auto viewPortJSON = renderPassJSON.getJSONValue("viewPort");
    if(!viewPortJSON.isNull())
    {
        FixedArray<int, 4> viewPort = viewPortJSON.getInt4();
        renderPass.viewPort.set(viewPort[0], viewPort[1], viewPort[2], viewPort[3]);
    }
    else
        renderPass.viewPort = renderer.getScreenViewPort();

    auto renderTargetJSON = renderPassJSON.getJSONValue("renderTarget");
    renderPass.renderTarget = graphicSystem.createRenderTarget(renderTargetJSON);

    auto shaderPasses = renderPassJSON.getJSONValue("shaderPasses");

    if(!shaderPasses.isNull())
    {
        for(unsigned int i = 0; i < shaderPasses.getSize(); ++i)
        {
            auto shaderPassJSON = shaderPasses.getJSONArrayItem(i);
            auto programJSON = shaderPassJSON.getJSONValue("shaderProgram");
            auto vertexDataJSON = shaderPassJSON.getJSONValue("vertexData");
            auto rasterStateJSON = shaderPassJSON.getJSONValue("rasterState");
            auto shaderParameterBlocksJSON = shaderPassJSON.getJSONValue("shaderParameterBlocks");
            auto texturesJSON = shaderPassJSON.getJSONValue("textures");
            ShaderPass shaderPass;

            if(!vertexDataJSON.isNull())
            {
                if(vertexDataJSON.getString().compare("fullScreenQuad") == 0)
                    shaderPass.vertexData = renderer.getFullScreenQuad();
            }
            if(!rasterStateJSON.isNull())
            {
                auto blendFunctionJSON = rasterStateJSON.getJSONValue("blendFunction");
                auto compareFunctionJSON = rasterStateJSON.getJSONValue("compareFunction");
                auto cullFaceJSON = rasterStateJSON.getJSONValue("cullFace");
                auto blendState = !blendFunctionJSON.isNull() ? BlendState(true, enumFromString<BlendFunction>(blendFunctionJSON.getString())) : BlendState(false, BlendFunction::Replace);
                auto compareState = !compareFunctionJSON.isNull() ? CompareState(true, enumFromString<CompareFunction>(compareFunctionJSON.getString())) : CompareState(false, CompareFunction::Never);
                auto cullState = !cullFaceJSON.isNull() ? CullState(true, enumFromString<CullFace>(cullFaceJSON.getString())) : CullState(false, CullFace::Back);
                shaderPass.rasterState = RasterState(blendState, compareState, cullState);
            }

            if(!shaderParameterBlocksJSON.isNull())
            {
                for(unsigned int j = 0; j < shaderParameterBlocksJSON.getSize(); ++j)
                {
                    ShaderParameterBlock* block = graphicSystem.createShaderParameterBlock(shaderParameterBlocksJSON.getJSONArrayItem(j));
                    if(block)
                        shaderPass.shaderParameterBlocks.pushBack(block);
                }
            }
            if(!texturesJSON.isNull())
            {
                for(unsigned int j = 0; j < texturesJSON.getSize(); ++j)
                {
                    Texture* texture = graphicSystem.createTexture(texturesJSON.getJSONArrayItem(j));
                    if(texture)
                        shaderPass.textures.pushBack(texture);
                }
            }

            if(!programJSON.isNull())
                shaderPass.program = graphicSystem.createShaderProgram(programJSON);

            renderPass.shaderPasses.pushBack(shaderPass);
        }
    }
    return renderPass;
}