Jump to content

[1.10.1+] Contract Configurator [v1.30.5] [2020-10-05]


nightingale

Recommended Posts

Do you know what this is about?


[ERR 22:41:03.918] ContractConfigurator.ContractType: CONTRACT_TYPE 'FS_Scraps': Error parsing validBodies

[EXC 22:41:03.919] DataStoreCastException: Cannot cast from CelestialBody to System.Collections.Generic.List`1[CelestialBody].
ContractConfigurator.ExpressionParser.ExpressionParser`1[CelestialBody].ParseList[CelestialBody] ()
Rethrow as TargetInvocationException: Exception has been thrown by the target of an invocation.
System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)
System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters)
ContractConfigurator.ExpressionParser.ExpressionParser`1[Contracts.Contract+ContractPrestige].ParseStatement[ContractPrestige] ()
Rethrow as DataStoreCastException: Cannot cast from CelestialBody to System.Collections.Generic.List`1[CelestialBody].
ContractConfigurator.ExpressionParser.ExpressionParser`1[Contracts.Contract+ContractPrestige].ParseStatement[ContractPrestige] ()
Rethrow as TargetInvocationException: Exception has been thrown by the target of an invocation.
System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)
System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters)
ContractConfigurator.ExpressionParser.ExpressionParser`1[CelestialBody].ParseStatement[CelestialBody] ()
Rethrow as DataStoreCastException: Cannot cast from CelestialBody to System.Collections.Generic.List`1[CelestialBody].
ContractConfigurator.ExpressionParser.ExpressionParser`1[CelestialBody].ParseStatement[CelestialBody] ()
Rethrow as Exception: Error parsing statement.
Error occurred near '*':
Prestige() == Trivial ? [ HomeWorld() ] : Prestige() == Significant ? @FieldResearch:l2Bodies.Random() : @FieldResearch:l3Bodies.Random()
.......................* <-- HERE
ContractConfigurator.ExpressionParser.ExpressionParser`1[T].ParseExpression (System.String key, System.String expression, ContractConfigurator.ExpressionParser.DataNode dataNode)
ContractConfigurator.ExpressionParser.ExpressionParser`1[T].ExecuteExpression (System.String key, System.String expression, ContractConfigurator.ExpressionParser.DataNode dataNode)
ContractConfigurator.ConfigNodeUtil.ParseSingleValue[CelestialBody] (System.String key, System.String stringValue, Boolean allowExpression)
System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)
Rethrow as TargetInvocationException: Exception has been thrown by the target of an invocation.
System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)
System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters)
ContractConfigurator.ConfigNodeUtil.ParseValue[List`1] (.ConfigNode configNode, System.String key, Boolean allowExpression)
UnityEngine.Debug:LogException(Exception)
ContractConfigurator.LoggingUtil:LogException(Exception)
ContractConfigurator.ConfigNodeUtil:ParseValue(ConfigNode, String, Action`1, IContractConfiguratorFactory, List`1, Func`2)
ContractConfigurator.ConfigNodeUtil:ParseValue(ConfigNode, String, Action`1, IContractConfiguratorFactory, Func`2)
ContractConfigurator.DeferredLoadUtil:ExecuteLoad(DeferredLoadObject`1)
System.Reflection.MethodBase:Invoke(Object, Object[])
ContractConfigurator.<UpdateNonDeterministicValuesIterator>d__10:MoveNext()
System.Linq.<CreateConcatIterator>c__Iterator1`1:MoveNext()
ContractConfigurator.<ContractGenerator>d__f:MoveNext()
ContractConfigurator.<ContractGenerator>d__2:MoveNext()
ContractConfigurator.ContractPreLoader:Update()

Link to comment
Share on other sites

Do you know what this is about?

<snip>

No idea. Raised [#313]

- - - Updated - - -

Really? I thought for sure it was RoverDude. Maybe it's that he has "Rover" in his name. :D

Yeah, was definitely Arsonide's FinePrint - I'm fairly certain RoverDude never touched contracts in a mod (although I guess the Asteroid Day thing counts).

Link to comment
Share on other sites

Okay I've got 2 questions for you, and no log file yet but I'll try to get one asap.

hidden and hideChildren don't seem to be working, or at least don't do what I expect. Given this code:


PARAMETER
{
type = VesselParameterGroup
title = Get the ENTIRE station on the ground. If a couple parts burn off or explode it shouldn't be a big deal, but we need at least ONE of every part the station started with.
hideChildren = true
PARAMETER
{
type = ReturnHome
hidden = true
}
PARAMETER
{
type = PartValidation
part = batteryBank
hidden = true
}
PARAMETER
{
type = PartValidation
part = advSasModule
hidden = true
}
... (and about 20 more)
}

Whether I have that hideChildren in there OR the hidden, the parameters show up in the contracts and look all ugly

not_hidden.jpg

I'm trying to make it just have what I wrote, which is Human for all the stuff that shows up below.

Second one, I'm spawning parts at random around KSC for a contract, and sometimes the part just doesn't show up. In the debug I'm not seeing anything related to making that part show up. I'm going through right now generating parts to get an example to upload a log, but KSP's fighting me at the moment.

Link to comment
Share on other sites

Okay I've got 2 questions for you, and no log file yet but I'll try to get one asap.

hidden and hideChildren don't seem to be working, or at least don't do what I expect. Given this code:


PARAMETER
{
type = VesselParameterGroup
title = Get the ENTIRE station on the ground. If a couple parts burn off or explode it shouldn't be a big deal, but we need at least ONE of every part the station started with.
hideChildren = true
PARAMETER
{
type = ReturnHome
hidden = true
}
PARAMETER
{
type = PartValidation
part = batteryBank
hidden = true
}
PARAMETER
{
type = PartValidation
part = advSasModule
hidden = true
}
... (and about 20 more)
}

Whether I have that hideChildren in there OR the hidden, the parameters show up in the contracts and look all ugly

http://pulpaudio.com/ksp/not_hidden.jpg

I'm trying to make it just have what I wrote, which is Human for all the stuff that shows up below.

Not sure why that's not working, you've got a pretty basic use case there. I'm just about to sign off for the night - mind copying this into a GitHub issue and I'll reproduce tomorrow?

Second one, I'm spawning parts at random around KSC for a contract, and sometimes the part just doesn't show up. In the debug I'm not seeing anything related to making that part show up. I'm going through right now generating parts to get an example to upload a log, but KSP's fighting me at the moment.

Is it tied to specific parts or random? It could perhaps be "under" KSC (which is actually floating 5-10 m above the terrain) - although you'd still see a vessel icon and see it in the tracking station in that case. Can't really think of anything else to ask on this one, but there's enough issues with Vessel spawning that it wouldn't surprise me if there's something weird going on.

Link to comment
Share on other sites

nightingale said:
Not sure why that's not working, you've got a pretty basic use case there. I'm just about to sign off for the night - mind copying this into a GitHub issue and I'll reproduce tomorrow?

Will do.

nightingale said:
Is it tied to specific parts or random? It could perhaps be "under" KSC (which is actually floating 5-10 m above the terrain) - although you'd still see a vessel icon and see it in the tracking station in that case. Can't really think of anything else to ask on this one, but there's enough issues with Vessel spawning that it wouldn't surprise me if there's something weird going on.

It's not tied to a part. I just successfully generated each part.

It's not the spawning under terrain thing, I've already had that problem and fixed it :D, and it doesn't happen every time. Maybe 1 out 10 or so. I've got the log file, there is a null ref in there:

 
NullReferenceException: Object reference not set to an instance of an object
  at ContractConfigurator.Behaviour.SpawnVessel.CreateVessels () [0x00000] in <filename unknown>:0 

Here's my current full contract pack that has both issues, so you don't have to set anything up. All you need to do is accept and then alt-f12 to complete the grabby car, and the other contracts will start showing up. To get the Kylab contract (which has the hidden/hidechildren stuff) you must also accept and complete the Old Lander contract.

[defunct site link removed by moderator]

Link to comment
Share on other sites

This may well be me, but I'm getting an unhandled exception:

Exception occured while attempt to generate contract of type 'SurfaceSample':
System.ArgumentNullException: Argument cannot be null.
Parameter name: source
at System.Linq.Check.SourceAndSelector (System.Object source, System.Object selector) [0x00000] in <filename unknown>:0
at System.Linq.Enumerable.Select[ScienceExperiment,String] (IEnumerable`1 source, System.Func`2 selector) [0x00000] in <filename unknown>:0
at ContractConfigurator.CollectScienceFactory.Generate (Contracts.Contract contract) [0x00000] in <filename unknown>:0
at ContractConfigurator.ParameterFactory.Generate (ContractConfigurator.ConfiguredContract contract, IContractParameterHost contractParamHost) [0x00000] in <filename unknown>:0
at ContractConfigurator.ParameterFactory.GenerateParameters (ContractConfigurator.ConfiguredContract contract, IContractParameterHost contractParamHost, System.Collections.Generic.List`1 paramFactories) [0x00000] in <filename unknown>:0
at ContractConfigurator.ParameterFactory.GenerateParameters (ContractConfigurator.ConfiguredContract contract, IContractParameterHost contractParamHost, System.Collections.Generic.List`1 paramFactories) [0x00000] in <filename unknown>:0
at ContractConfigurator.ContractType.GenerateParameters (ContractConfigurator.ConfiguredContract contract) [0x00000] in <filename unknown>:0
at ContractConfigurator.ConfiguredContract.Initialize (ContractConfigurator.ContractType contractType) [0x00000] in <filename unknown>:0

Looking at the debug log, the bit it doesn't like is:

	DATA
{
type = ScienceSubject
requiredValue = true
uniqueValue = true
experiment1 = AllScienceSubjectsByBiome([@biome1]).Where(s => s.Experiment() == surfaceSample && s.CollectedScience() <1).First()
}

The specific error in the log is "Cannot cast from ScienceSubject to ScienceExperiment" (but I don't think I'm trying to?)

It's probably an issue with my contract... basically, I'm trying to only make the contract ask for Surface Samples if the player hasn't already collected one from that biome.

Full contract: http://pastebin.com/SZQqmdzZ

Logs: https://www.dropbox.com/s/mpgy01ics7f4ja2/Logs.zip?dl=0:

Edit: I figured it out. The problem was further down, in the Parameters. I was using


experiment = @/experiment1

but I should have been using


subject = @/experiment1

Still... unhandled exception and all that. Could be handled a little more gracefully.

Edit the 2nd: And I think I found a real exception. I've just logged #315

Edited by severedsolo
Link to comment
Share on other sites

Bug fix release. Download now!

Contract Configurator 1.7.3

  • Added Round() function for rounding numeric values.
  • Contracts will now expire out of the pre-loader after a few Kerbin days. Help prevent contracts that may no longer be valid from being generated.
  • Fixed issue with hidden parameters not actually being hidden (thanks 5thHorseman).
  • Fixed issue with using subject with CollectScience (thanks severedsolo).
  • Fixed issue using Biome with uniqueValue in a DATA node (thanks severedsolo).
  • Fixed issue where disabling a contract pack doesn't save the fact that it is disabled (thanks Poodmund).

Link to comment
Share on other sites

Is it possible to have contracts target Biomes? I am thinking about starting a contract back that involves biome targeting. I just want to make sure that CC can target biomes.

The question is sort of vague, I'd recommend reading the wiki and asking more specific questions.

In general, there is some stuff you can do around biomes, mostly around science. Doll the answer is most likely yes. Other stuff that isn't there might be easy to add - all depends on what you're trying to do.

Link to comment
Share on other sites

Well, I am looking to add contracts that replace the default "Take visual surveys and crew reports on X area" with "Explore X biome."

For example instead of "Take a crew report at Area XYZ" it'll be "Explore the Far-side Crater of the Mun" or "Explore the Greater Flats of Minmus." I am hoping that these contracts will incentivize exploring all the biomes on the celestial bodies. I will check the wiki on it.

Link to comment
Share on other sites

Should be possible. ReachState supports a biome, so that covers a contract parameter for things like "Landed at the Mun's Highlands". You can get a list of biomes for a CelestialBody using the Biomes() method (eg. @targetBody.Biomes()). There's no way to tell which biomes a player has visited, aside from which biomes they've done science in. That gets a bit more complicated, but you can have a look at Field Research, it should have lots of examples that are pretty close to what you want.

Link to comment
Share on other sites

Hey there. I've got a question regarding modded contract packs in general. Let's say I completed one contract pack's contract progression (like Kerbin of Fire, for example), so new contracts are not showing up anymore (as it should happen). Would there be a way to force said contract progress to restart? I've tried simply removing the contract pack in question and reinstalling it, but that hasn't done the trick

Thanks!

Link to comment
Share on other sites

Hey there. I've got a question regarding modded contract packs in general. Let's say I completed one contract pack's contract progression (like Kerbin of Fire, for example), so new contracts are not showing up anymore (as it should happen). Would there be a way to force said contract progress to restart? I've tried simply removing the contract pack in question and reinstalling it, but that hasn't done the trick

Thanks!

There isn't a simple answer, as it depends how the contract pack does its progression logic. If it does it by contracts (you have to do contract A to get contract B), then you can clear all your completed contracts through the alt-f12 debug menu. If it uses any other mechanism (KSP internal progress tracking, "state" variables), then you need to do some save hackery, and you'd need to understand what the contract pack in question is doing to do it right.

Link to comment
Share on other sites

Ok, so changed all my contracts over to using type duration instead of VPG duration. Just tried to test a really simple setup and after the duration completes it reverts to non-completions if the next step negates the previous.

so for instance:

	PARAMETER
{
name = Orbit
type = VesselParameterGroup
title = Orbit @targetBody

PARAMETER
{
name = NewVessel
type = NewVessel
}

PARAMETER
{
name = HasCrew
type = HasCrew
minCrew = 1
}

PARAMETER
{
name = Orbit
type = Orbit
minPeA = @targetBody.AtmosphereAltitude() * 1.1
}

PARAMETER
{
name = Duration
type = Duration
duration = 1d

preWaitText = Orbiting for a day will provide us with some valuable data.
waitingText = One more day should do.
completionText = Excellent, this will be very helpful.
rewardFunds = 6250 / @targetBody.Multiplier()
rewardScience = 2 / @targetBody.Multiplier()
}

PARAMETER
{
name = ReturnHome
type = ReturnHome
}
}

I used to have this contract apply a simple 1d duration under the VPG. Trying to move everything over to type=duration instead.

But this isn't working how I thought it would. Is the issue that the ones before ReturnHome don't stay completed since return home is in the same VPG? I did try completeinsequence and disableonstatechange to no avail.

However, if I add another VPG then you are tied to the one vessel. Sorry if this is similar to other conversations we've had before. I haven't worked on this for a week or so, so I may be teading similar ground.

Link to comment
Share on other sites

Ok, so changed all my contracts over to using type duration instead of VPG duration. Just tried to test a really simple setup and after the duration completes it reverts to non-completions if the next step negates the previous.

so for instance:

<snip>

I used to have this contract apply a simple 1d duration under the VPG. Trying to move everything over to type=duration instead.

But this isn't working how I thought it would. Is the issue that the ones before ReturnHome don't stay completed since return home is in the same VPG? I did try completeinsequence and disableonstatechange to no avail.

However, if I add another VPG then you are tied to the one vessel. Sorry if this is similar to other conversations we've had before. I haven't worked on this for a week or so, so I may be teading similar ground.

I may have to go and document up some stuff around the Duration, as the recommended way to do this has changed (NathanKell came up with some more issues that needed a fix). So the recommendation for what you're trying to do would look like this:

    PARAMETER
{
name = Orbit
type = VesselParameterGroup
title = Orbit @targetBody

PARAMETER
{
name = NewVessel
type = NewVessel
}

PARAMETER
{
name = HasCrew
type = HasCrew
minCrew = 1
}

PARAMETER
{
name = Orbit
type = Orbit
minPeA = @targetBody.AtmosphereAltitude() * 1.1

PARAMETER
{
name = Duration
type = Duration
duration = 1d

preWaitText = Orbiting for a day will provide us with some valuable data.
waitingText = One more day should do.
completionText = Excellent, this will be very helpful.
rewardFunds = 6250 / @targetBody.Multiplier()
rewardScience = 2 / @targetBody.Multiplier()
}
}

PARAMETER
{
name = ReturnHome
type = ReturnHome

completeInSequence = true
}
}

Link to comment
Share on other sites

Ok, thanks. That was literally the one thing I hadn't tried yet. :) it was the next thing though...

Also, do you sleep with this thread open or something cuz you respond so insanely fast! :P

I check subscribed threads frequently (and I have a lot of subscriptions). :)

Link to comment
Share on other sites

I've got the following DATA node and it's working great. But I decided that I don't want this contract to fire more than once per planet.

So, this contract fires if you have reached a planet but not landed on. Issue is, for compatibility reasons I don't check whether it has been orbited or not. Technically you can complete this contract without landing on the body. If you do that the CB will still be a valid target. It also will continue to offer the contact for surfaceless bodies and that isn't ideal either.

Looking at data documentation I thought about adding uniqueValue = true but then I'm assuming if the player failed the contract it wouldn't fire for that planet.

Any thoughts on a "simple" way to do this?


DATA
{
type = CelestialBody
activeUniqueValue = true
validTarget = AllBodies().Where(cb => cb.SemiMajorAxis() < @/smamax && cb.SemiMajorAxis() > @/smamin && cb.IsPlanet() && cb.HaveReached() && cb.HaveLandedOn() == false && cb.IsHomeWorld() == false).Random()
}

Link to comment
Share on other sites

I've got the following DATA node and it's working great. But I decided that I don't want this contract to fire more than once per planet.

So, this contract fires if you have reached a planet but not landed on. Issue is, for compatibility reasons I don't check whether it has been orbited or not. Technically you can complete this contract without landing on the body. If you do that the CB will still be a valid target. It also will continue to offer the contact for surfaceless bodies and that isn't ideal either.

Looking at data documentation I thought about adding uniqueValue = true but then I'm assuming if the player failed the contract it wouldn't fire for that planet.

Any thoughts on a "simple" way to do this?


DATA
{
type = CelestialBody
activeUniqueValue = true
validTarget = AllBodies().Where(cb => cb.SemiMajorAxis() < @/smamax && cb.SemiMajorAxis() > @/smamin && cb.IsPlanet() && cb.HaveReached() && cb.HaveLandedOn() == false && cb.IsHomeWorld() == false).Random()
}

The expression behaviour changes that allow you to have any type (introduced in 1.7.x) will help you here. I'm thinking something like this:


// Track the bodies that this contract has been completed for
BEHAVIOUR
{
type = Expression

// The CONTRACT_COMPLETED_SUCCESS node gets executed when the
// contract is completed successfully.
CONTRACT_COMPLETED_SUCCESS
{
type = List<CelestialBody>

DummyList = [ @/targetBody ]
NoriContractCompletedBody = $DummyList.Concat($NoriContractCompletedBody)
}
}

// Add in an exclusion for anything where there contract has already been completed
DATA
{
type = CelestialBody
activeUniqueValue = true
validTarget = AllBodies().Where(cb => cb.SemiMajorAxis() < @/smamax && cb.SemiMajorAxis() > @/smamin && cb.IsPlanet() && cb.HaveReached() && cb.HaveLandedOn() == false && cb.IsHomeWorld() == false).[COLOR=#ff0000]ExcludeAll($NoriContractCompletedBody).[/COLOR]Random()
}

I haven't tested the above, so it may not work. :D

The reason I do stuff in a bit of a weird way is due to some parser limitations. If it hasn't initialized $NoriContractCompletedBody, it won't know what type it is, which means doing $NoriContractCompletedBody.Something() won't parse. There's a chance the way I did it above won't work either... but this way probably has the best odds.

Oh and a quick tip - if you seperate the validTarget into two (ie. break out a List<CelestialBody> called validTargets), you'll be able to see its list of bodies in the debug window - might help you in testing/debugging.

Link to comment
Share on other sites

Thanks. I'll try that out.

Lists confuse me :P ... Something like this then? Is the activeUniqueValue in the right spot?


DATA
{
type = CelestialBody
activeUniqueValue = true
validTarget = AllBodies().Where(cb => cb.SemiMajorAxis() < @/smamax && cb.SemiMajorAxis() > @/smamin && cb.IsPlanet() && cb.HaveReached() && cb.HaveLandedOn() == false && cb.IsHomeWorld() == false).Random()
}

DATA
{
type = List<CelestialBody>
validTargets = validTarget
}

I looked at some of your contracts and is there any reason why I couldn't do this instead?


targetBody = @/validTarget.Random()

DATA
{
type = List<CelestialBody>
activeUniqueValue = true
validTarget = AllBodies().Where(cb => cb.SemiMajorAxis() < @/smamax && cb.SemiMajorAxis() > @/smamin && cb.IsPlanet() && cb.HaveReached() && cb.HaveLandedOn() == false && cb.IsHomeWorld() == false)
}

If I am able to, could .ExcludeAll($NoriContractCompletedBody) still be added to the end?

Link to comment
Share on other sites

I may have to go and document up some stuff around the Duration, as the recommended way to do this has changed (NathanKell came up with some more issues that needed a fix). So the recommendation for what you're trying to do would look like this:

    PARAMETER
{
name = Orbit
type = VesselParameterGroup
title = Orbit @targetBody

PARAMETER
{
name = NewVessel
type = NewVessel
}

PARAMETER
{
name = HasCrew
type = HasCrew
minCrew = 1
}

PARAMETER
{
name = Orbit
type = Orbit
minPeA = @targetBody.AtmosphereAltitude() * 1.1

PARAMETER
{
name = Duration
type = Duration
duration = 1d

preWaitText = Orbiting for a day will provide us with some valuable data.
waitingText = One more day should do.
completionText = Excellent, this will be very helpful.
rewardFunds = 6250 / @targetBody.Multiplier()
rewardScience = 2 / @targetBody.Multiplier()
}
}

PARAMETER
{
name = ReturnHome
type = ReturnHome

completeInSequence = true
}
}

Just tested this out and unfortanetly it isn't working for me. The orbit parameter goes to not completed when I try to land.

Do I need to set a disableonstatechange = true for the Orbit parameter?

Link to comment
Share on other sites

Just tested this out and unfortanetly it isn't working for me. The orbit parameter goes to not completed when I try to land.

Do I need to set a disableonstatechange = true for the Orbit parameter?

Correct. I missed that the first time I looked at this one.

EDIT: Also, the Duration won't be optional in this set-up, but I don't think there is a way to have it optional without going back to the VesselParameterGroup (as we discussed a few pages back ;))

- - - Updated - - -

Thanks. I'll try that out.

Lists confuse me :P ... Something like this then? Is the activeUniqueValue in the right spot?


DATA
{
type = CelestialBody
activeUniqueValue = true
validTarget = AllBodies().Where(cb => cb.SemiMajorAxis() < @/smamax && cb.SemiMajorAxis() > @/smamin && cb.IsPlanet() && cb.HaveReached() && cb.HaveLandedOn() == false && cb.IsHomeWorld() == false).Random()
}

DATA
{
type = List<CelestialBody>
validTargets = validTarget
}

I looked at some of your contracts and is there any reason why I couldn't do this instead?


targetBody = @/validTarget.Random()

DATA
{
type = List<CelestialBody>
activeUniqueValue = true
validTarget = AllBodies().Where(cb => cb.SemiMajorAxis() < @/smamax && cb.SemiMajorAxis() > @/smamin && cb.IsPlanet() && cb.HaveReached() && cb.HaveLandedOn() == false && cb.IsHomeWorld() == false)
}

If I am able to, could .ExcludeAll($NoriContractCompletedBody) still be added to the end?

The first one is wrong, the second right. You can still add the ExcludeAll.

EDIT: To expand on this, you have it reversed (the List<> should feed into the single value). Basically exactly what you have in the second one.

Edited by nightingale
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...