Добро пожаловать, Гость. Пожалуйста авторизуйтесь здесь.
FGHIGate на GaNJa NeTWoRK ST@Ti0N - Просмотр сообщения в эхоконференции GANJANET.LOCAL
Введите FGHI ссылку:


Присутствуют сообщения из эхоконференции GANJANET.LOCAL с датами от 13 Oct 05 22:03:42 до 05 Aug 17 10:35:42, всего сообщений: 3030
Ответить на сообщение К списку сообщений Предыдущее сообщение Следующее сообщение
= Сообщение: 2653 из 3030 =================================== GANJANET.LOCAL =
От   : Mithgol the Webmaster            2:5063/88          26 Aug 08 15:13:40
Кому : Konstantin Kuzov                                    26 Aug 08 15:13:40
Тема : Твой GEd+ не игнорирует слэш после эхотага при входе в эху по URLу
FGHI : area://GANJANET.LOCAL?msgid=2:5063/88+48b3e5cd
= Кодировка сообщения определена как: CP866 ==================================
Ответ: area://GANJANET.LOCAL?msgid=2:5019/40.1+48bbb236
==============================================================================

Я попытался открыть вот такой URL:

area://1072.CompNews/?msgid=2:5029/45.45+8af55620

И нифига у меня не получилось: GoldEd+ сказал, что эхи '1072.CompNews/'
не существует.

Так не должно быть. Если бы я хотел открыть эху '1072.CompNews/', то URL был бы
другим:

area://1072.CompNews%2F?msgid=2:5029/45.45+8af55620

Из-за этого бага у меня создаётся впечатление, что ты, хотя и реализовывая
черновик 0.3 FGHI URL, всё же кинулся с нуля совершать достаточно большой труд
по созданию синтаксического разборщика URLов FGHI. За труд свой ты заслуживаешь
похвалы, однако я предпочёл бы, чтобы усилия твои не направлялись на повторное
изобретение хотя бы таких велосипедов, которые столь неуютнее изобретённых мною
прежде. Поэтому напомню, что разборщик URLов FGHI уж был опубликован мною менее
десяти месяцев тому назад, и код его GPL, так что ты мог бы им воспользоваться
при программировании. Код этот написан на JavaScript, но вряд ли ты найдёшь
так уж много отличий этого языка от C++ ── разве что встроенные функции работы
с регулярными выражениями, типа match() и split() ── но, как я слышал, в GEd+
какую-то библиотеку для работы с регулярными выражениями тоже вкомпилировали.

Так что я предлагаю тебе этот код с оптимизмом и надеждой на его полезность.

Вот письмо, содержащее HTML-код вебостраницы, внутри которой ── джаваскриптовый
код моего синтаксического разборщика URLов FGHI:

╔═════════════════════════════════════════════════════────────────────────────
║ Письмо из эхи:  FTSC_Public (Public echo of FTSC)
║ URL сообщения:  area://FTSC_Public?msgid=2:5063/88+472c2171
║ Автор и время:  Sergey Sokoloff, 2:5063/88 (03 Nov 07 10:04)
║ Кому написано:  Alexey Vissarionov
║ Заглавие темы:  FidoURL.txt
╚════════════════════════════════════════════════════════════════════─────────
@TZUTC: 0300

And about 00:03 31 Oct 07 it was written from Alexey Vissarionov to Sergey Sokoloff:

AV> Will there be a reference implementation?

As an addition to my previous letter, I don't mind admitting that for the
previous version of the draft (FGHI URL v0.3) I had a demo implementation,
a FGHI URL parser written on JavaScript and embedded in a HTML page.

Originally it was a part of an early non-public alpha version of my Fidofox
extension for Firefox, a JavaScript object I wrapped in HTML to make a demo:

<!DOCTYPE FGHI><html><head>
<title>The FGHI URL parser demonstration</title>
<script type="text/javascript"><!--
/*
 *  This JavaScript code is a part of Fidofox (Firefox extension for Fidonet)
 *  created by Mithgol the Webmaster, 2:5063/88, later redesigned as a demo.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
*/

   // An auxiliary parser function:
   // converts a %-encoded string to real string
   function decodeFGHIURL(encodedString){
      var spaceDecodedString = encodedString.replace(/\+/g, ' ');
      var SourceArray =
         spaceDecodedString.split(/((%[0-9ABCDEFabcdef][0-9ABCDEFabcdef])+)/);
      if (SourceArray.length == 1) {
         // No encoded content detected :-)
         return spaceDecodedString;
      } else {
         // Converting all URLencoded fragments
         var ijk;
         for (ijk = 1; ijk < SourceArray.length; ijk += 3){
            SourceArray[ijk] = decodeURIComponent(SourceArray[ijk]);
            SourceArray[ijk+1] = '';
         };
         return SourceArray.join('');
      };
   };

   //
   //  The FGHI URL object:
   //

   function FidonetURL(){  // FidonetURL constructor
      this.scheme = '';
   };

   FidonetURL.prototype = {
      // Possible exceptions:
      FGHI_URL_NO_SEPARATOR        : 'No :// separator in URL!',
      FGHI_URL_EMPTY_OPTIONAL_NAME : 'An optional parameter name is empty!',
      FGHI_URL_EMPTY_OPTIONAL_PAIR : 'Empty parameter+value pair detected!',
      FGHI_URL_INVALID_STATION : 'Fidonet station address violates FSP-1004!',
      FGHI_URL_EMPTY_AREA_NAME : 'Area name is empty!',
      FGHI_URL_DOUBLE_SLASH    : 'Unexpected double slash!',

      // Empty requests are invalid in FGHI URL post-0.3 drafts
      FGHI_URL_EMPTY_FAQ_REQUEST : 'FAQ request is empty!',

      FGHI_URL_UNKNOWN_SCHEME : 'Unknown Fidonet URL scheme!',

      // The station parser function:
      // slices station address (sets stationZone, stationNet,
      //                              stationNode, stationPoint, stationDomain)
      ParseStation : function (){
         var Parsed = this.station.match(
             /^(([0-9]+):)?([0-9]+)\/([0-9]+)(\.([0-9]+))?(@(.+))?$/
         );
         if (Parsed === null){
            throw this.FGHI_URL_INVALID_STATION;
         } else {
            this.stationZone = Parsed[2];
            if (this.stationZone === undefined) this.stationZone = '';

            this.stationNet  = Parsed[3];
            this.stationNode = Parsed[4];

            this.stationPoint = Parsed[6];
            if (this.stationPoint === undefined) this.stationPoint = '';

            this.stationDomain = Parsed[8];
            if (this.stationDomain === undefined) {
               this.stationDomain = ''
            } else this.stationDomain = decodeFGHIURL(this.stationDomain);
         };
      },

      // And when there is no station:
      NoStation : function (){
         this.station = '';
         this.stationZone   = '';
         this.stationNet    = '';
         this.stationNode   = '';
         this.stationPoint  = '';
         this.stationDomain = '';
      },

      // And when there is no object-path:
      NoObjectPath : function (){
         this.objectPath = '';
         this.objectPathPart = Array();
      },

      ParseObjectPath : function (){
         this.objectPathPart = Array();
         var PathBuf = this.objectPath;
         while (PathBuf.length > 0) {
            // next step: getting another slashed slice
            var SlashPos = PathBuf.indexOf('/');
            if (SlashPos < 0){
               // No more slashes!
               this.objectPathPart.push(decodeFGHIURL(PathBuf));
               PathBuf = '';
            } else if (SlashPos == 0){
               throw this.FGHI_URL_DOUBLE_SLASH;
            } else if (SlashPos == (PathBuf.length - 1)){
               // Trailing slash. IMPORTANT! Must not be ignored.
               this.objectPathPart.push(decodeFGHIURL(PathBuf.slice(0, -1)));
               this.objectPathPart.push('/');
               PathBuf = '';
            } else {
               // There are more slices yet.
               this.objectPathPart.push(
                  decodeFGHIURL(PathBuf.slice(0, SlashPos))
               );
               PathBuf = PathBuf.slice(SlashPos + 1);
            };
            // Another slashed slice got
         };
         // PathBuf completely processed.
      },

      // The main parser function:
      ParseFromString : function (pfsString){
         var SchemeSeparatorMatch = pfsString.match(/:(\/{2})?/);
                    // NB: the above regexp is greedy ^^^^^^^^
         if (SchemeSeparatorMatch === null) {
            throw this.FGHI_URL_NO_SEPARATOR;  // URL is invalid!
         };

         var SchemeSeparatorPosition =
                           pfsString.indexOf(SchemeSeparatorMatch[0]);
         var SchemeSeparatorMatchLen = SchemeSeparatorMatch[0].length;

         this.scheme = pfsString.slice(0, SchemeSeparatorPosition);
         this.scheme = this.scheme.toLowerCase(); // force ignore scheme case
         this.schemeSpecificPart = pfsString.slice(SchemeSeparatorPosition
                                                 + SchemeSeparatorMatchLen);

         var QuestionPos = this.schemeSpecificPart.indexOf('?');
         if (QuestionPos < 0) {
         // optional part is empty!
            this.optionalPart = '';
            this.requiredPart = this.schemeSpecificPart;
         } else {
         // optional part may be non-empty
            this.requiredPart =
               this.schemeSpecificPart.slice(0, QuestionPos);
            this.optionalPart =
               this.schemeSpecificPart.slice(QuestionPos + 1);
         };

         if (this.optionalPart == ''){
            // no optional params!
            this.optionalParam = new Array();
            // (this array would remain empty!
         } else {
            // parsing optional params...
            this.optionalParam = new Array();
            var optionalBuf = this.optionalPart;
            // if the optional parts ends with ampersand (&), kill it:
            if (optionalBuf.charAt(optionalBuf.length-1) == '&'){
               optionalBuf = optionalBuf.slice(0, -1);
            };
            while (optionalBuf.length > 0){
               // each step: getting the next param name+value pair
               var AmpersandPos = optionalBuf.indexOf('&');
               var ParamValuePair = '';
               if (AmpersandPos == 0) {
                  // Mistake: nothing precedes an ampersand,
                  // or unexpected double ampersand (&&) is encountered!
                  throw this.FGHI_URL_EMPTY_OPTIONAL_PAIR;
               } else if (AmpersandPos < 0) {
                  // No more ampersands!
                  ParamValuePair = optionalBuf;
                  optionalBuf = '';
               } else {
                  // grab the first remaining slice:
                  ParamValuePair = optionalBuf.slice(0, AmpersandPos);
                  optionalBuf = optionalBuf.slice(AmpersandPos + 1);
               };
               // optionalBuf decremented by the slice;
               // now we have ParamValuePair; let's parse it!
               var EqualsPos = ParamValuePair.indexOf('=');
               var ParamValueObject = new Object();
               if (EqualsPos == 0) {
                  // Mistake: empty parameter name!
                  throw this.FGHI_URL_EMPTY_OPTIONAL_NAME;
               } else if (EqualsPos < 0) {
                  // The equals sign is absent!
                  // The ParamValuePair contains just the name
                  ParamValueObject.name = decodeFGHIURL(ParamValuePair);
                  ParamValueObject.value = '';
               } else {
                  // grab the slices:
                  ParamValueObject.name =
                     decodeFGHIURL(ParamValuePair.slice(0, EqualsPos));
                  ParamValueObject.value =
                     decodeFGHIURL(ParamValuePair.slice(EqualsPos + 1));
               };
               // ParamValueObject is formed
               this.optionalParam.push(ParamValueObject);
            };
            // optionalBuf is processed
         };
         // this.optionalPart is processed.

         // Now we start parsing requiredPart.
         // This is going to be very scheme-specific.
         // Our goal is to fill one or more of the following:
         //
         // *) station (stationZone, stationNet, stationNode, stationPoint,
         //             stationDomain)
         //
         // *) echoName
         //
         // *) objectPath (and the objectPathPart[] array)
         //
         // *) request (for faqserv://)
         switch(this.scheme){
            // cases follow in order of appearance in the FGHI URL standard:
            case 'netmail':
               this.request = '';
               this.NoObjectPath();
               this.echoName = '';
               this.station = this.requiredPart;
               this.ParseStation();
            break;

            case 'areafix':
            case 'echomail':
               this.request = '';
               this.NoObjectPath();
               this.NoStation();
               this.echoName = decodeFGHIURL(this.requiredPart);
            break;

            case 'area':
            case 'fecho':
               this.request = '';
               this.NoStation();

               var SlashPos = this.requiredPart.indexOf('/');
               if (SlashPos < 0){
                  // No object-path!
                  this.NoObjectPath();
                  this.echoName = decodeFGHIURL(this.requiredPart);
               } else if (SlashPos == 0){
                  throw this.FGHI_URL_EMPTY_AREA_NAME;
               } else {
                  this.echoName =
                     decodeFGHIURL(this.requiredPart.slice(0, SlashPos));
                  this.objectPath = this.requiredPart.slice(SlashPos + 1);
                  this.ParseObjectPath();
               };
            break;

            case 'faqserv':
               var FirstSlashPos = this.requiredPart.indexOf('/');
               var FreqBuf = '';

               if (FirstSlashPos <= 0) throw this.FGHI_URL_INVALID_STATION;

               var SecondSlashPos = this.requiredPart.indexOf('/',
                                                         FirstSlashPos+1);
               if (SecondSlashPos < 0) {
                  // No request, no object-path
                  this.request = '';
                  this.NoObjectPath();
                  this.station = this.requiredPart;
                  this.ParseStation();
               } else {
                  this.station = this.requiredPart.slice(0, SecondSlashPos);
                  this.ParseStation();
                  FreqBuf = this.requiredPart.slice(SecondSlashPos + 1);

                  var ThirdSlashPos = FreqBuf.indexOf('/');
                  if (ThirdSlashPos < 0){
                     // No object-path!
                     this.NoObjectPath();
                     this.request = decodeFGHIURL(FreqBuf);
                  } else if (ThirdSlashPos == 0){
                     // Empty requests are invalid in FGHI URL post-0.3 drafts
                     throw this.FGHI_URL_EMPTY_FAQ_REQUEST;
                  } else {
                     this.request =
                        decodeFGHIURL(FreqBuf.slice(0, ThirdSlashPos));
                     this.objectPath = FreqBuf.slice(ThirdSlashPos + 1);
                     this.ParseObjectPath();
                  };
                  // Finished parsing request (and object-path, if exists)
               };
            break;

            case 'freq':
               this.request = '';

               var FirstSlashPos = this.requiredPart.indexOf('/');
               var FreqBuf = '';

               if (FirstSlashPos <= 0) throw this.FGHI_URL_INVALID_STATION;

               var SecondSlashPos = this.requiredPart.indexOf('/',
                                                         FirstSlashPos+1);
               if (SecondSlashPos < 0) {
                  // No object-path!
                  this.NoObjectPath();
                  this.station = this.requiredPart;
                  this.ParseStation();
               } else {
                  this.station = this.requiredPart.slice(0, SecondSlashPos);
                  this.ParseStation();
                  this.objectPath = this.requiredPart.slice(SecondSlashPos+1);
                  this.ParseObjectPath();
               };
            break;

            default:
               throw this.FGHI_URL_UNKNOWN_SCHEME;
            break;
         };
      },

      //
      //    Output functions:
      //

      PropertyRow : function (prName){
         var prData = eval('this.' + prName);
         var prHTML;

         if (prData === undefined) {
            prHTML = '<em>undefined</em>';
         } else if (prData === '') {
            prHTML = '<em>empty</em>';
         } else prHTML = prData;

         return '<tr><th>' + prName + '</th><td>' + prHTML
              + '</th></tr>';
      },

      PropertyArray : function (arrName){
         var paBuffer = this.PropertyRow(arrName + '.length');
         var paLen = eval('this.' + arrName + '.length');
         if (paLen > 0) {
            var paI;
            for (paI = 0; paI < paLen; paI++){
               paBuffer +=
                  this.PropertyRow(arrName + '[' + paI + '].name');
               paBuffer +=
                  this.PropertyRow(arrName + '[' + paI + '].value');
            }
         }
         return paBuffer;
      },

      SimpleArray : function (arrName){
         var saBuffer = this.PropertyRow(arrName + '.length');
         var saLen = eval('this.' + arrName + '.length');
         if (saLen > 0) {
            var saI;
            for (saI = 0; saI < saLen; saI++){
               saBuffer +=
                  this.PropertyRow(arrName + '[' + saI + ']');
            }
         }
         return saBuffer;
      },

      ToHTML : function (){
         var Buffer = '';
         Buffer += '<table cellspacing="1" cellpadding="4" border="1">';
         Buffer += this.PropertyRow('scheme');
         Buffer += this.PropertyRow('schemeSpecificPart');
         Buffer += this.PropertyRow('requiredPart');
         Buffer += this.PropertyRow('optionalPart');
         Buffer += this.PropertyArray('optionalParam');
         Buffer += this.PropertyRow('echoName');
         Buffer += this.PropertyRow('station');
         if (this.station !== ''){
            Buffer += this.PropertyRow('stationZone');
            Buffer += this.PropertyRow('stationNet');
            Buffer += this.PropertyRow('stationNode');
            Buffer += this.PropertyRow('stationPoint');
            Buffer += this.PropertyRow('stationDomain');
         };
         Buffer += this.PropertyRow('request');
         Buffer += this.PropertyRow('objectPath');
         Buffer += this.SimpleArray('objectPathPart');

         return Buffer;
      }
   }

   //
   //   Example of the real use:
   //

   function RunTheParser(){
      var FidoURL = new FidonetURL();
      try {
         FidoURL.ParseFromString(
            document.forms['FGHI'].elements['SourceURL'].value);
         document.getElementById('Results').innerHTML = FidoURL.ToHTML();
      } catch (catchedException) {
         document.getElementById('Results').innerHTML =
            '<b>Exception:</b> &nbsp; ' + catchedException;
      };
   };

// --></script>
</head><body onLoad="document.getElementById('RunParser').focus();">
<form name="FGHI" onSubmit="RunTheParser(); return false;">
<input style="width:75%;" type="text" name="SourceURL"
value="area://Ru.Blog.Mithgol/?msgid=" /><br />
<input type="submit" id="RunParser" value="Render">
</form>
<div id="Results"></div>
</body></html>


Though this script is already incompatible with v0.4 of FGHI URLs, it is almost
unavoidable that I'd make another (and very similar) implementation of FGHI URL
parser, v0.5-compatible, for the next version of my Fidofox, and I won't mind
sharing it as a similar demo file.



With best Fidonet 2.0 regards,
Mithgol the Webmaster.

... 153. My Legions of Terror will be an equal-opportunity employer.
■■■ Orcs are near, Alexey Vissarionov! My Golded 1.1.5-b20060515 is gleaming!..
 √ Origin: Be careful, the paranoid ones are always wathing you!.. (2:5063/88)
────────────────────────════════╪══╬═╣()╠═╬══╪════════────────────────────────

Должен предупредить, что в этом году я надеюсь создать улучшенный вариант кода,
учитывающий все те изменения, которые произойдут в стандарте FGHI URL по мере
появления его чистовика. Но даже черновая версия сбережёт тебе массу усилий,
я уверен. Если для понимания джаваскриптов тебе понадобится справочник языка,
то на http://www.ecma-international.org/publications/files/ecma-st/ECMA-262.pdf
ты сможешь скачать его невозбранно (хотя я должен предупредить, что этот PDF
является более стандартом, нежели пособием, так что очень многие обстоятельства
излагаются там с уклоном в недвусмысленность вплоть до занудности ── например,
используется BNF-запись определений).


Фидонет будет великим и гипертекстовым!    [Ru.Mozilla]     http://Mithgol.Ru/
Mithgol the Webmaster.                    [Братство Нод] [Team А я меняю subj]

... По судебнику 1497 года в России казнили за кражу холопов.
--- Эшелону: STEEPLEBUSH  RG  BSS  DDIS  миксмастер  европейская полиция  SARL
* Origin: Раньше у России был путь Ленина ── а теперь лень Путина (2:5063/88)

К главной странице гейта
Powered by NoSFeRaTU`s FGHIGate
Открытие страницы: 0.042435 секунды