Esempio n. 1
0
 public static void CreateKeyframe(SubstanceMaterialParams substanceMaterialParams, SubstanceAnimationParams animationParams, SubstanceToolParams substanceToolParams)
 {
     //UnityEditor.Undo.RegisterCompleteObjectUndo(new UnityEngine.Object[] { substanceMaterialParams.substance, substanceToolParams.currentSelection }, "Create Keyframe " + substanceMaterialParams.MaterialVariableKeyframeDictionaryList.Count().ToString());
     if (animationParams.keyFrameTimes.Count == 0)
     {
         substanceToolParams.DebugStrings.Add("Created Keyframe 1:");
         substanceMaterialParams.MaterialVariableKeyframeDictionaryList.Add(new MaterialVariableDictionaryHolder());
         substanceMaterialParams.MaterialVariableKeyframeList.Add(new MaterialVariableListHolder());
         SubstanceTweenStorageUtility.AddProceduralVariablesToList(substanceMaterialParams.MaterialVariableKeyframeList[0], substanceMaterialParams, animationParams, substanceToolParams);
         SubstanceTweenStorageUtility.AddProceduralVariablesToDictionary(substanceMaterialParams.MaterialVariableKeyframeDictionaryList[0], substanceMaterialParams, animationParams, substanceToolParams);
         animationParams.keyFrames++;
         animationParams.keyFrameTimes.Add(substanceMaterialParams.MaterialVariableKeyframeList[0].animationTime);
         animationParams.substanceCurve.AddKey(new Keyframe(substanceMaterialParams.MaterialVariableKeyframeList[0].animationTime, substanceMaterialParams.MaterialVariableKeyframeList[0].animationTime));
         UnityEditor.AnimationUtility.SetKeyLeftTangentMode(animationParams.substanceCurve, 0, UnityEditor.AnimationUtility.TangentMode.Linear);
         UnityEditor.AnimationUtility.SetKeyRightTangentMode(animationParams.substanceCurve, 0, UnityEditor.AnimationUtility.TangentMode.Linear);
     }
     else if (animationParams.keyFrameTimes.Count > 0)
     {
         for (int i = 0; i <= animationParams.keyFrameTimes.Count - 1; i++)
         {     // Goes through each key frame and checks if the keyframe that you are trying to create has the same number of parameters as the rest and if they all save Output parameters or not.
             if (substanceMaterialParams.saveOutputParameters && substanceMaterialParams.MaterialVariableKeyframeList[i].hasParametersWithoutRange == false)
             { //Subsance designer can export special properties like '$randomSeed' that can be saved. this checks if you selected to save those objects and turned it off later
                 UnityEditor.EditorUtility.DisplayDialog("Error", "Could not save keyframe because you are saving Parameters without a range however keyframe " + (i + 1) + " does " +
                                                         "not save these variables. To fix this uncheck \"Save Output Parameters\" on this frame and try again or check \"Save Output Parameters\" then select and overWrite on every other frame. ", "OK");
                 return;
             }
             if (!substanceMaterialParams.saveOutputParameters && substanceMaterialParams.MaterialVariableKeyframeList[i].hasParametersWithoutRange == true)
             {
                 UnityEditor.EditorUtility.DisplayDialog("Error", "Could not save keyframe because you are not saving Parameters without a range however keyframe " + i + " does " +
                                                         "save these variables. To fix this check \"Save Output Parameters\" on this frame and try again or uncheck \"Save Output Parameters\" then select and overWrite on every other frame. ", "OK");
                 return;
             }
         }
         substanceMaterialParams.MaterialVariableKeyframeList.Add(new MaterialVariableListHolder());
         substanceToolParams.DebugStrings.Add("Created KeyFrame: " + substanceMaterialParams.MaterialVariableKeyframeList.Count);
         substanceMaterialParams.MaterialVariableKeyframeDictionaryList.Add(new MaterialVariableDictionaryHolder());
         SubstanceTweenStorageUtility.AddProceduralVariablesToList(substanceMaterialParams.MaterialVariableKeyframeList[animationParams.keyFrames], substanceMaterialParams, animationParams, substanceToolParams);
         SubstanceTweenStorageUtility.AddProceduralVariablesToDictionary(substanceMaterialParams.MaterialVariableKeyframeDictionaryList[animationParams.keyFrames], substanceMaterialParams, animationParams, substanceToolParams);
         animationParams.keyFrameTimes.Add(substanceMaterialParams.MaterialVariableKeyframeList[animationParams.keyFrames].animationTime);
         animationParams.keyframeSum = 0;
         for (int i = 0; i < substanceMaterialParams.MaterialVariableKeyframeList.Count() - 1; i++)
         {
             animationParams.keyframeSum += substanceMaterialParams.MaterialVariableKeyframeList[i].animationTime;
         }
         animationParams.substanceCurve.AddKey(new Keyframe(animationParams.keyframeSum, animationParams.keyframeSum));
         if (animationParams.keyFrames > 0)
         {
             UnityEditor.AnimationUtility.SetKeyLeftTangentMode(animationParams.substanceCurve, animationParams.keyFrames, UnityEditor.AnimationUtility.TangentMode.Linear);
         }
         UnityEditor.AnimationUtility.SetKeyRightTangentMode(animationParams.substanceCurve, animationParams.keyFrames, UnityEditor.AnimationUtility.TangentMode.Linear);
         animationParams.keyFrames++;
     }
     animationParams.substanceCurveBackup.keys = animationParams.substanceCurve.keys;
     substanceToolParams.lastAction            = MethodBase.GetCurrentMethod().Name.ToString();
     SubstanceTweenAnimationUtility.CacheAnimatedProceduralVariables(substanceMaterialParams, animationParams);
     SubstanceTweenAnimationUtility.CalculateAnimationLength(substanceMaterialParams, animationParams);
 }
Esempio n. 2
0
 public static void AddDefaultMaterial(SubstanceMaterialParams substanceMaterialParams, SubstanceAnimationParams animationParams, SubstanceToolParams substanceToolParams, SubstanceDefaultMaterialParams substanceDefaultMaterialParams)
 {
     substanceDefaultMaterialParams.defaultSubstanceObjProperties.Add(new MaterialVariableListHolder());
     substanceDefaultMaterialParams.defaultSubstance = substanceMaterialParams.rend.sharedMaterial as ProceduralMaterial;
     substanceMaterialParams.materialVariables       = substanceMaterialParams.substance.GetProceduralPropertyDescriptions();
     substanceDefaultMaterialParams.defaultSubstanceObjProperties[animationParams.defaultSubstanceIndex].PropertyMaterialName = substanceDefaultMaterialParams.defaultSubstance.name;
     SubstanceTweenStorageUtility.AddProceduralVariablesToList(substanceDefaultMaterialParams.defaultSubstanceObjProperties[animationParams.defaultSubstanceIndex], substanceMaterialParams, animationParams, substanceToolParams);
     substanceDefaultMaterialParams.defaultSubstanceObjProperties[animationParams.defaultSubstanceIndex].MainTex       = substanceMaterialParams.MainTexOffset;
     substanceDefaultMaterialParams.defaultSubstanceObjProperties[animationParams.defaultSubstanceIndex].emissionColor = substanceMaterialParams.emissionInput;
     animationParams.defaultSubstanceIndex++;
 }
Esempio n. 3
0
    public static void InsertKeyframe(int index, SubstanceMaterialParams substanceMaterialParams, SubstanceAnimationParams animationParams, SubstanceToolParams substanceToolParams)
    {
        if (animationParams.keyFrameTimes.Count > 0)
        {
            for (int i = 0; i <= animationParams.keyFrameTimes.Count - 1; i++)
            {     // Goes through each key frame and checks if the keyframe that you are trying to create has the same number of parameters as the rest and if they all save Output parameters or not.
                if (substanceMaterialParams.saveOutputParameters && substanceMaterialParams.MaterialVariableKeyframeList[i].hasParametersWithoutRange == false)
                { //Substance designer can export special properties like '$randomSeed' that can be saved. this checks if you selected to save those objects and turned it off later
                    UnityEditor.EditorUtility.DisplayDialog("Error", "Could not save keyframe because you are saving Parameters without a range however keyframe " + (i + 1) + " does " +
                                                            "not save these variables. To fix this uncheck \"Save Output Parameters\" on this frame and try again or check \"Save Output Parameters\" then select and overWrite on every other frame. ", "OK");
                    return;
                }
                if (!substanceMaterialParams.saveOutputParameters && substanceMaterialParams.MaterialVariableKeyframeList[i].hasParametersWithoutRange == true)
                {
                    UnityEditor.EditorUtility.DisplayDialog("Error", "Could not save keyframe because you are not saving Parameters without a range however keyframe " + i + " does " +
                                                            "save these variables. To fix this check \"Save Output Parameters\" on this frame and try again or uncheck \"Save Output Parameters\" then select and overWrite on every other frame. ", "OK");
                    return;
                }
            }
            substanceMaterialParams.MaterialVariableKeyframeList.Insert(index, new MaterialVariableListHolder());
            substanceToolParams.DebugStrings.Add("Created KeyFrame: " + substanceMaterialParams.MaterialVariableKeyframeList.Count);
            substanceMaterialParams.MaterialVariableKeyframeDictionaryList.Insert(index, new MaterialVariableDictionaryHolder());
            SubstanceTweenStorageUtility.AddProceduralVariablesToList(substanceMaterialParams.MaterialVariableKeyframeList[index], substanceMaterialParams, animationParams, substanceToolParams);
            SubstanceTweenStorageUtility.AddProceduralVariablesToDictionary(substanceMaterialParams.MaterialVariableKeyframeDictionaryList[index], substanceMaterialParams, animationParams, substanceToolParams);
            animationParams.keyframeSum = 0;
            for (int i = 0; i < index; i++)
            {
                animationParams.keyframeSum += substanceMaterialParams.MaterialVariableKeyframeList[i].animationTime;
            }
            if (index >= 1)
            {
                substanceMaterialParams.MaterialVariableKeyframeList[index - 1].animationTime = animationParams.currentAnimationTime;
                animationParams.keyFrameTimes[index - 1] = animationParams.currentAnimationTime;
            }
            else
            {
                substanceMaterialParams.MaterialVariableKeyframeList[index - 1].animationTime = animationParams.currentAnimationTime;
                animationParams.keyFrameTimes[index - 1] = animationParams.currentAnimationTime;
            }
            substanceMaterialParams.MaterialVariableKeyframeList[index].animationTime = animationParams.keyframeSum - animationParams.animationTimeRestartEnd;
            animationParams.keyFrameTimes.Insert(index, animationParams.substanceCurve.keys[index + 1].time - animationParams.substanceCurve.keys[index].time); // note: change animation time if inserting keyframe

            animationParams.keyFrames++;
        }
        animationParams.substanceCurveBackup.keys = animationParams.substanceCurve.keys;
        SubstanceTweenAnimationUtility.CacheAnimatedProceduralVariables(substanceMaterialParams, animationParams);
        SubstanceTweenAnimationUtility.CalculateAnimationLength(substanceMaterialParams, animationParams);
    }
Esempio n. 4
0
 public static void OverWriteKeyframe(int index, SubstanceMaterialParams substanceMaterialParams, SubstanceAnimationParams animationParams, SubstanceToolParams substanceToolParams)// Overwrites a keyframe with the current procedural values
 {
     if (animationParams.keyFrameTimes.Count >= 1)
     {
         if (index >= 0)
         {
             substanceMaterialParams.MaterialVariableKeyframeList.Remove(substanceMaterialParams.MaterialVariableKeyframeList[index]);
             substanceMaterialParams.MaterialVariableKeyframeList.Insert(index, new MaterialVariableListHolder());
             SubstanceTweenStorageUtility.AddProceduralVariablesToList(substanceMaterialParams.MaterialVariableKeyframeList[index], substanceMaterialParams, animationParams, substanceToolParams);
             substanceMaterialParams.MaterialVariableKeyframeDictionaryList.Remove(substanceMaterialParams.MaterialVariableKeyframeDictionaryList[index]);
             substanceMaterialParams.MaterialVariableKeyframeDictionaryList.Insert(index, new MaterialVariableDictionaryHolder());
             SubstanceTweenStorageUtility.AddProceduralVariablesToDictionary(substanceMaterialParams.MaterialVariableKeyframeDictionaryList[index], substanceMaterialParams, animationParams, substanceToolParams);
             substanceToolParams.DebugStrings.Add("OverWrote Keyframe: " + (index + 1));
         }
     }
     animationParams.substanceCurveBackup.keys = animationParams.substanceCurve.keys;
     SubstanceTweenAnimationUtility.CacheAnimatedProceduralVariables(substanceMaterialParams, animationParams);
 }
Esempio n. 5
0
    public static void WriteJSON(SubstanceMaterialParams substanceMaterialParams, SubstanceAnimationParams animationParams, SubstanceToolParams substanceToolParams) //  Write current material variables to a JSON file
    {
        StreamWriter writer;
        var          path = EditorUtility.SaveFilePanel("Save JSON file", "", "", "json");

        if (path.Length != 0)
        {
            FileInfo fInfo = new FileInfo(path);
            AssetDatabase.Refresh();
            if (!fInfo.Exists)
            {
                writer = fInfo.CreateText();
            }
            else
            {
                writer = fInfo.CreateText(); Debug.Log("Overwriting File");
            }
            MaterialVariableListHolder jsonDescription = new MaterialVariableListHolder();//Creates empty list to be saved to a JSON file
            SubstanceTweenStorageUtility.AddProceduralVariablesToList(jsonDescription, substanceMaterialParams, animationParams, substanceToolParams);
            jsonDescription.PropertyMaterialName = substanceMaterialParams.substance.name;
            jsonDescription.emissionColor        = substanceMaterialParams.emissionInput;
            jsonDescription.MainTex = substanceMaterialParams.MainTexOffset;
            string json = JsonUtility.ToJson(jsonDescription);
            writer.Write(json);
            writer.Close();//Closes the Json writer
            substanceToolParams.DebugStrings.Add("-----------------------------------");
            substanceToolParams.DebugStrings.Add("Wrote JSON file to: " + fInfo + ", File has: ");
            substanceToolParams.DebugStrings.Add(jsonDescription.PropertyName.Count + " Total Properties ");
            substanceToolParams.DebugStrings.Add(jsonDescription.PropertyFloat.Count + " Float Properties");
            substanceToolParams.DebugStrings.Add(jsonDescription.PropertyColor.Count + " Color Properties");
            substanceToolParams.DebugStrings.Add(jsonDescription.PropertyVector4.Count + " Vector4 Properties");
            substanceToolParams.DebugStrings.Add(jsonDescription.PropertyVector3.Count + " Vector3 Properties");
            substanceToolParams.DebugStrings.Add(jsonDescription.PropertyVector2.Count + " Vector2 Properties");
            substanceToolParams.DebugStrings.Add(jsonDescription.PropertyEnum.Count + " Enum Properties");
            substanceToolParams.DebugStrings.Add(jsonDescription.PropertyBool.Count + " Boolean Properties");
            substanceToolParams.DebugStrings.Add(jsonDescription.myKeys.Count + " Keys");
            substanceToolParams.DebugStrings.Add(jsonDescription.myValues.Count + " Values");
            substanceToolParams.DebugStrings.Add("Material Name: " + jsonDescription.PropertyMaterialName);
            substanceToolParams.DebugStrings.Add("Substance Texture Size: " + substanceMaterialParams.substanceWidth + " " + substanceMaterialParams.substanceHeight);
            substanceToolParams.DebugStrings.Add("-----------------------------------");
        }
        substanceToolParams.lastAction = MethodBase.GetCurrentMethod().Name.ToString();
    }
Esempio n. 6
0
    public static void WriteXML(SubstanceMaterialParams substanceMaterialParams, SubstanceAnimationParams animationParams, SubstanceToolParams substanceToolParams) // Write current material variables to a XML file.
    {
        StreamWriter writer;
        var          path = EditorUtility.SaveFilePanel("Save XML file", "", "", "xml");

        if (path.Length != 0)
        {
            FileInfo fInfo = new FileInfo(path);
            AssetDatabase.Refresh();
            if (!fInfo.Exists)
            {
                writer = fInfo.CreateText();
            }
            else
            {
                writer = fInfo.CreateText(); Debug.Log("Overwriting File");
            }
            MaterialVariableListHolder xmlDescription = new MaterialVariableListHolder();                                                             //Creates empty list to be saved to a XMl file
            XmlSerializer serializer = new XmlSerializer(typeof(MaterialVariableListHolder));
            SubstanceTweenStorageUtility.AddProceduralVariablesToList(xmlDescription, substanceMaterialParams, animationParams, substanceToolParams); // Writes current variables to a list to be saved to a XML file
            xmlDescription.PropertyMaterialName = substanceMaterialParams.substance.name;
            xmlDescription.emissionColor        = substanceMaterialParams.emissionInput;
            xmlDescription.MainTex = substanceMaterialParams.MainTexOffset;
            serializer.Serialize(writer, xmlDescription); //Writes the xml file using the fileInfo and the list we want to write.
            writer.Close();                               //Closes the XML writer
            substanceToolParams.DebugStrings.Add("-----------------------------------");
            substanceToolParams.DebugStrings.Add("Wrote XML file to: " + fInfo + ", File has: ");
            substanceToolParams.DebugStrings.Add(xmlDescription.PropertyName.Count + " Total Properties ");
            substanceToolParams.DebugStrings.Add(xmlDescription.PropertyFloat.Count + " Float Properties");
            substanceToolParams.DebugStrings.Add(xmlDescription.PropertyColor.Count + " Color Properties");
            substanceToolParams.DebugStrings.Add(xmlDescription.PropertyVector4.Count + " Vector4 Properties");
            substanceToolParams.DebugStrings.Add(xmlDescription.PropertyVector3.Count + " Vector3 Properties");
            substanceToolParams.DebugStrings.Add(xmlDescription.PropertyVector2.Count + " Vector2 Properties");
            substanceToolParams.DebugStrings.Add(xmlDescription.PropertyEnum.Count + " Enum Properties");
            substanceToolParams.DebugStrings.Add(xmlDescription.PropertyBool.Count + " Boolean Properties");
            substanceToolParams.DebugStrings.Add(xmlDescription.myKeys.Count + " Keys");
            substanceToolParams.DebugStrings.Add(xmlDescription.myValues.Count + " Values");
            substanceToolParams.DebugStrings.Add("Material Name: " + xmlDescription.PropertyMaterialName);
            //DebugStrings.Add("Substance Texture Size: " + substanceWidth + " " + substanceHeight);
            substanceToolParams.DebugStrings.Add("-----------------------------------");
        }
        substanceToolParams.lastAction = MethodBase.GetCurrentMethod().Name.ToString();
    }
Esempio n. 7
0
    public static void ReadAllXML(SubstanceMaterialParams substanceMaterialParams, SubstanceAnimationParams animationParams, SubstanceToolParams substanceToolParams) // Read XML files and create keyframes from them.
    {
        var    serializer        = new XmlSerializer(typeof(MaterialVariableListHolder));
        string xmlReadFolderPath = EditorUtility.OpenFolderPanel("Load xml files from folder", "", ""); //Creates 'Open Folder' Dialog

        if (xmlReadFolderPath.Length != 0)
        {
            string[] xmlReadFiles = Directory.GetFiles(xmlReadFolderPath);//array of selected xml file paths
            if (xmlReadFiles.Count() > 0)
            {
                animationParams.keyFrames = animationParams.keyFrameTimes.Count();
                foreach (string xmlReadFile in xmlReadFiles) //for each xml file path in the list.
                {
                    if (xmlReadFile.EndsWith(".xml"))
                    {
                        var stream    = new FileStream(xmlReadFile, FileMode.Open);                   // defines how to use the file at the selected path
                        var container = serializer.Deserialize(stream) as MaterialVariableListHolder; //Puts current xml file into a list.
                                                                                                      //SubstanceTweenSetParameterUtility.SetProceduralVariablesFromList(container);//Sets current substance values from list
                        SubstanceTweenSetParameterUtility.SetProceduralVariablesFromList(container, substanceMaterialParams, animationParams, substanceToolParams);
                        substanceMaterialParams.MainTexOffset = container.MainTex;
                        Color xmlEmissionColor = new Color(0, 0, 0, 0);
                        xmlEmissionColor = container.emissionColor;
                        if (substanceMaterialParams.rend.sharedMaterial.HasProperty("_EmissionColor"))
                        {
                            substanceMaterialParams.emissionInput = xmlEmissionColor;
                            if (substanceToolParams.selectedPrefabScript)
                            {
                                substanceToolParams.selectedPrefabScript.emissionInput = substanceMaterialParams.emissionInput;
                            }
                            substanceMaterialParams.rend.sharedMaterial.SetColor("_EmissionColor", xmlEmissionColor);
                        }
                        stream.Close();                               //Close Xml reader
                        substanceMaterialParams.substance.RebuildTexturesImmediately();
                        if (animationParams.keyFrameTimes.Count == 0) // Create keyframe from list containing XML variables
                        {
                            if (animationParams.substanceCurve.keys.Count() > 0)
                            {
                                animationParams.substanceCurve.RemoveKey(0);
                                animationParams.substanceCurve.AddKey(0, 0);
                            }
                            substanceMaterialParams.MaterialVariableKeyframeDictionaryList.Add(new MaterialVariableDictionaryHolder());
                            substanceMaterialParams.MaterialVariableKeyframeList.Add(new MaterialVariableListHolder());
                            substanceMaterialParams.MaterialVariableKeyframeList[0] = container;
                            SubstanceTweenStorageUtility.AddProceduralVariablesToDictionary(substanceMaterialParams.MaterialVariableKeyframeDictionaryList[0], substanceMaterialParams, animationParams, substanceToolParams);
                            animationParams.keyFrames++;
                            animationParams.keyFrameTimes.Add(substanceMaterialParams.MaterialVariableKeyframeList[0].animationTime);
                            AnimationUtility.SetKeyBroken(animationParams.substanceCurve, 0, true);
                            AnimationUtility.SetKeyLeftTangentMode(animationParams.substanceCurve, 0, AnimationUtility.TangentMode.Linear);
                            AnimationUtility.SetKeyRightTangentMode(animationParams.substanceCurve, 0, AnimationUtility.TangentMode.Linear);
                        }
                        else if (animationParams.keyFrameTimes.Count > 0)
                        {
                            substanceMaterialParams.MaterialVariableKeyframeList.Add(new MaterialVariableListHolder());
                            substanceMaterialParams.MaterialVariableKeyframeList[animationParams.keyFrames] = container;
                            substanceMaterialParams.MaterialVariableKeyframeDictionaryList.Add(new MaterialVariableDictionaryHolder());
                            substanceMaterialParams.MaterialVariableKeyframeDictionaryList[animationParams.keyFrames] = new MaterialVariableDictionaryHolder();
                            SubstanceTweenStorageUtility.AddProceduralVariablesToDictionary(substanceMaterialParams.MaterialVariableKeyframeDictionaryList[animationParams.keyFrames], substanceMaterialParams, animationParams, substanceToolParams);
                            animationParams.keyFrameTimes.Add(container.animationTime);
                            animationParams.keyframeSum = 0;
                            for (int i = 0; i < substanceMaterialParams.MaterialVariableKeyframeList.Count() - 1; i++)
                            {
                                animationParams.keyframeSum += substanceMaterialParams.MaterialVariableKeyframeList[i].animationTime;
                            }
                            if (container.AnimationCurveKeyframeList.Count() >= 1)
                            {
                                animationParams.substanceCurve.AddKey(new Keyframe(animationParams.keyframeSum, animationParams.keyframeSum, container.AnimationCurveKeyframeList[0].inTangent, container.AnimationCurveKeyframeList[0].outTangent));
                            }
                            else
                            {
                                animationParams.substanceCurve.AddKey(new Keyframe(animationParams.keyframeSum, animationParams.keyframeSum));
                            }
                            if (animationParams.keyFrames >= 1)
                            {
                                AnimationUtility.SetKeyBroken(animationParams.substanceCurve, animationParams.keyFrames, true);
                            }
                            animationParams.keyFrames++;
                        }
                    }
                    substanceToolParams.DebugStrings.Add("Read keyframe from: " + xmlReadFile);
                }
                substanceToolParams.DebugStrings.Add(animationParams.keyFrames - 1 + " Keyframes created from XML files ");
                animationParams.substanceCurveBackup.keys = animationParams.substanceCurve.keys;
                substanceToolParams.lastAction            = MethodBase.GetCurrentMethod().Name.ToString();
            }
            else
            {
                EditorUtility.DisplayDialog("Empty Folder", "No Files were found in the selected folder", "Ok");
            }
            substanceToolParams.lastAction = MethodBase.GetCurrentMethod().Name.ToString();
            SubstanceTweenAnimationUtility.CacheAnimatedProceduralVariables(substanceMaterialParams, animationParams);
            SubstanceTweenAnimationUtility.CalculateAnimationLength(substanceMaterialParams, animationParams);
        }
    }