<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title><![CDATA[Серый форум &mdash; JScript: "WindowsInstaller" и "SAPI" - чтение и запись бинарных файлов]]></title>
		<link>http://forum.script-coding.com/viewtopic.php?id=15731</link>
		<atom:link href="http://forum.script-coding.com/extern.php?action=feed&amp;tid=15731&amp;type=rss" rel="self" type="application/rss+xml" />
		<description><![CDATA[Недавние сообщения в теме «JScript: "WindowsInstaller" и "SAPI" - чтение и запись бинарных файлов».]]></description>
		<lastBuildDate>Wed, 21 Oct 2020 15:27:33 +0000</lastBuildDate>
		<generator>PunBB</generator>
		<item>
			<title><![CDATA[Re: JScript: "WindowsInstaller" и "SAPI" - чтение и запись бинарных файлов]]></title>
			<link>http://forum.script-coding.com/viewtopic.php?pid=142702#p142702</link>
			<description><![CDATA[<p><strong>Исключение заголовка &quot;BOM&quot;.</strong></p><p>Два байта заголовка &quot;BOM&quot; (ff fe) появляются при конвертации в формате Юникод. Их можно пропустить, как было показано выше, но также можно использовать способ конвертации &quot;напрямую&quot;, при которой заголовок &quot;BOM&quot; не появится.</p><p>Для этого можно воспользоваться возможностями ActiveX объекта &quot;ADODB.Recordset&quot; и функцией конвертации &quot;MultiByteToBinary&quot; от <a href="https://www.motobit.com/tips/detpg_binarytostring/">motobit.com</a>.</p><p>Стоит отметить, что использовать функцию &quot;MultiByteToBinary&quot; в исходном виде нецелесообразно, так как она не оптимизирована и приведет к снижению производительности.</p><p>Оптимизируем &quot;MultiByteToBinary&quot; применительно к чтению бинарного файла с помощью &quot;WindowsInstaller.Installer&quot; так, чтобы исключить повторные инициализации и работать с меньшим количеством входных переменных:</p><div class="codebox"><pre><code>!function sourceRead(bytesCount)                                    //функция последовательного чтения байтов файла-источника
{                                                                                           //(количество байтов от предыдущей позиции чтения)
    var RS = new ActiveXObject(&#039;ADODB.Recordset&#039;);      //исключение повторных инициализаций при вызове функции
    RS.Fields._Append(0, 205, 1);                                       //имеет меньший размер после инициализации, также у &quot;_Append&quot; меньше входных переменных, чем у &quot;Append&quot;
    RS.Open();
    RS.AddNew();
    var bytes = RS(0);
    sourceRead = function(bytesCount)
    {
        bytes.AppendChunk(source.ReadStream(1, bytesCount, 3));
        RS.Update();
        //return bytes.Value;                                                    //работает медленнее, чем &quot;GetChunk&quot;, возвращает лишний нулевой байт
        return bytes.GetChunk(bytesCount);                          //работает медленнее, чем конвертация при помощи &quot;ADODB.Stream&quot;
    }
}();</code></pre></div><p>Несмотря на проведенную оптимизацию, использование &quot;ADODB.Recordset&quot; для конвертации приводит к снижению производительности по сравнению с использованием &quot;ADODB.Stream&quot;.</p><p><strong>Вывод:</strong> &quot;ADODB.Stream&quot; - самый быстрый ActiveX объект из всех известных мне для итеративной работы с бинарными данными в оперативной памяти. Он в том числе работает быстрее на JScript, чем &quot;SAPI.SpMemoryStream&quot; на VBScript.</p><p>Также стоит отметить, что чтение при помощи &quot;WindowsInstaller.Installer&quot; на JScript происходит немногим, но быстрее, чем при помощи &quot;SAPI.SpFileStream&quot; на VBScript.</p>]]></description>
			<author><![CDATA[null@example.com (lifeflame)]]></author>
			<pubDate>Wed, 21 Oct 2020 15:27:33 +0000</pubDate>
			<guid>http://forum.script-coding.com/viewtopic.php?pid=142702#p142702</guid>
		</item>
		<item>
			<title><![CDATA[JScript: "WindowsInstaller" и "SAPI" - чтение и запись бинарных файлов]]></title>
			<link>http://forum.script-coding.com/viewtopic.php?pid=142687#p142687</link>
			<description><![CDATA[<p>Предлагаю на примерах рассмотреть особенности работы ActiveX-объектов &quot;<strong>WindowsInstaller.Installer</strong>&quot; и &quot;<strong>SAPI.SpFileStream</strong>&quot; при чтении и записи бинарных файлов, которые я использовал в HTML приложении <a href="http://forum.script-coding.com/viewtopic.php?id=15725">&quot;Resource Extractor&quot;</a>.</p><p>Данный материал рассчитан в том числе и на тех, кто сталкивается с этим впервые, поэтому он достаточно линеен и оставлено множество комментариев с пояснениями.</p><p>При исследовании &quot;<strong>WindowsInstaller.Installer</strong>&quot; я сделал вывод, что он подходит <strong>для чтения бинарных файлов и возвращения истинных строковых байтов под любой локалью и на чистом JScript</strong>, что является его определенным преимуществом для данного языка, так как JScript не может принимать и изменять данные по ссылке, за исключением изменения свойств объектов, а также отдельных исключительных случаев у некоторых компонентов, относящихся больше не к языку, а непосредственно к реализации таких компонентов.</p><p>В случае с &quot;SAPI.SpFileStream&quot; один из параметров метода чтения файлов &quot;Read&quot; (это параметр &quot;Buffer&quot;) принимает переменную по ссылке и изменяет ее, что возможно по умолчанию на VBScript, но опять же не на чистом JScript.</p><p>Но в качестве исключения, например, метод &quot;transformNodeToObject&quot; вернет измененный по ссылке объект на чистом JScript.</p><p><strong>Примечание</strong>: в данном обзоре и далее будет встречаться понятие &quot;<em>истинные байты</em>&quot;. Истинные байты (true bytes) - это обычные байты, которые не были изменены вмешательством посторонних объектов, таких как, например, &quot;Scripting.FileSystemObject&quot;, который возвращает уже не &quot;<em>истинные строковые байты</em>&quot; под китайской локалью и ей подобными. В свою очередь, истинные строковые байты это не то же самое, что истинные байты (тип данных &quot;<strong>Byte()</strong>&quot;). Истинные строковые байты - это истинные байты, но в строковом представлении (тип данных &quot;<strong>String</strong>&quot;).</p><p><strong>Работа с исходным кодом.</strong><br /></p><ol class="decimal"><li><p>Для запуска приложения с примером скопируйте его исходный код и сохраните его в текстовом файле, сменив его расширение на &quot;hta&quot;.</p></li><li><p>Запуск приложения с примером осуществляется двойным нажатием, как и в случае с обычной программой.</p></li></ol><p>Рекомендую использовать <a href="http://akelpad.sourceforge.net/en/download.php">AkelPad</a> для просмотра сохраненного исходного кода примеров <span class="bbu">с правильными отступами</span>.</p><p><strong>Рассмотрим подробнее на примере поведение &quot;SAPI.SpFileStream&quot; и &quot;transformNodeToObject&quot; в отношении передачи переменной по ссылке</strong>:</p><div class="codebox"><pre><code>&lt;script language = VBScript&gt;

Function alert(message)                                                        &#039;заменим &quot;alert&quot; из JScript на более информативный метод для анализа данных
    Dim messageType
    messageType = TypeName(message)
    If messageType = &quot;String&quot; Or messageType = &quot;Byte()&quot; Then
        InputBox &quot;&quot;, &quot;Message from webpage&quot;, message
    Else
        InputBox &quot;&quot;, &quot;Message from webpage&quot;, TypeName(message)
    End If
End Function

Function vbsSourceRead(startPosition, bytesCount)           &#039;функция чтения байтов файла-источника (начальная позиция, количество байтов)
    source.Seek(startPosition)                                                &#039;пропускаем определенное число байтов до достижения начальной позиции чтения
    Dim data
    source.Read data, bytesCount                                          &#039;передаем переменную data по ссылке в метод чтения байтов
    vbsSourceRead = data                                                      &#039;возвращаем прочитанные методом &quot;Read&quot; истинные байты в переменной data по ссылке
End Function

&lt;/script&gt;

&lt;script language = JScript&gt;

var jsSourceRead = function(startPosition, bytesCount)      //функция с попыткой чтения байтов файла-источника (начальная позиция, количество байтов)
{
    source.Seek(startPosition);                                               //пропускаем определенное число байтов до достижения начальной позиции чтения
    var data;
    source.Read(data, bytesCount);                                       //пытаемся передать переменную data по ссылке в метод чтения байтов
    return data;                                                        //пытаемся вернуть прочитанные методом &quot;Read&quot; истинные байты по ссылке
},

xml = new ActiveXObject(&#039;Microsoft.XMLDOM&#039;),
hex = xml.createElement(&#039;hex&#039;);
hex.dataType = &#039;bin.hex&#039;;

var bytesToHex = function(bytes)                                          //функция для конвертации байтов в их строковое шестнадцатеричное представление
{
    if(typeof bytes == &#039;unknown&#039;)
    {
        hex.nodeTypedValue = bytes;
        return hex.text;
    }
    return bytes;
}

var source = new ActiveXObject(&#039;SAPI.SpFileStream&#039;);       //подготовим новый объект для работы с файловой системой
source.Format.Type = 1;                                                       //используем байты-текст как смешанный тип принимаемых данных (SAFTText = 1)
source.Open(&#039;C:\\Windows\\System32\\shell32.dll&#039;);            //открываем &quot;shell32.dll&quot; только для чтения (SSFMOpenForRead = 0)

var data = vbsSourceRead(0, 7);                                          //читаем первые 7 истинных байтов файла &quot;shell32.dll&quot; на VBScript
alert(data);                                                                              //выведет первые 7 истинных байтов файла &quot;shell32.dll&quot; в исходном виде, но не все байты могут
                                                                                                    //быть отображены в виде текста при таком выводе
alert(bytesToHex(data));                                                        //выведет, например, &quot;4d5a9000030000&quot;, то есть это первые 7 истинных байтов &quot;shell32.dll&quot; - 4d 5a 90 00 03 00 00

data = jsSourceRead(0, 7);                                                   //читаем те же первые 7 истинных байтов файла &quot;shell32.dll&quot; на JScript
alert(data);                                                                             //пытаемся вывести первые 7 истинных байтов файла &quot;shell32.dll&quot; в исходном виде, но результат Empty, то есть
                                                                                                    //чтение на JScript не вернуло данные по ссылке

var memory = new ActiveXObject(&#039;ADODB.Stream&#039;);         //подготовим новый объект для работы в оперативной памяти
memory.Open();                                                                    //откроем поток памяти на чтение и запись
memory.Type = 1;                                                                 //будем работать с байтами (adTypeBinary = 1)
data = memory.Read();                                                         //прочитаем поток памяти в виде байтов
alert(data);                                                                             //выведет Null, то есть новый поток памяти изначально ничем не заполнен

memory.Position = 0;                                                            //вернемся к началу потока памяти после завершения операции чтения
hex.text = &#039;31323334&#039;;                                                            //заполним xml-ноду hex байтами &quot;1234&quot; в строковом шестнадцатеричном представлении
hex.transformNodeToObject(hex, memory);                        //попытаемся передать в метод &quot;transformNodeToObject&quot; xml-ноды объект memory в качестве параметра
                                                                                                    //&quot;outputObject&quot; по ссылке (второй параметр &quot;stylesheet&quot; в данном случае не так интересен)
memory.Position = 0;                                                            //вернемся к началу потока памяти после предполагаемого его заполнения методом &quot;transformNodeToObject&quot;
memory.Type = 2;                                                                 //будем работать с текстом (adTypeText = 2)
data = memory.ReadText();                                                  //прочитаем поток памяти в виде текста
alert(data);                                                                             //выведет &quot;&lt;hex dt:dt=&quot;bin.hex&quot;&gt;31323334&lt;/hex&gt;&quot; - текущее представление xml-ноды hex, то есть возникла
                                                                                                    //исключительная ситуация на JScript - был изменен и заполнен данными ноды непосредственно
                                                                                                    //объект memory, переданный по ссылке

&lt;/script&gt;</code></pre></div><p><strong>Теперь остановимся подробнее на чтении бинарных файлов при использовании &quot;WindowsInstaller.Installer&quot; на чистом JScript</strong>:</p><div class="codebox"><pre><code>&lt;script language = VBScript&gt;

Function alert(message)                                                              &#039;заменим &quot;alert&quot; из JScript на более информативный метод для анализа данных
    Dim messageType
    messageType = TypeName(message)
    If messageType = &quot;String&quot; Or messageType = &quot;Byte()&quot; Then
        InputBox &quot;&quot;, &quot;Message from webpage&quot;, message
    Else
        InputBox &quot;&quot;, &quot;Message from webpage&quot;, TypeName(message)
    End If
End Function

&lt;/script&gt;

&lt;script language = JScript&gt;

var doc = GetObject(&#039;\\&#039;, &#039;htmlfile&#039;);
doc.write(&quot;&lt;xml&gt;&lt;_ xmlns:dt=&#039;urn:schemas-microsoft-com:datatypes&#039;&gt;&lt;_ dt:dt=&#039;bin.hex&#039;/&gt;&lt;/_&gt;&lt;/xml&gt;&quot;);
var xml = doc.documentElement.firstChild.children[1];
xml.preserveWhiteSpace = 1;

var hex = xml.firstChild.childNodes[0],

bytesToHex = function(bytes)                                                      //функция для конвертации байтов в их строковое шестнадцатеричное представление
{
    if(typeof bytes == &#039;unknown&#039;)
    {
        hex.nodeTypedValue = bytes;
        return hex.text;
    }
    return bytes;
},

sourceRead = function(bytesCount)                                           //функция последовательного чтения байтов файла-источника
                                                                                                            //(количество байтов от предыдущей позиции чтения)
{
    memory.Position = 0;                                                              //сбрасываем поток памяти в начальную позицию
    memory.Type = 2;                                                                   //будем работать с текстом (adTypeText = 2)
    memory.Charset = &#039;Unicode&#039;;                                                  //воспринимаем истинные строковые байты файла-источника как символы в формате Юникод
    var stringBytes = source.ReadStream(1, bytesCount, 3);      //читаем истинные строковые байты файла-источника &quot;напрямую&quot; (msiReadStreamDirect = 3)
    memory.WriteText(stringBytes);                                              //помещаем прочитанные методом &quot;ReadStream&quot; истинные строковые байты в поток памяти для их
                                                                                                            //конвертации в истинные байты
    memory.SetEOS();                                                                  //устанавливаем конец потока памяти, то есть обрезаем остатки потока памяти с предыдущего чтения
    memory.Position = 0;                                                               //вернемся к началу потока памяти после завершения операции записи
    memory.Type = 1;                                                                    //будем работать с байтами (adTypeBinary = 1)
    memory.Position = 2;                                                               //пропускаем два байта заголовка &quot;BOM&quot;, который возвращает поток памяти после конвертации
                                                                                                            //в формате Юникод
    var bytes = memory.Read(bytesCount);                                 //обрезаем поток памяти строго по количеству прочитанных байтов, так как в случае чтения нечетного
                                                                                                            //количества байтов будет возвращен лишний нулевой байт как последствие конвертации
                                                                                                            //в формате Юникод
    return bytes;
}

var source = new ActiveXObject(&#039;WindowsInstaller.Installer&#039;).CreateRecord(1);       //подготовим новый объект для работы с файловой системой
source.SetStream(1, &#039;C:\\Windows\\System32\\shell32.dll&#039;);                                     //открываем &quot;shell32.dll&quot; как текстовый поток файловой системы только для чтения,
                                                                                                                                            //других опций не предусмотрено, последующее закрытие потока не требуется,
                                                                                                                                            //может использоваться вновь для открытия новых файлов

var memory = new ActiveXObject(&#039;ADODB.Stream&#039;);                                                //подготовим новый объект для работы в оперативной памяти
memory.Open();                                                                                                           //откроем поток памяти на чтение и запись

var data = sourceRead(7);                                                                                           //читаем первые 7 истинных байтов файла &quot;shell32.dll&quot;
alert(data);                                                                                                                    //выведет первые 7 истинных байтов файла &quot;shell32.dll&quot; в исходном виде, но не все байты
                                                                                                                                            //могут быть отображены в виде текста при таком выводе
alert(bytesToHex(data));                                                                                               //выведет, например, &quot;4d5a9000030000&quot;, то есть это первые 7 истинных байтов
                                                                                                                                            //&quot;shell32.dll&quot; в строковом шестнадцатеричном представлении - 4d 5a 90 00 03 00 00

data = sourceRead(1);                                                                                                 //читаем следующий один (8-й) истинный байт файла &quot;shell32.dll&quot;
alert(data);                                                                                                                     //выведет один (8-й) истинный байт файла &quot;shell32.dll&quot;, если он может быть
                                                                                                                                            //отображен в виде текста
alert(bytesToHex(data));                                                                                               //выведет, например, &quot;00&quot;, то есть это один нулевой (8-й) истинный байт &quot;shell32.dll&quot;
                                                                                                                                            //в строковом шестнадцатеричном представлении - 00

&lt;/script&gt;</code></pre></div><p><strong>Примечание</strong>: удаление нулевого байта после возможной конвертации нечетного количества строковых байтов в формате Юникод в HTML приложении &quot;Resource Extractor&quot; происходит автоматически на последующем уровне обработки полученных данных. Таким образом исключена обработка дополнительного параметра количества байтов в универсальной функции &quot;strToBt&quot; без снижения производительности.</p><p><strong>Ну и в заключение рассмотрим особенности записи в бинарные файлы при использовании &quot;SAPI.SpFileStream&quot; на чистом JScript</strong>:</p><div class="codebox"><pre><code>&lt;script language = VBScript&gt;

Function alert(message)                                                      &#039;заменим &quot;alert&quot; из JScript на более информативный метод для анализа данных
    Dim messageType
    messageType = TypeName(message)
    If messageType = &quot;String&quot; Or messageType = &quot;Byte()&quot; Then
        InputBox &quot;&quot;, &quot;Message from webpage&quot;, message
    Else
        InputBox &quot;&quot;, &quot;Message from webpage&quot;, TypeName(message)
    End If
End Function

&lt;/script&gt;

&lt;script language = JScript&gt;

var doc = GetObject(&#039;\\&#039;, &#039;htmlfile&#039;);
doc.write(&quot;&lt;xml&gt;&lt;_ xmlns:dt=&#039;urn:schemas-microsoft-com:datatypes&#039;&gt;&lt;_ dt:dt=&#039;bin.hex&#039;/&gt;&lt;/_&gt;&lt;/xml&gt;&quot;);
var xml = doc.documentElement.firstChild.children[1];
xml.preserveWhiteSpace = 1;

var hex = xml.firstChild.childNodes[0],

bytesToHex = function(bytes)
{
    if(typeof bytes == &#039;unknown&#039;)
    {
        hex.nodeTypedValue = bytes;
        return hex.text;
    }
    return bytes;
},

hexToBytes = function(hexString)                                        //функция для конвертации строкового шестнадцатеричного представления байтов в байты
{
    if(hexString)
    {
        hex.text = hexString;
        return hex.nodeTypedValue;
    }
    return bytes;
},

sourceRead = function(bytesCount)
{
    memory.Position = 0;
    memory.Type = 2;
    memory.Charset = &#039;Unicode&#039;;
    var stringBytes = source.ReadStream(1, bytesCount, 3);
    memory.WriteText(stringBytes);
    memory.SetEOS();
    memory.Position = 0;
    memory.Type = 1;
    memory.Position = 2;
    var bytes = memory.Read(bytesCount);
    return bytes;
}

var source = new ActiveXObject(&#039;WindowsInstaller.Installer&#039;).CreateRecord(1);
source.SetStream(1, &#039;C:\\Windows\\System32\\shell32.dll&#039;);

var memory = new ActiveXObject(&#039;ADODB.Stream&#039;);
memory.Open();

var output = new ActiveXObject(&#039;SAPI.SpFileStream&#039;);       //подготовим новый объект для работы с файловой системой
output.Format.Type = 1;                                                       //используем байты-текст как смешанный тип принимаемых данных (SAFTText = 1)
output.Open(&#039;output.bin&#039;, 3);                                                 //создаем и открываем файл для выгрузки данных на запись (SSFMCreateForWrite = 3)

var data = sourceRead(7);
var sourceData = bytesToHex(data);                                   //собираем байты источника в строковом шестнадцатеричном представлении для их последующего сравнения
                                                                                                    //с выгруженными данными
output.Write(data);                                                                //пишем первые 7 истинных байтов файла &quot;shell32.dll&quot; в файл для выгрузки данных

sourceData += &#039;313220000000&#039;;
output.Write(&#039;\u3231\x20&#039;);                                                    //пишем строковые байты в файл для выгрузки данных - используем Юникод для последующей нераздельной
                                                                                                    //передачи пары байтов строки &quot;12&quot;, а также пишем одиночный байт пробела, который “SAPI.SpFileStream&quot;
                                                                                                    //в силу своих особенностей превращает в 4 байта

data = &#039;68656c6c6f&#039;;
sourceData += data;
output.Write(hexToBytes(data));                                           //пишем байты строки &quot;hello&quot; в файл для выгрузки данных

data = sourceRead(10);
sourceData += bytesToHex(data);
output.Write(data);                                                                 //пишем следующие 10 (с 8-го по 17-й) истинных байтов файла &quot;shell32.dll&quot; в файл для выгрузки данных

output.Close();                                                                       //закрываем поток на запись файла для выгрузки данных
source.SetStream(1, &#039;output.bin&#039;);                                         //открываем файл выгрузки данных как текстовый поток файловой системы только для чтения
data = sourceRead(-1);                                                         //считываем все истинные байты файла выгрузки данных

doc.parentWindow.alert
(
    &#039;Source hexString: &#039; + sourceData +
    &#039;\n\nOutput hexString: &#039; + bytesToHex(data) +
    &#039;\n\nTotal true bytes count: &#039; + sourceData.length/2+&#039;.&#039;
);                                                                                             //сравниваем то, что записывали в файл выгрузки данных с тем, что в него записалось

&lt;/script&gt;</code></pre></div><p><strong>Подведем итоги</strong>:<br /></p><ul><li><p>&quot;<strong>SAPI.SpFileStream</strong>&quot; умеет <strong>писать как байты, так и строковые байты под любой локалью</strong>, однако необходимость в последних отпадает, если смотреть в сторону уменьшения обращений к жесткому диску и произведения необходимых операций преимущественно в памяти при использовании &quot;ADODB.Stream&quot;;</p></li><li><p>путем передачи пары байтов в &quot;SAPI.SpFileStream&quot; в виде символа в формате Юникод можно исключить возникновение лишних нулевых байтов, которые добавляет &quot;SAPI.SpFileStream&quot; в случае записи одиночных строковых байтов;</p></li><li><p>&quot;<strong>WindowsInstaller.Installer</strong>&quot; прекрасно выполняет свою функцию в комбинации с &quot;ADODB.Stream&quot; <strong>для чтения бинарных файлов под любой локалью</strong>;</p></li><li><p>&quot;<strong>ADODB.Stream</strong>&quot; прекрасно выполняет свои функции в качестве <strong>обработчика данных в оперативной памяти под любой локалью</strong>.</p></li></ul><p><strong>Примечания</strong>:<br /></p><ul><li><p>если данных очень много, то следует достигать баланса между работой в памяти и выгрузкой данных на жесткий диск.<br />Опыт разработки Resource Extractor показал, что JScript довольно слабо справляется с большими объемами данных в памяти, и производительность без промежуточных выгрузок на жесткий диск в этом случае начинает проседать;</p></li><li><p>&quot;SAPI.SpFileStream&quot; не может писать файлы с расширением &quot;wav&quot; в Windows XP при использовании параметра &quot;SAFTText = 1&quot;, что, ожидается, было устранено во всех последующих версиях Windows.</p></li></ul><p>Отдельно хочу поблагодарить <strong>JSman</strong> за <a href="http://forum.script-coding.com/viewtopic.php?pid=87857#p87857">примеры работы</a> с &quot;SAPI.SpFileStream&quot;, на которые я опирался при разработке, и <strong>Xameleon</strong> за изначальную подачу материала по &quot;SAPI.SpFileStream&quot; и примеры по <a href="http://forum.script-coding.com/viewtopic.php?pid=58136#p58136">hex-конвертации</a>.</p><p>Желаю всем удачных экспериментов с бинарными данными! Но, пожалуйста, будьте осторожны.</p>]]></description>
			<author><![CDATA[null@example.com (lifeflame)]]></author>
			<pubDate>Sun, 18 Oct 2020 21:21:37 +0000</pubDate>
			<guid>http://forum.script-coding.com/viewtopic.php?pid=142687#p142687</guid>
		</item>
	</channel>
</rss>
