| 1 | using System; | 
 
 
 
 
 | 2 | using System.Collections.Generic; | 
 
 
 
 
 | 3 | using System.IO; | 
 
 
 
 
 | 4 | using System.Xml; | 
 
 
 
 
 | 5 | using Oni.Metadata; | 
 
 
 
 
 | 6 |  | 
 
 
 
 
 | 7 | namespace Oni.Totoro | 
 
 
 
 
 | 8 | { | 
 
 
 
 
 | 9 | internal class AnimationXmlWriter | 
 
 
 
 
 | 10 | { | 
 
 
 
 
 | 11 | private Animation animation; | 
 
 
 
 
 | 12 | private XmlWriter xml; | 
 
 
 
 
 | 13 | private string daeFileName; | 
 
 
 
 
 | 14 | private int startFrame; | 
 
 
 
 
 | 15 | private int endFrame; | 
 
 
 
 
 | 16 |  | 
 
 
 
 
 | 17 | private AnimationXmlWriter() | 
 
 
 
 
 | 18 | { | 
 
 
 
 
 | 19 | } | 
 
 
 
 
 | 20 |  | 
 
 
 
 
 | 21 | public static void Write(Animation animation, XmlWriter xml, string daeFileName, int startFrame, int endFrame) | 
 
 
 
 
 | 22 | { | 
 
 
 
 
 | 23 | var writer = new AnimationXmlWriter { | 
 
 
 
 
 | 24 | xml = xml, | 
 
 
 
 
 | 25 | animation = animation, | 
 
 
 
 
 | 26 | daeFileName = daeFileName, | 
 
 
 
 
 | 27 | startFrame = startFrame, | 
 
 
 
 
 | 28 | endFrame = endFrame | 
 
 
 
 
 | 29 | }; | 
 
 
 
 
 | 30 |  | 
 
 
 
 
 | 31 | writer.Write(); | 
 
 
 
 
 | 32 | } | 
 
 
 
 
 | 33 |  | 
 
 
 
 
 | 34 | private void Write() | 
 
 
 
 
 | 35 | { | 
 
 
 
 
 | 36 | xml.WriteStartElement("Animation"); | 
 
 
 
 
 | 37 |  | 
 
 
 
 
 | 38 | if (daeFileName != null) | 
 
 
 
 
 | 39 | { | 
 
 
 
 
 | 40 | xml.WriteStartElement("Import"); | 
 
 
 
 
 | 41 | xml.WriteAttributeString("Path", daeFileName); | 
 
 
 
 
 | 42 |  | 
 
 
 
 
 | 43 | if (startFrame > 0 || endFrame > 0) | 
 
 
 
 
 | 44 | xml.WriteElementString("Start", XmlConvert.ToString(startFrame)); | 
 
 
 
 
 | 45 |  | 
 
 
 
 
 | 46 | if (endFrame > 0) | 
 
 
 
 
 | 47 | xml.WriteElementString("End", XmlConvert.ToString(endFrame)); | 
 
 
 
 
 | 48 |  | 
 
 
 
 
 | 49 | xml.WriteEndElement(); | 
 
 
 
 
 | 50 | } | 
 
 
 
 
 | 51 |  | 
 
 
 
 
 | 52 | xml.WriteStartElement("Lookup"); | 
 
 
 
 
 | 53 | xml.WriteElementString("Type", animation.Type.ToString()); | 
 
 
 
 
 | 54 | xml.WriteElementString("AimingType", animation.AimingType.ToString()); | 
 
 
 
 
 | 55 | xml.WriteElementString("FromState", animation.FromState.ToString()); | 
 
 
 
 
 | 56 | xml.WriteElementString("ToState", animation.ToState.ToString()); | 
 
 
 
 
 | 57 | xml.WriteElementString("Varient", MetaEnum.ToString(animation.Varient)); | 
 
 
 
 
 | 58 | xml.WriteElementString("FirstLevel", XmlConvert.ToString(animation.FirstLevelAvailable)); | 
 
 
 
 
 | 59 | WriteRawArray("Shortcuts", animation.Shortcuts, Write); | 
 
 
 
 
 | 60 | xml.WriteEndElement(); | 
 
 
 
 
 | 61 |  | 
 
 
 
 
 | 62 | xml.WriteElementString("Flags", MetaEnum.ToString(animation.Flags)); | 
 
 
 
 
 | 63 |  | 
 
 
 
 
 | 64 | xml.WriteStartElement("Atomic"); | 
 
 
 
 
 | 65 | xml.WriteElementString("Start", XmlConvert.ToString(animation.AtomicStart)); | 
 
 
 
 
 | 66 | xml.WriteElementString("End", XmlConvert.ToString(animation.AtomicEnd)); | 
 
 
 
 
 | 67 | xml.WriteEndElement(); | 
 
 
 
 
 | 68 |  | 
 
 
 
 
 | 69 | xml.WriteStartElement("Invulnerable"); | 
 
 
 
 
 | 70 | xml.WriteElementString("Start", XmlConvert.ToString(animation.InvulnerableStart)); | 
 
 
 
 
 | 71 | xml.WriteElementString("End", XmlConvert.ToString(animation.InvulnerableEnd)); | 
 
 
 
 
 | 72 | xml.WriteEndElement(); | 
 
 
 
 
 | 73 |  | 
 
 
 
 
 | 74 | xml.WriteStartElement("Overlay"); | 
 
 
 
 
 | 75 | xml.WriteElementString("UsedBones", MetaEnum.ToString(animation.OverlayUsedBones)); | 
 
 
 
 
 | 76 | xml.WriteElementString("ReplacedBones", MetaEnum.ToString(animation.OverlayReplacedBones)); | 
 
 
 
 
 | 77 | xml.WriteEndElement(); | 
 
 
 
 
 | 78 |  | 
 
 
 
 
 | 79 | xml.WriteStartElement("DirectAnimations"); | 
 
 
 
 
 | 80 | xml.WriteElementString("Link", animation.DirectAnimations[0]); | 
 
 
 
 
 | 81 | xml.WriteElementString("Link", animation.DirectAnimations[1]); | 
 
 
 
 
 | 82 | xml.WriteEndElement(); | 
 
 
 
 
 | 83 | xml.WriteStartElement("Pause"); | 
 
 
 
 
 | 84 | xml.WriteElementString("Hard", XmlConvert.ToString(animation.HardPause)); | 
 
 
 
 
 | 85 | xml.WriteElementString("Soft", XmlConvert.ToString(animation.SoftPause)); | 
 
 
 
 
 | 86 | xml.WriteEndElement(); | 
 
 
 
 
 | 87 | xml.WriteStartElement("Interpolation"); | 
 
 
 
 
 | 88 | xml.WriteElementString("End", XmlConvert.ToString(animation.InterpolationEnd)); | 
 
 
 
 
 | 89 | xml.WriteElementString("Max", XmlConvert.ToString(animation.InterpolationMax)); | 
 
 
 
 
 | 90 | xml.WriteEndElement(); | 
 
 
 
 
 | 91 |  | 
 
 
 
 
 | 92 | xml.WriteElementString("FinalRotation", XmlConvert.ToString(MathHelper.ToDegrees(animation.FinalRotation))); | 
 
 
 
 
 | 93 | xml.WriteElementString("Direction", animation.Direction.ToString()); | 
 
 
 
 
 | 94 | xml.WriteElementString("Vocalization", XmlConvert.ToString(animation.Vocalization)); | 
 
 
 
 
 | 95 | xml.WriteElementString("ActionFrame", XmlConvert.ToString(animation.ActionFrame)); | 
 
 
 
 
 | 96 | xml.WriteElementString("Impact", animation.Impact); | 
 
 
 
 
 | 97 |  | 
 
 
 
 
 | 98 | WriteRawArray("Particles", animation.Particles, Write); | 
 
 
 
 
 | 99 | WriteRawArray("MotionBlur", animation.MotionBlur, Write); | 
 
 
 
 
 | 100 | WriteRawArray("Footsteps", animation.Footsteps, Write); | 
 
 
 
 
 | 101 | WriteRawArray("Sounds", animation.Sounds, Write); | 
 
 
 
 
 | 102 |  | 
 
 
 
 
 | 103 | if (daeFileName == null) | 
 
 
 
 
 | 104 | { | 
 
 
 
 
 | 105 | WriteHeights(); | 
 
 
 
 
 | 106 | WriteVelocities(); | 
 
 
 
 
 | 107 | WriteRotations(); | 
 
 
 
 
 | 108 | WritePositions(); | 
 
 
 
 
 | 109 | } | 
 
 
 
 
 | 110 |  | 
 
 
 
 
 | 111 | WriteThrowInfo(); | 
 
 
 
 
 | 112 | WriteRawArray("SelfDamage", animation.SelfDamage, Write); | 
 
 
 
 
 | 113 |  | 
 
 
 
 
 | 114 | if (animation.Attacks.Count > 0) | 
 
 
 
 
 | 115 | { | 
 
 
 
 
 | 116 | WriteRawArray("Attacks", animation.Attacks, Write); | 
 
 
 
 
 | 117 |  | 
 
 
 
 
 | 118 | if (daeFileName == null) | 
 
 
 
 
 | 119 | { | 
 
 
 
 
 | 120 | WriteAttackRing(); | 
 
 
 
 
 | 121 | } | 
 
 
 
 
 | 122 | } | 
 
 
 
 
 | 123 |  | 
 
 
 
 
 | 124 | xml.WriteEndElement(); | 
 
 
 
 
 | 125 | } | 
 
 
 
 
 | 126 |  | 
 
 
 
 
 | 127 | private void WriteRotations() | 
 
 
 
 
 | 128 | { | 
 
 
 
 
 | 129 | xml.WriteStartElement("Rotations"); | 
 
 
 
 
 | 130 |  | 
 
 
 
 
 | 131 | foreach (var keys in animation.Rotations) | 
 
 
 
 
 | 132 | { | 
 
 
 
 
 | 133 | xml.WriteStartElement("Bone"); | 
 
 
 
 
 | 134 |  | 
 
 
 
 
 | 135 | foreach (var key in keys) | 
 
 
 
 
 | 136 | { | 
 
 
 
 
 | 137 | if (animation.FrameSize == 6) | 
 
 
 
 
 | 138 | { | 
 
 
 
 
 | 139 | xml.WriteElementString("EKey", string.Format("{0} {1} {2} {3}", | 
 
 
 
 
 | 140 | XmlConvert.ToString(key.Duration), | 
 
 
 
 
 | 141 | XmlConvert.ToString(key.Rotation.X), | 
 
 
 
 
 | 142 | XmlConvert.ToString(key.Rotation.Y), | 
 
 
 
 
 | 143 | XmlConvert.ToString(key.Rotation.Z))); | 
 
 
 
 
 | 144 | } | 
 
 
 
 
 | 145 | else if (animation.FrameSize == 16) | 
 
 
 
 
 | 146 | { | 
 
 
 
 
 | 147 | xml.WriteElementString("QKey", string.Format("{0} {1} {2} {3} {4}", | 
 
 
 
 
 | 148 | XmlConvert.ToString(key.Duration), | 
 
 
 
 
 | 149 | XmlConvert.ToString(key.Rotation.X), | 
 
 
 
 
 | 150 | XmlConvert.ToString(key.Rotation.Y), | 
 
 
 
 
 | 151 | XmlConvert.ToString(key.Rotation.Z), | 
 
 
 
 
 | 152 | XmlConvert.ToString(-key.Rotation.W))); | 
 
 
 
 
 | 153 | } | 
 
 
 
 
 | 154 | } | 
 
 
 
 
 | 155 |  | 
 
 
 
 
 | 156 | xml.WriteEndElement(); | 
 
 
 
 
 | 157 | } | 
 
 
 
 
 | 158 |  | 
 
 
 
 
 | 159 | xml.WriteEndElement(); | 
 
 
 
 
 | 160 | } | 
 
 
 
 
 | 161 |  | 
 
 
 
 
 | 162 | private void WritePositions() | 
 
 
 
 
 | 163 | { | 
 
 
 
 
 | 164 | var positions = animation.Positions; | 
 
 
 
 
 | 165 |  | 
 
 
 
 
 | 166 | xml.WriteStartElement("PositionOffset"); | 
 
 
 
 
 | 167 | xml.WriteElementString("X", XmlConvert.ToString(positions.Count == 0 ? 0.0f : positions[0].X)); | 
 
 
 
 
 | 168 | xml.WriteElementString("Z", XmlConvert.ToString(positions.Count == 0 ? 0.0f : positions[0].Z)); | 
 
 
 
 
 | 169 | xml.WriteEndElement(); | 
 
 
 
 
 | 170 |  | 
 
 
 
 
 | 171 | WriteRawArray("Positions", animation.Positions, Write); | 
 
 
 
 
 | 172 | } | 
 
 
 
 
 | 173 |  | 
 
 
 
 
 | 174 | private void WriteHeights() | 
 
 
 
 
 | 175 | { | 
 
 
 
 
 | 176 | xml.WriteStartElement("Heights"); | 
 
 
 
 
 | 177 |  | 
 
 
 
 
 | 178 | foreach (float height in animation.Heights) | 
 
 
 
 
 | 179 | { | 
 
 
 
 
 | 180 | xml.WriteElementString("Height", XmlConvert.ToString(height)); | 
 
 
 
 
 | 181 | } | 
 
 
 
 
 | 182 |  | 
 
 
 
 
 | 183 | xml.WriteEndElement(); | 
 
 
 
 
 | 184 | } | 
 
 
 
 
 | 185 |  | 
 
 
 
 
 | 186 | private void WriteVelocities() | 
 
 
 
 
 | 187 | { | 
 
 
 
 
 | 188 | xml.WriteStartElement("Velocities"); | 
 
 
 
 
 | 189 |  | 
 
 
 
 
 | 190 | foreach (Vector2 velocity in animation.Velocities) | 
 
 
 
 
 | 191 | { | 
 
 
 
 
 | 192 | xml.WriteElementString("Velocity", string.Format("{0} {1}", | 
 
 
 
 
 | 193 | XmlConvert.ToString(velocity.X), | 
 
 
 
 
 | 194 | XmlConvert.ToString(velocity.Y))); | 
 
 
 
 
 | 195 | } | 
 
 
 
 
 | 196 |  | 
 
 
 
 
 | 197 | xml.WriteEndElement(); | 
 
 
 
 
 | 198 | } | 
 
 
 
 
 | 199 |  | 
 
 
 
 
 | 200 | private void WriteAttackRing() | 
 
 
 
 
 | 201 | { | 
 
 
 
 
 | 202 | xml.WriteStartElement("AttackRing"); | 
 
 
 
 
 | 203 |  | 
 
 
 
 
 | 204 | for (int i = 0; i < 36; i++) | 
 
 
 
 
 | 205 | xml.WriteElementString("Length", XmlConvert.ToString(animation.AttackRing[i])); | 
 
 
 
 
 | 206 |  | 
 
 
 
 
 | 207 | xml.WriteEndElement(); | 
 
 
 
 
 | 208 | } | 
 
 
 
 
 | 209 |  | 
 
 
 
 
 | 210 | private void WriteThrowInfo() | 
 
 
 
 
 | 211 | { | 
 
 
 
 
 | 212 | xml.WriteStartElement("ThrowSource"); | 
 
 
 
 
 | 213 |  | 
 
 
 
 
 | 214 | ThrowInfo info = animation.ThrowSource; | 
 
 
 
 
 | 215 |  | 
 
 
 
 
 | 216 | if (info != null) | 
 
 
 
 
 | 217 | { | 
 
 
 
 
 | 218 | xml.WriteStartElement("TargetAdjustment"); | 
 
 
 
 
 | 219 | xml.WriteElementString("Position", string.Format("{0} {1} {2}", | 
 
 
 
 
 | 220 | XmlConvert.ToString(info.Position.X), | 
 
 
 
 
 | 221 | XmlConvert.ToString(info.Position.Y), | 
 
 
 
 
 | 222 | XmlConvert.ToString(info.Position.Z))); | 
 
 
 
 
 | 223 | xml.WriteElementString("Angle", XmlConvert.ToString(info.Angle)); | 
 
 
 
 
 | 224 | xml.WriteEndElement(); | 
 
 
 
 
 | 225 |  | 
 
 
 
 
 | 226 | xml.WriteElementString("Distance", XmlConvert.ToString(info.Distance)); | 
 
 
 
 
 | 227 | xml.WriteElementString("TargetType", info.Type.ToString()); | 
 
 
 
 
 | 228 | } | 
 
 
 
 
 | 229 |  | 
 
 
 
 
 | 230 | xml.WriteEndElement(); | 
 
 
 
 
 | 231 | } | 
 
 
 
 
 | 232 |  | 
 
 
 
 
 | 233 | private void Write(Position position) | 
 
 
 
 
 | 234 | { | 
 
 
 
 
 | 235 | xml.WriteStartElement("Position"); | 
 
 
 
 
 | 236 | xml.WriteElementString("Height", XmlConvert.ToString(position.Height)); | 
 
 
 
 
 | 237 | xml.WriteElementString("YOffset", XmlConvert.ToString(position.YOffset)); | 
 
 
 
 
 | 238 | xml.WriteEndElement(); | 
 
 
 
 
 | 239 | } | 
 
 
 
 
 | 240 |  | 
 
 
 
 
 | 241 | private void Write(AttackExtent extent) | 
 
 
 
 
 | 242 | { | 
 
 
 
 
 | 243 | xml.WriteStartElement("Extent"); | 
 
 
 
 
 | 244 | xml.WriteElementString("Angle", XmlConvert.ToString(extent.Angle)); | 
 
 
 
 
 | 245 | xml.WriteElementString("Length", XmlConvert.ToString(extent.Length)); | 
 
 
 
 
 | 246 | xml.WriteElementString("MinY", XmlConvert.ToString(extent.MinY)); | 
 
 
 
 
 | 247 | xml.WriteElementString("MaxY", XmlConvert.ToString(extent.MaxY)); | 
 
 
 
 
 | 248 | xml.WriteEndElement(); | 
 
 
 
 
 | 249 | } | 
 
 
 
 
 | 250 |  | 
 
 
 
 
 | 251 | private void Write(Attack attack) | 
 
 
 
 
 | 252 | { | 
 
 
 
 
 | 253 | xml.WriteStartElement("Attack"); | 
 
 
 
 
 | 254 | xml.WriteElementString("Start", XmlConvert.ToString(attack.Start)); | 
 
 
 
 
 | 255 | xml.WriteElementString("End", XmlConvert.ToString(attack.End)); | 
 
 
 
 
 | 256 | xml.WriteElementString("Bones", MetaEnum.ToString(attack.Bones)); | 
 
 
 
 
 | 257 | xml.WriteElementString("Flags", MetaEnum.ToString(attack.Flags)); | 
 
 
 
 
 | 258 | xml.WriteElementString("Knockback", XmlConvert.ToString(attack.Knockback)); | 
 
 
 
 
 | 259 | xml.WriteElementString("HitPoints", XmlConvert.ToString(attack.HitPoints)); | 
 
 
 
 
 | 260 | xml.WriteElementString("HitType", attack.HitType.ToString()); | 
 
 
 
 
 | 261 | xml.WriteElementString("HitLength", XmlConvert.ToString(attack.HitLength)); | 
 
 
 
 
 | 262 | xml.WriteElementString("StunLength", XmlConvert.ToString(attack.StunLength)); | 
 
 
 
 
 | 263 | xml.WriteElementString("StaggerLength", XmlConvert.ToString(attack.StaggerLength)); | 
 
 
 
 
 | 264 |  | 
 
 
 
 
 | 265 | if (daeFileName == null) | 
 
 
 
 
 | 266 | { | 
 
 
 
 
 | 267 | WriteRawArray("Extents", attack.Extents, Write); | 
 
 
 
 
 | 268 | } | 
 
 
 
 
 | 269 |  | 
 
 
 
 
 | 270 | xml.WriteEndElement(); | 
 
 
 
 
 | 271 | } | 
 
 
 
 
 | 272 |  | 
 
 
 
 
 | 273 | private void Write(Particle particle) | 
 
 
 
 
 | 274 | { | 
 
 
 
 
 | 275 | xml.WriteStartElement("Particle"); | 
 
 
 
 
 | 276 | xml.WriteElementString("Start", XmlConvert.ToString(particle.Start)); | 
 
 
 
 
 | 277 | xml.WriteElementString("End", XmlConvert.ToString(particle.End)); | 
 
 
 
 
 | 278 | xml.WriteElementString("Bone", particle.Bone.ToString()); | 
 
 
 
 
 | 279 | xml.WriteElementString("Name", particle.Name); | 
 
 
 
 
 | 280 | xml.WriteEndElement(); | 
 
 
 
 
 | 281 | } | 
 
 
 
 
 | 282 |  | 
 
 
 
 
 | 283 | private void Write(Damage damage) | 
 
 
 
 
 | 284 | { | 
 
 
 
 
 | 285 | xml.WriteStartElement("Damage"); | 
 
 
 
 
 | 286 | xml.WriteElementString("Points", XmlConvert.ToString(damage.Points)); | 
 
 
 
 
 | 287 | xml.WriteElementString("Frame", XmlConvert.ToString(damage.Frame)); | 
 
 
 
 
 | 288 | xml.WriteEndElement(); | 
 
 
 
 
 | 289 | } | 
 
 
 
 
 | 290 |  | 
 
 
 
 
 | 291 | private void Write(Sound sound) | 
 
 
 
 
 | 292 | { | 
 
 
 
 
 | 293 | xml.WriteStartElement("Sound"); | 
 
 
 
 
 | 294 | xml.WriteElementString("Name", sound.Name); | 
 
 
 
 
 | 295 | xml.WriteElementString("Start", XmlConvert.ToString(sound.Start)); | 
 
 
 
 
 | 296 | xml.WriteEndElement(); | 
 
 
 
 
 | 297 | } | 
 
 
 
 
 | 298 |  | 
 
 
 
 
 | 299 | private void Write(Footstep footstep) | 
 
 
 
 
 | 300 | { | 
 
 
 
 
 | 301 | xml.WriteStartElement("Footstep"); | 
 
 
 
 
 | 302 | xml.WriteElementString("Frame", XmlConvert.ToString(footstep.Frame)); | 
 
 
 
 
 | 303 | xml.WriteElementString("Type", MetaEnum.ToString(footstep.Type)); | 
 
 
 
 
 | 304 | xml.WriteEndElement(); | 
 
 
 
 
 | 305 | } | 
 
 
 
 
 | 306 |  | 
 
 
 
 
 | 307 | private void Write(Shortcut shortcut) | 
 
 
 
 
 | 308 | { | 
 
 
 
 
 | 309 | xml.WriteStartElement("Shortcut"); | 
 
 
 
 
 | 310 | xml.WriteElementString("FromState", shortcut.FromState.ToString()); | 
 
 
 
 
 | 311 | xml.WriteElementString("Length", XmlConvert.ToString(shortcut.Length)); | 
 
 
 
 
 | 312 | xml.WriteElementString("ReplaceAtomic", shortcut.ReplaceAtomic ? "yes" : "no"); | 
 
 
 
 
 | 313 | xml.WriteEndElement(); | 
 
 
 
 
 | 314 | } | 
 
 
 
 
 | 315 |  | 
 
 
 
 
 | 316 | private void Write(MotionBlur motionBlur) | 
 
 
 
 
 | 317 | { | 
 
 
 
 
 | 318 | xml.WriteStartElement("MotionBlur"); | 
 
 
 
 
 | 319 | xml.WriteElementString("Bones", MetaEnum.ToString(motionBlur.Bones)); | 
 
 
 
 
 | 320 | xml.WriteElementString("Start", XmlConvert.ToString(motionBlur.Start)); | 
 
 
 
 
 | 321 | xml.WriteElementString("End", XmlConvert.ToString(motionBlur.End)); | 
 
 
 
 
 | 322 | xml.WriteElementString("Lifetime", XmlConvert.ToString(motionBlur.Lifetime)); | 
 
 
 
 
 | 323 | xml.WriteElementString("Alpha", XmlConvert.ToString(motionBlur.Alpha)); | 
 
 
 
 
 | 324 | xml.WriteElementString("Interval", XmlConvert.ToString(motionBlur.Interval)); | 
 
 
 
 
 | 325 | xml.WriteEndElement(); | 
 
 
 
 
 | 326 | } | 
 
 
 
 
 | 327 |  | 
 
 
 
 
 | 328 | private void WriteRawArray<T>(string name, List<T> list, Action<T> elementWriter) | 
 
 
 
 
 | 329 | { | 
 
 
 
 
 | 330 | xml.WriteStartElement(name); | 
 
 
 
 
 | 331 |  | 
 
 
 
 
 | 332 | foreach (T t in list) | 
 
 
 
 
 | 333 | elementWriter(t); | 
 
 
 
 
 | 334 |  | 
 
 
 
 
 | 335 | xml.WriteEndElement(); | 
 
 
 
 
 | 336 | } | 
 
 
 
 
 | 337 | } | 
 
 
 
 
 | 338 | } |