Add string previewer

This commit is contained in:
jeffman 2015-03-25 13:35:12 -04:00
parent 341feb8deb
commit 38fc3656be
9 changed files with 460 additions and 48 deletions

View File

@ -9,10 +9,26 @@ namespace ScriptTool
{
public class Compiler : ICompiler
{
private static int[] virtualWidths;
private static int[] renderWidths;
public IEnumerable<IControlCode> ControlCodes { get; set; }
public Dictionary<string, int> AddressMap { get; set; }
public Func<byte[], int, bool> ControlCodePredicate { get; set; }
static Compiler()
{
byte[] widths = File.ReadAllBytes("m2-widths-main.bin");
virtualWidths = new int[widths.Length / 2];
renderWidths = new int[widths.Length / 2];
for (int i = 0; i < widths.Length; i += 2)
{
virtualWidths[i / 2] = widths[i];
renderWidths[i / 2] = widths[i + 1];
}
}
public Compiler(IEnumerable<IControlCode> controlCodes,
Func<byte[], int, bool> controlCodePredicate)
{
@ -81,7 +97,7 @@ namespace ScriptTool
if (str[i] == '[')
{
if (str.IndexOf(']', i + 1) == -1)
throw new Exception("Opening bracket has no matching closing bracket");
throw new Exception("Opening bracket has no matching closing bracket: position " + i);
string[] codeStrings = str.Substring(i + 1, str.IndexOf(']', i + 1) - i - 1)
.Split(' ');
@ -97,10 +113,10 @@ namespace ScriptTool
if (codeString[0] == '_')
{
if (codeString[codeString.Length - 1] != '_')
throw new Exception("Reference has no closing underscore");
throw new Exception("Reference has no closing underscore: position " + i);
if (codeString.Length <= 2)
throw new Exception("Reference is empty");
throw new Exception("Reference is empty: position " + i);
if (!scanCodesOnly)
referenceAddress += 4;
@ -123,19 +139,19 @@ namespace ScriptTool
}
else if (str[i] == ']')
{
throw new Exception("Closing bracket has no matching opening bracket");
throw new Exception("Closing bracket has no matching opening bracket: position " + i);
}
else if (str[i] == '^')
{
if (str.IndexOf('^', i + 1) == -1)
throw new Exception("Label has no matching closing caret");
throw new Exception("Label has no matching closing caret: position " + i);
string label = str.Substring(i + 1, str.IndexOf('^', i + 1) - i - 1);
if (AddressMap.ContainsKey(label))
throw new Exception("Label already defined");
throw new Exception("Label already defined: position " + i);
if(!scanCodesOnly)
if (!scanCodesOnly)
AddressMap.Add(label, referenceAddress);
i = str.IndexOf('^', i + 1) + 1;
@ -169,7 +185,7 @@ namespace ScriptTool
if (str[i] == '[')
{
if (str.IndexOf(']', i + 1) == -1)
throw new Exception("Opening bracket has no matching closing bracket");
throw new Exception("Opening bracket has no matching closing bracket: position " + i);
string[] codeStrings = str.Substring(i + 1, str.IndexOf(']', i + 1) - i - 1)
.Split(' ');
@ -183,7 +199,7 @@ namespace ScriptTool
for (int j = 0; j < codeStrings.Length; j++)
{
if (!IsHexByte(codeStrings[j]))
throw new Exception("Code string for unrecognized control code block must be a byte literal");
throw new Exception("Code string for unrecognized control code block must be a byte literal: position " + i);
byte value = byte.Parse(codeStrings[j], System.Globalization.NumberStyles.HexNumber);
if (buffer != null)
@ -196,7 +212,7 @@ namespace ScriptTool
{
// Validate
if (!code.IsValid(codeStrings))
throw new Exception("Invalid control code");
throw new Exception("Invalid control code: position " + i);
// Parse
code.Compile(codeStrings, buffer, ref referenceAddress, AddressMap);
@ -206,12 +222,12 @@ namespace ScriptTool
}
else if (str[i] == ']')
{
throw new Exception("Closing bracket has no matching opening bracket");
throw new Exception("Closing bracket has no matching opening bracket: position " + i);
}
else if (str[i] == '^')
{
if (str.IndexOf('^', i + 1) == -1)
throw new Exception("Label has no matching closing caret");
throw new Exception("Label has no matching closing caret: position " + i);
i = str.IndexOf('^', i + 1) + 1;
}
@ -236,7 +252,8 @@ namespace ScriptTool
int bytesWritten = buffer.Count - previousBufferSize;
if (bytesWritten > padLength)
throw new Exception("Exceeded pad length");
throw new Exception("Exceeded pad length: wrote " + bytesWritten +
" bytes, but the pad length is " + padLength + " bytes");
for (int i = bytesWritten; i < padLength; i++)
{
@ -257,7 +274,7 @@ namespace ScriptTool
if (str[i] == '[')
{
if (str.IndexOf(']', i + 1) == -1)
throw new Exception("Opening bracket has no matching closing bracket");
throw new Exception("Opening bracket has no matching closing bracket: position " + i);
sb.Append(str.Substring(i, str.IndexOf(']', i + 1) - i + 1));
@ -265,12 +282,12 @@ namespace ScriptTool
}
else if (str[i] == ']')
{
throw new Exception("Closing bracket has no matching opening bracket");
throw new Exception("Closing bracket has no matching opening bracket: position " + i);
}
else if (str[i] == '^')
{
if (str.IndexOf('^', i + 1) == -1)
throw new Exception("Label has no matching closing caret");
throw new Exception("Label has no matching closing caret: position " + i);
sb.Append(str.Substring(i, str.IndexOf('^', i + 1) - i + 1));
@ -284,5 +301,144 @@ namespace ScriptTool
return sb.ToString();
}
public IList<string> FormatPreviewM12(string str, out IList<int> widths, IDictionary<byte, string> charLookup)
{
var sb = new StringBuilder();
widths = new List<int>();
int currentWidth = 0;
var strings = new List<string>();
for (int i = 0; i < str.Length; )
{
if (str[i] == '[')
{
if (str.IndexOf(']', i + 1) == -1)
throw new Exception("Opening bracket has no matching closing bracket: position " + i);
string[] codeStrings = str.Substring(i + 1, str.IndexOf(']', i + 1) - i - 1)
.Split(' ');
M12ControlCode code = (M12ControlCode)ControlCodes.FirstOrDefault(c => c.IsMatch(codeStrings));
foreach (var codeString in codeStrings)
{
if (codeString[0] == '_')
{
if (codeString[codeString.Length - 1] != '_')
throw new Exception("Reference has no closing underscore: position " + i);
if (codeString.Length <= 2)
throw new Exception("Reference is empty: position " + i);
}
else if (!IsHexByte(codeString))
{
throw new Exception(String.Format(
"Encountered invalid code string at position {0}: {1}", i, codeString));
}
}
i = str.IndexOf(']', i + 1) + 1;
switch (code.Identifier)
{
case 0xC:
case 0xD:
case 0xE:
case 0xF:
case 0x10:
case 0x11:
case 0x12:
case 0x15:
case 0x1A:
case 0x2D:
case 0x9F:
case 0xAD:
// Name/item code
sb.Append("[NAME]");
currentWidth += 60;
break;
case 0x1:
case 0x2:
// Line break
strings.Add(sb.ToString());
sb.Clear();
widths.Add(currentWidth);
currentWidth = 0;
break;
case 0x20:
sb.Append("[SMAAASH]");
currentWidth += 72;
break;
case 0x21:
sb.Append("[YOU WIN]");
currentWidth += 72;
break;
case 0x23:
case 0x63:
case 0x98:
case 0xB7:
sb.Append("[MONEY]");
currentWidth += 36;
break;
case 0x24:
case 0x25:
case 0x26:
case 0x27:
case 0x28:
case 0x29:
case 0x2A:
case 0x2B:
sb.Append("[STAT]");
currentWidth += 18;
break;
case 0x1E:
case 0x1F:
sb.Append("_");
currentWidth += 10;
break;
}
}
else if (str[i] == ']')
{
throw new Exception("Closing bracket has no matching opening bracket: position " + i);
}
else if (str[i] == '^')
{
if (str.IndexOf('^', i + 1) == -1)
throw new Exception("Label has no matching closing caret: position " + i);
string label = str.Substring(i + 1, str.IndexOf('^', i + 1) - i - 1);
i = str.IndexOf('^', i + 1) + 1;
}
else
{
if (!(str[i] == '\r') && !(str[i] == '\n'))
{
sb.Append(str[i]);
currentWidth += virtualWidths[GetByte(str[i], charLookup) - 0x50];
}
i++;
}
}
if (sb.Length > 0)
{
strings.Add(sb.ToString());
widths.Add(currentWidth);
}
return strings;
}
}
}

View File

@ -86,6 +86,9 @@
<None Include="m12-codelist.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="m2-widths-main.bin">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>

Binary file not shown.

View File

@ -33,6 +33,8 @@
this.fileMenu = new System.Windows.Forms.ToolStripMenuItem();
this.saveMenu = new System.Windows.Forms.ToolStripMenuItem();
this.topPanel = new System.Windows.Forms.FlowLayoutPanel();
this.label1 = new System.Windows.Forms.Label();
this.collectionSelector = new System.Windows.Forms.ComboBox();
this.groupSelector = new System.Windows.Forms.ComboBox();
this.backButton = new System.Windows.Forms.Button();
this.mainPanel = new System.Windows.Forms.Panel();
@ -44,6 +46,7 @@
this.m12StringEnglish = new System.Windows.Forms.TextBox();
this.lineOpsPanel = new System.Windows.Forms.FlowLayoutPanel();
this.copyCodesButton = new System.Windows.Forms.Button();
this.previewButton = new System.Windows.Forms.Button();
this.codeSplitContainer = new System.Windows.Forms.SplitContainer();
this.codeList = new System.Windows.Forms.ListBox();
this.label2 = new System.Windows.Forms.Label();
@ -55,9 +58,7 @@
this.statusBar = new System.Windows.Forms.StatusStrip();
this.statusLabel = new System.Windows.Forms.ToolStripStatusLabel();
this.writeTimer = new System.Windows.Forms.Timer(this.components);
this.label1 = new System.Windows.Forms.Label();
this.collectionSelector = new System.Windows.Forms.ComboBox();
this.previewButton = new System.Windows.Forms.Button();
this.previewer = new ScriptToolGui.StringPreviewer();
this.mainMenu.SuspendLayout();
this.topPanel.SuspendLayout();
this.mainPanel.SuspendLayout();
@ -67,6 +68,7 @@
this.mainSplitContainer.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.leftSplitContainer)).BeginInit();
this.leftSplitContainer.Panel1.SuspendLayout();
this.leftSplitContainer.Panel2.SuspendLayout();
this.leftSplitContainer.SuspendLayout();
this.textBoxPanel.SuspendLayout();
this.lineOpsPanel.SuspendLayout();
@ -118,6 +120,27 @@
this.topPanel.Size = new System.Drawing.Size(1026, 29);
this.topPanel.TabIndex = 10;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(3, 8);
this.label1.Margin = new System.Windows.Forms.Padding(3, 8, 0, 0);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(39, 13);
this.label1.TabIndex = 13;
this.label1.Text = "Group:";
//
// collectionSelector
//
this.collectionSelector.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.collectionSelector.FormattingEnabled = true;
this.collectionSelector.Location = new System.Drawing.Point(45, 4);
this.collectionSelector.Margin = new System.Windows.Forms.Padding(3, 4, 3, 3);
this.collectionSelector.Name = "collectionSelector";
this.collectionSelector.Size = new System.Drawing.Size(157, 21);
this.collectionSelector.TabIndex = 14;
this.collectionSelector.SelectionChangeCommitted += new System.EventHandler(this.collectionSelector_SelectionChangeCommitted);
//
// groupSelector
//
this.groupSelector.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
@ -187,6 +210,10 @@
//
this.leftSplitContainer.Panel1.Controls.Add(this.textBoxPanel);
this.leftSplitContainer.Panel1.Controls.Add(this.lineOpsPanel);
//
// leftSplitContainer.Panel2
//
this.leftSplitContainer.Panel2.Controls.Add(this.previewer);
this.leftSplitContainer.Size = new System.Drawing.Size(800, 667);
this.leftSplitContainer.SplitterDistance = 526;
this.leftSplitContainer.TabIndex = 5;
@ -260,6 +287,16 @@
this.copyCodesButton.UseVisualStyleBackColor = true;
this.copyCodesButton.Click += new System.EventHandler(this.copyCodesButton_Click);
//
// previewButton
//
this.previewButton.Location = new System.Drawing.Point(133, 3);
this.previewButton.Name = "previewButton";
this.previewButton.Size = new System.Drawing.Size(75, 23);
this.previewButton.TabIndex = 1;
this.previewButton.Text = "Preview";
this.previewButton.UseVisualStyleBackColor = true;
this.previewButton.Click += new System.EventHandler(this.previewButton_Click);
//
// codeSplitContainer
//
this.codeSplitContainer.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
@ -384,35 +421,17 @@
this.writeTimer.Interval = 10000;
this.writeTimer.Tick += new System.EventHandler(this.writeTimer_Tick);
//
// label1
// previewer
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(3, 8);
this.label1.Margin = new System.Windows.Forms.Padding(3, 8, 0, 0);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(39, 13);
this.label1.TabIndex = 13;
this.label1.Text = "Group:";
//
// collectionSelector
//
this.collectionSelector.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.collectionSelector.FormattingEnabled = true;
this.collectionSelector.Location = new System.Drawing.Point(45, 4);
this.collectionSelector.Margin = new System.Windows.Forms.Padding(3, 4, 3, 3);
this.collectionSelector.Name = "collectionSelector";
this.collectionSelector.Size = new System.Drawing.Size(157, 21);
this.collectionSelector.TabIndex = 14;
this.collectionSelector.SelectionChangeCommitted += new System.EventHandler(this.collectionSelector_SelectionChangeCommitted);
//
// previewButton
//
this.previewButton.Location = new System.Drawing.Point(133, 3);
this.previewButton.Name = "previewButton";
this.previewButton.Size = new System.Drawing.Size(75, 23);
this.previewButton.TabIndex = 1;
this.previewButton.Text = "Preview";
this.previewButton.UseVisualStyleBackColor = true;
this.previewer.AutoScroll = true;
this.previewer.CharLookup = null;
this.previewer.DisplayedString = null;
this.previewer.Dock = System.Windows.Forms.DockStyle.Fill;
this.previewer.Location = new System.Drawing.Point(0, 0);
this.previewer.M12Compiler = null;
this.previewer.Name = "previewer";
this.previewer.Size = new System.Drawing.Size(796, 133);
this.previewer.TabIndex = 0;
//
// MainForm
//
@ -440,6 +459,7 @@
this.mainSplitContainer.ResumeLayout(false);
this.leftSplitContainer.Panel1.ResumeLayout(false);
this.leftSplitContainer.Panel1.PerformLayout();
this.leftSplitContainer.Panel2.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.leftSplitContainer)).EndInit();
this.leftSplitContainer.ResumeLayout(false);
this.textBoxPanel.ResumeLayout(false);
@ -491,6 +511,7 @@
private System.Windows.Forms.Label label1;
private System.Windows.Forms.ComboBox collectionSelector;
private System.Windows.Forms.Button previewButton;
private StringPreviewer previewer;
}
}

View File

@ -72,6 +72,9 @@ namespace ScriptToolGui
public MainForm()
{
InitializeComponent();
previewer.M12Compiler = m12Compiler;
previewer.CharLookup = ebCharLookup;
ImportAllStringRefs();
ImportAllStrings(workingFolder);
@ -308,6 +311,8 @@ namespace ScriptToolGui
PopulateCodeList();
PopulateReferenceList();
previewButton_Click(null, null);
}
private void SelectGroup(MatchedGroup group)
@ -388,6 +393,8 @@ namespace ScriptToolGui
PopulateCodeList();
PopulateReferenceList();
previewButton_Click(null, null);
}
private void PushPreviousNavigationState()
@ -538,11 +545,22 @@ namespace ScriptToolGui
if (collectionSelector.SelectedIndex == -1)
{
groupSelector.Items.Clear();
previewer.DisplayedString = null;
}
else
{
var collection = (MatchedGroupCollection)collectionSelector.SelectedItem;
// Set the previewer width before we do navigation stuff
if (collection == psiHelpGroups)
{
previewer.MaxWidth = 224;
}
else
{
previewer.MaxWidth = 144;
}
// Take no action if we haven't actually changed the collection
// (otherwise, the group selector would jump to 0, probably unwanted)
if (collection == currentCollection)
@ -555,6 +573,11 @@ namespace ScriptToolGui
groupSelector_SelectionChangeCommitted(null, null);
}
}
private void previewButton_Click(object sender, EventArgs e)
{
previewer.DisplayedString = m12StringEnglish.Text;
}
}
enum Game

View File

@ -81,6 +81,9 @@
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<EmbeddedResource Include="StringPreviewer.resx">
<DependentUpon>StringPreviewer.cs</DependentUpon>
</EmbeddedResource>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>

View File

@ -28,10 +28,35 @@
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
this.stringPanel = new System.Windows.Forms.FlowLayoutPanel();
this.SuspendLayout();
//
// stringPanel
//
this.stringPanel.AutoSize = true;
this.stringPanel.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.stringPanel.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
this.stringPanel.Location = new System.Drawing.Point(0, 0);
this.stringPanel.Name = "stringPanel";
this.stringPanel.Size = new System.Drawing.Size(0, 0);
this.stringPanel.TabIndex = 0;
//
// StringPreviewer
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScroll = true;
this.Controls.Add(this.stringPanel);
this.Name = "StringPreviewer";
this.Size = new System.Drawing.Size(324, 105);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.FlowLayoutPanel stringPanel;
}
}

View File

@ -7,14 +7,75 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using ScriptTool;
namespace ScriptToolGui
{
public partial class StringPreviewer : UserControl
{
public Compiler M12Compiler { get; set; }
public IDictionary<byte, string> CharLookup { get; set; }
public int MaxWidth { get; set; }
private string text;
public string DisplayedString
{
get
{
return text;
}
set
{
text = value;
Redraw();
}
}
public StringPreviewer()
{
InitializeComponent();
}
private void Redraw()
{
stringPanel.Controls.Clear();
if (M12Compiler == null || CharLookup == null || text == null)
{
return;
}
try
{
IList<int> widths;
IList<string> parsed = M12Compiler.FormatPreviewM12(text, out widths, CharLookup);
for (int i = 0; i < parsed.Count; i++)
{
var label = new Label();
label.AutoSize = true;
label.Text = parsed[i] + "(" + widths[i] + ")";
if (widths[i] <= MaxWidth)
label.ForeColor = Color.Green;
else
label.ForeColor = Color.Red;
stringPanel.Controls.Add(label);
}
}
catch (Exception e)
{
stringPanel.Controls.Clear();
var errLabel = new Label();
errLabel.AutoSize = true;
errLabel.Font = new Font(errLabel.Font, FontStyle.Bold);
errLabel.Text = "Error: " + e.Message;
stringPanel.Controls.Add(errLabel);
}
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>