Resource

Resource Basics

Resource Name Sort Into Season Collections
Resource Version 1.8
Category Catalog
Downloads 538
Release Date 11/5/2022 9:21:39 AM
 

Resource Details

Description A Photo Supreme script to sort items by season for selected
images, collections or portfolio. Sorted items are added to
season collections. Optionally, each item may be updated with
a season catalog label (keyword) in the Miscellaneous category,
if not already present.
Installation Instructions Download script.
Usage Instructions 1. Under Portfolios tab, select images, a Collection or a Portfolio
2. Open Scripter (Hamburger Menu->Tools->Scripter)
3. Load downloaded/edited script (Open->select script->Open)
4. Use Scripter to edit script settings as needed
5. Click Run

Note A. For detailed instructions see script header comment.
Note B. Downloaded script contains time and date data for Greenwich Mean Time (GMT), used to sort astronomical seasons.
Note C. Time and date data was sourced from NASA GISS and is for personal and non-commercial use only.
Note D. Use helper spreadsheet to format time and date data for other years.
Changes in this version Version: 1.7 2022-11-04
- added Acknowledgements section in script header
- replaced astropixels time and date data with NASA GISS data
- updated spreadsheet helper to use NASA GISS data
- various minor tweaks

Version: 1.8 2022-11-04
- changed AWStrListReportLine from TTntStringList to TStringList
- changed AWStrListReportText from TTntStringList to TStringList
- added UTF-8 encoding to csv lines using UTF8Encode
Special Requirements Excel/LibreOffice/etc to open spreadsheet
 

Author Information

Author Name Michael Biggs
 

Available Attachments

Attachment #1 Sort Into Season Collections HELPER SPREADSHEET.xlsx
 

Script

//----------------------------------------------------------------------------80
{
  Author: Michael James Biggs
  Initial Date: 2022-10-31
  Version: 1.0

  Version: 1.1    2022-10-31
      - added ability to distinguish astronomical seasons in Northern and
        Southern hemispheres using functions:
            funcGetSeasonAstroNorth
            funcGetSeasonAstroSouth
      - various minor tweaks

  Version: 1.2    2022-11-01
      - replaced use of UpperCase by WideUpperCase
      - replaced use of LowerCase by WideLowerCase
      - replaced PublicCatalog.EnumCategoryNamed('Miscellaneous', ACategory)
        by       PublicCatalog.EnumCategory(KeywordsGUID, ACategory, False)
      - added function funcFormatISODateTimeString
      - updated astronomical functions to use ISO DateTime string conversions
            funcGetSeasonAstroNorth
            funcGetSeasonAstroSouth
      - appended astropixels GMT data set to end of script
      - updated spreadsheet helper to include astropixels GMT data set
      - various minor tweaks

  Version: 1.3    2022-11-02
      - updated functions to use DateTimeToISODateString
            funcGetSeasonAstroNorth
            funcGetSeasonAstroSouth
            funcGetSeasonMeteoNorth
            funcGetSeasonMeteoSouth
      - various minor tweaks

  Version: 1.4    2022-11-02
      - changed AWStrListReportText from TStringList to TTntStringList
      - changed ChangeFileExt to WideChangeFileExt
      - changed DirectoryExists to WideDirectoryExists
      - changed CreateDir to WideForceDirectories
      - for AWStrListReportText, enclosed file names in double quotes to allow
        for file names containing commas
      - various minor tweaks

  Version: 1.5    2022-11-02
      - improved formatting of csv lines for AWStrListReportText
            csv lines are now constructed by first adding items to a line
            TTntStringList then using member identifier '.CommaText' to add that
            list as a single csv line to AWStrListReportText
            (using '.CommaText' automatically escapes items containing spaces
             and commas by enclosing them in double quotes)

  Version: 1.6    2022-11-03
      - updated AWStrReportPath to use default windows document path if no user
        path specified
      - renamed cATextEditor as cAEditor
      - set cAScriptReportPath to null, to use default windows document path
      - set cAEditor to null, to use default editor associated with '.csv' files
      - moved astropixels table to separate document
      - various minor tweaks

  Version: 1.7    2022-11-04
      - added Acknowledgements section in script header
      - replaced astropixels time and date data with NASA GISS data
      - updated spreadsheet helper to use NASA GISS data
      - various minor tweaks

  Version: 1.8    2022-11-04
      - changed AWStrListReportLine from TTntStringList to TStringList
      - changed AWStrListReportText from TTntStringList to TStringList
      - added UTF-8 encoding to csv lines using UTF8Encode

  Name: Sort Into Season Collections.psc

  Full Name: PSU_Sort__for_Selected_Images_Collection_or_Portfolio__Files_into_
             Seasons__Astronomical_and_Meteorological__LABEL.psc

  Description: A Photo Supreme script to sort items by season for selected
               images, collections or portfolio.  Sorted items are added to
               season collections.  Optionally, each item may be updated with
               a season catalog label (keyword) in the KeywordsGUID category,
               (ie 'Miscellaneous'), if not already present.

  Usage: Download script
         Use a text editor to edit downloaded script
         Change settings as needed (see below) and save
         Place script in Photo Supreme script folder:
             ...\IDimager Products\Photo Supreme x64\Resources\Scripts
         Open Photo Supreme
         Under Portfolios tab, select images, a Collection or a Portfolio
         Open Scripter (Hamburger Menu->Tools->Scripter)
         Load downloaded/edited script (Open->select script->Open)
         Use Scripter to edit script settings as needed (see below)
         Click Run

  Seasons: Astronomical seasons:
               Edit script to remove or replace time and date data as needed;
                   search script for 'TIME AND DATE DATA SET'
               Follow instructions in 'HELPER' spreadsheet to get data in
               suitable format then copy and paste as necessary.
               Edit script to change constant values as needed:
                   cASeasonAstroSort       sort astronomical [0=no, 1=yes]
                   cASeasonAstroDataSet    data set description
           Meteorological seasons:
               Edit script to change constant values as needed:
                   cASeasonMeteoSort       sort meteorological [0=no, 1=yes]
           Hemisphere:
               Edit script to change constant value as needed:
                   cASeasonHemisphere      'Northern' or 'Southern'
           Season label:
               Edit script to change constant value as needed:
                   cASeasonAddLabel        add season label [0=no, 1=yes]

  Settings: Edit the script to change the following constant values as needed:
                cASaveReport          save report [0=no, 1=yes]
                cAScriptReportDir     report directory
                cAScriptReportName    report file name
                cAScriptReportPath    report folder path
                cAShowDialog          show dialog [0=no, 1=yes]
                cAEditor              editor path to open report '.csv' file

  Warning: If cASeasonAddLabel is set to 1, original files will be modified
           unless 'auto-sync' checkbox is unchecked.
           (Preferences->Synchronize Settings->Automatically write out...)

  PSU: Tested with: IDimager Photo Supreme [build 5.6.0.3432 (64 bit)]
                    IDimager Photo Supreme [build 6.7.2.4229 (64 bit)]
                    IDimager Photo Supreme [build 7.4.1.4604 (64 bit)]

  System: Tested with: Microsoft Windows 10 Home (x64)
                       [Version 21H2 Build 19044.2130]

  Disclaimer: Use at own risk.  Recommend backing up catalog before use.

  Acknowledgements: Thanks to IDimager for feedback, code advice
                    and encouragement.

  Reference: Based on scripts and code snippets authored by IDimager
             (and others), either stored in the Photo Supreme Resource
             Repository or presented in the Photo Supreme User-To-User Forum.
}

const
  cASaveReport  = 1; // [0=no, 1=yes]
  cAScriptName = 'Sort Into Season Collections.psc';
  cAScriptFullName = 'Sort__for_Selected_Images_Collection_or_Portfolio__' +
                     'Files_into_Seasons__Astronomical_and_Meteorological__' +
                     'LABEL.psc';
  cAScriptReportDir = 'Photo_Supreme_Script_Report';
  cAScriptReportName = 'script_report.csv';
  // specified folder path must terminate in backslash '\', for example:
  //     cAScriptReportPath = 'C:\Users\<username>\Documents\';
  // assign null string '' to use default windows document path
  cAScriptReportPath = '';
  cASeasonAddLabel = 0; // [0=no, 1=yes]
  cASeasonAstroSort = 1; // [0=no, 1=yes]
  cASeasonAstroDataSet = 'NASA GISS (GMT)';
  cASeasonHemisphere = 'Northern';
  cASeasonMeteoSort = 1; // [0=no, 1=yes]
  cAShowDialog  = 1; // [0=no, 1=yes]
  // specified editor must use full path, for example:
  //     cAEditor = 'C:\Program Files\Notepad++\notepad++.exe';
  // assign null string '' to use default editor associated with '.csv' files,
  // ie Excel/LibreOffice/etc
  cAEditor = '';

var
  gATStrListCatItemGUID: TTntStringList; // global var
  gATStrListCatItemParentGUID: TTntStringList; // global var
  //gACatItemsArray: TidElement; // global var // FOR ARRAY METHOD

  //--------------------------------------------------------------------------80
  function funcChangeToTitleCase(AWStrText: WideString): WideString;
  begin
    result := WideUppercase(LeftStr(AWStrText, 1)) +
              WideLowerCase(RightStr(AWStrText, Length(AWStrText) - 1));
  end;

  //--------------------------------------------------------------------------80
  procedure procLabelImgItem(AImage: TImageItem; ALabel: WideString);
  // KeywordsGUID = '{6B36224B-1405-47A0-8430-573229C8CCB9}'
  // is equivalent to 'Miscellaneous' category
  var
    ACatItem: TCatalogItem;
    AProp: TCatalogItemProp;
  begin
    ACatItem := TCatalogItem.Create(nil);
    AProp := TCatalogItemProp.Create(nil);
    // get main version
    if PublicCatalog.FindImageCombined (AImage, ACatItem, True, vptNone) then
    begin
      // check for existing catalog prop with name ALabel
      // (FindPropByName: assigns value to AProp as first matching prop found
      //  from non ordered list of props; this means prop ALabel added to
      //  catalog item may be from KeywordsGUID category, but equally may be
      //  from some other category)
      if not PublicCatalog.FindPropByName (ALabel, AProp, '', True) then
      begin
        // match not found so create one in KeywordsGUID category
        AProp.GUID := NewGUID;  // give a unique ID
        AProp.PropName := ALabel;
        PublicCatalog.StorePropToDatabase (AProp, KeywordsGUID, False);
      end;
      // assign prop, (match pre-existing or newly created), to catalog item
      PublicCatalog.AddPropToItem (ACatItem, AProp, False, False);
    end;
    AProp.Free;
    ACatItem.Free;
  end;

  //--------------------------------------------------------------------------80
  procedure procLabelImgItemKeywords(AImage: TImageItem; ALabel: WideString);
  // KeywordsGUID = '{6B36224B-1405-47A0-8430-573229C8CCB9}'
  // is equivalent to 'Miscellaneous' category
  var
    ACatItem: TCatalogItem;
    AProp: TCatalogItemProp;
    ACategory: TCatalogPropCategory;
  begin
    ACatItem := TCatalogItem.Create(nil);
    AProp := TCatalogItemProp.Create(nil);
    AProps := TCatalogItemProps.Create(TCatalogItemProp, '');
    ACategory := TCatalogPropCategory.Create(nil);
    // get main version
    if PublicCatalog.FindImageCombined(AImage, ACatItem, True, vptNone) then
    begin
      // if KeywordsGUID category exists
      if PublicCatalog.EnumCategory(KeywordsGUID, ACategory, False) then
      begin
        // check for existing prop with name ALabel in KeywordsGUID category
        if not PublicCatalog.EnumPropName(ACategory.GUID, ALabel, AProp, False) then
        begin
          // no prop found so create new one in KeywordsGUID category
          AProp.GUID := NewGUID;  // give a unique ID
          AProp.PropName := ALabel;
          PublicCatalog.StorePropToDatabase(AProp, KeywordsGUID, False);
        end;
        // assign prop from KeywordsGUID category
        PublicCatalog.AddPropToItem(ACatItem, AProp, False, False);
      end;
      // else do nothing
    end;
    ACatItem.Free;
    AProp.Free;
    ACategory.Free;
  end;

  //--------------------------------------------------------------------------80
  procedure procDeleteTStrListDupCatItem;
  var
    i: Integer;
  begin
    for i := gATStrListCatItemGUID.Count - 1 downto 1 do // global var
    begin
      if gATStrListCatItemGUID.IndexOf(gATStrListCatItemGUID.Strings[i]) <> i then // global var
      begin
        gATStrListCatItemGUID.Delete(i); // global var
        gATStrListCatItemParentGUID.Delete(i); // global var
      end;
    end;
  end;

  //--------------------------------------------------------------------------80
  function funcAddArrayElemCatItem(AArray: TidElement;
                                   ACatItemGUID: WideString;
                                   ACatItemParentGUID: WideString): TidElement;
  begin
    result := AArray.Elements.Add;
    result.Prop['CatItemGUID'] := ACatItemGUID;
    result.Prop['CatItemParentGUID'] := ACatItemParentGUID;
  end;

  //--------------------------------------------------------------------------80
  function funcCreateCollection(ACGUIDParent: WideString;
                                ACName: WideString;
                                ACDescription: WideString): TImageCollection;
  var
    AImageColls: TImageCollections;
    AImageColl: TImageCollection;
  begin
    // load AImageColls with all current collection names
    // for parent ACGUIDParent
    AImageColls := TImageCollections.Create(TImageCollection, '');
    PublicCatalog.EnumCollectionsForParent(ACGUIDParent,
                                           AImageColls);
    // check if collection already exists
    AImageColl := AImageColls.FindNamed(ACName);
    if AImageColl = nil then
    begin
      // create collection if doesn't already exist
      AImageColl := TImageCollection.Create(nil);
      AImageColl.CollectionName := ACName;
      AImageColl.CollectionDescription := ACDescription;
      PublicCatalog.StoreCollectionToParentSimple(ACGUIDParent,
                                                  AImageColl);
    end;
    Result := AImageColl;
  end;

  //--------------------------------------------------------------------------80
  procedure procGetCollAllCatItems(AColl: TImageCollection);
  // (RECURSIVE)
  var
    i: Integer;
    ACatItems: TCatalogItems;
    ASubColls: TImageCollections;
  begin
    // get catalogue items
    ACatItems := TCatalogItems.Create(TCatalogItem, '');
    PublicCatalog.EnumItemsInCollection(AColl, ACatItems);
    if ACatItems.Count > 0 then
    begin
      for i := 0 to ACatItems.Count - 1 do
      begin
        //funcAddArrayElemCatItem(gACatItemsArray, ACatItems.Items[i].GUID, AColl.GUID); // CALL FUNC // global var // FOR ARRAY METHOD
        gATStrListCatItemGUID.Add(ACatItems.Items[i].GUID); // global var
        gATStrListCatItemParentGUID.Add(AColl.GUID); // global var
      end;
    end;
    ACatItems.Free;
    // process sub collections
    if PublicCatalog.CollectionHasCollections(AColl.GUID) then
    begin
      ASubColls := TImageCollections.Create(TImageCollection, '');
      PublicCatalog.EnumCollectionCollections(AColl, ASubColls);
      if ASubColls.Count > 0 then
      begin
        for i := 0 to ASubColls.Count - 1 do
          procGetCollAllCatItems(ASubColls.Items[i]); // CALL PROC
      end;
      ASubColls.Free;
    end;
  end;

  //--------------------------------------------------------------------------80
  procedure procGetCollsAllCatItems(AColls: TImageCollections);
  // (RECURSIVE)
  var
    i, j: Integer;
    ACatItems: TCatalogItems;
    ASubColls: TImageCollections;
  begin
    if AColls.Count > 0 then
    begin
      for i := 0 to AColls.Count - 1 do
      begin
        // count catalogue items in sub collection
        ACatItems := TCatalogItems.Create(TCatalogItem, '');
        PublicCatalog.EnumItemsInCollection(AColls.Items[i], ACatItems);
        if ACatItems.Count > 0 then
        begin
          for j := 0 to ACatItems.Count - 1 do
          begin
            //funcAddArrayElemCatItem(gACatItemsArray, ACatItems.Items[j].GUID, AColls.Items[i].GUID); // CALL FUNC // global var // FOR ARRAY METHOD
            gATStrListCatItemGUID.Add(ACatItems.Items[j].GUID); // global var
            gATStrListCatItemParentGUID.Add(AColls.Items[i].GUID); // global var
          end;
        end;
        ACatItems.Free;
        // process sub collections in sub collection
        if PublicCatalog.CollectionHasCollections(AColls.Items[i].GUID) then
        begin
          ASubColls := TImageCollections.Create(TImageCollection, '');
          PublicCatalog.EnumCollectionCollections(AColls.Items[i], ASubColls);
          procGetCollsAllCatItems(ASubColls); // CALL PROC
          ASubColls.Free;
        end;
      end;
    end;
  end;

  //--------------------------------------------------------------------------80
  procedure procCreatePortfolioGUID(APortfolioGUID: WideString;
                                    APortfolioName: WideString;
                                    APortfolioDescription: WideString);
  var
    APortfolio: TImageModel;
    AGallery: TImageGallery;
  begin
    // create portfolio (with gallery) if doesn't already exist
    APortfolio := TImageModel.Create(nil);
    if not PublicCatalog.EnumModel(APortfolioGUID, APortfolio) then
    begin
      APortfolio := TImageModel.Create(nil);
      try
        APortfolio.ModelName := APortfolioName;
        APortfolio.Description := APortfolioDescription;
        APortfolio.Galleries.Clear;
        AGallery := APortfolio.Galleries.Add as TImageGallery;
        AGallery.GalleryName := APortfolio.ModelName;
        AGallery.Collections.Clear;
        PublicCatalog.StoreModelToDatabase(APortfolio);
      finally
        AGallery.Free;
        APortfolio.Free;
      end;
    end;
  end;

  //--------------------------------------------------------------------------80
  procedure procCreatePortfolioNamed(APortfolioName: WideString;
                                     APortfolioDescription: WideString);
  var
    APortfolio: TImageModel;
    AGallery: TImageGallery;
  begin
    // create portfolio (with gallery) if doesn't already exist
    APortfolio := TImageModel.Create(nil);
    if not PublicCatalog.EnumModelNamed(APortfolioName, APortfolio) then
    begin
      APortfolio := TImageModel.Create(nil);
      try
        APortfolio.ModelName := APortfolioName;
        APortfolio.Description := APortfolioDescription;
        APortfolio.Galleries.Clear;
        AGallery := APortfolio.Galleries.Add as TImageGallery;
        AGallery.GalleryName := APortfolio.ModelName;
        AGallery.Collections.Clear;
        PublicCatalog.StoreModelToDatabase(APortfolio);
      finally
        AGallery.Free;
        APortfolio.Free;
      end;
    end;
  end;

  //--------------------------------------------------------------------------80
  function funcAddArrayElem(AArray: TidElement;
                            AYear: WideString;
                            AMarE, AJunS, ASepE, ADecS: WideString): TidElement;
  begin
    result := AArray.Elements.Add;
    result.Prop['Year'] := AYear;
    result.Prop['MarE'] := AMarE; // March Equinox
    result.Prop['JunS'] := AJunS; // June Solstice
    result.Prop['SepE'] := ASepE; // September Equinox
    result.Prop['DecS'] := ADecS; // December Solstice
  end;

  //--------------------------------------------------------------------------80
  function funcInitArray: TidElement;
  var
    AElem: TidElement;
  begin
    result := TidElement.Create(nil);
    //**************************************************************************
    //**************************************************************************
    //*************************************************** TIME AND DATE DATA SET
    //**************************************************************************
    //**************************************************************************
    // website:     NASA Goddard Institute for Space Studies
    // year:        2022
    // title:       Time and Date of Vernal Equinox: 1800 to 2100
    // accessed:    2022-11-04
    // url:         https://data.giss.nasa.gov/modelE/ar5plots/srvernal.html
    funcAddArrayElem( result, '1800', '1800-03-20 19:30', '1800-06-21 17:15', '1800-09-23 06:48', '1800-12-21 23:34' ); // CALL FUNC
    funcAddArrayElem( result, '1801', '1801-03-21 01:19', '1801-06-21 23:03', '1801-09-23 12:36', '1801-12-22 05:24' ); // CALL FUNC
    funcAddArrayElem( result, '1802', '1802-03-21 07:08', '1802-06-22 04:51', '1802-09-23 18:25', '1802-12-22 11:14' ); // CALL FUNC
    funcAddArrayElem( result, '1803', '1803-03-21 12:58', '1803-06-22 10:39', '1803-09-24 00:14', '1803-12-22 17:04' ); // CALL FUNC
    funcAddArrayElem( result, '1804', '1804-03-20 18:47', '1804-06-21 16:28', '1804-09-23 06:03', '1804-12-21 22:54' ); // CALL FUNC
    funcAddArrayElem( result, '1805', '1805-03-21 00:36', '1805-06-21 22:16', '1805-09-23 11:52', '1805-12-22 04:43' ); // CALL FUNC
    funcAddArrayElem( result, '1806', '1806-03-21 06:25', '1806-06-22 04:04', '1806-09-23 17:40', '1806-12-22 10:33' ); // CALL FUNC
    funcAddArrayElem( result, '1807', '1807-03-21 12:14', '1807-06-22 09:52', '1807-09-23 23:29', '1807-12-22 16:23' ); // CALL FUNC
    funcAddArrayElem( result, '1808', '1808-03-20 18:04', '1808-06-21 15:40', '1808-09-23 05:18', '1808-12-21 22:13' ); // CALL FUNC
    funcAddArrayElem( result, '1809', '1809-03-20 23:53', '1809-06-21 21:28', '1809-09-23 11:07', '1809-12-22 04:03' ); // CALL FUNC
    funcAddArrayElem( result, '1810', '1810-03-21 05:42', '1810-06-22 03:16', '1810-09-23 16:56', '1810-12-22 09:52' ); // CALL FUNC
    funcAddArrayElem( result, '1811', '1811-03-21 11:31', '1811-06-22 09:05', '1811-09-23 22:44', '1811-12-22 15:42' ); // CALL FUNC
    funcAddArrayElem( result, '1812', '1812-03-20 17:20', '1812-06-21 14:53', '1812-09-23 04:33', '1812-12-21 21:32' ); // CALL FUNC
    funcAddArrayElem( result, '1813', '1813-03-20 23:10', '1813-06-21 20:41', '1813-09-23 10:22', '1813-12-22 03:22' ); // CALL FUNC
    funcAddArrayElem( result, '1814', '1814-03-21 04:59', '1814-06-22 02:29', '1814-09-23 16:11', '1814-12-22 09:11' ); // CALL FUNC
    funcAddArrayElem( result, '1815', '1815-03-21 10:48', '1815-06-22 08:17', '1815-09-23 21:59', '1815-12-22 15:01' ); // CALL FUNC
    funcAddArrayElem( result, '1816', '1816-03-20 16:37', '1816-06-21 14:05', '1816-09-23 03:48', '1816-12-21 20:51' ); // CALL FUNC
    funcAddArrayElem( result, '1817', '1817-03-20 22:26', '1817-06-21 19:54', '1817-09-23 09:37', '1817-12-22 02:41' ); // CALL FUNC
    funcAddArrayElem( result, '1818', '1818-03-21 04:16', '1818-06-22 01:42', '1818-09-23 15:26', '1818-12-22 08:31' ); // CALL FUNC
    funcAddArrayElem( result, '1819', '1819-03-21 10:05', '1819-06-22 07:30', '1819-09-23 21:15', '1819-12-22 14:20' ); // CALL FUNC
    funcAddArrayElem( result, '1820', '1820-03-20 15:54', '1820-06-21 13:18', '1820-09-23 03:03', '1820-12-21 20:10' ); // CALL FUNC
    funcAddArrayElem( result, '1821', '1821-03-20 21:43', '1821-06-21 19:06', '1821-09-23 08:52', '1821-12-22 02:00' ); // CALL FUNC
    funcAddArrayElem( result, '1822', '1822-03-21 03:32', '1822-06-22 00:54', '1822-09-23 14:41', '1822-12-22 07:50' ); // CALL FUNC
    funcAddArrayElem( result, '1823', '1823-03-21 09:22', '1823-06-22 06:43', '1823-09-23 20:30', '1823-12-22 13:40' ); // CALL FUNC
    funcAddArrayElem( result, '1824', '1824-03-20 15:11', '1824-06-21 12:31', '1824-09-23 02:19', '1824-12-21 19:29' ); // CALL FUNC
    funcAddArrayElem( result, '1825', '1825-03-20 21:00', '1825-06-21 18:19', '1825-09-23 08:07', '1825-12-22 01:19' ); // CALL FUNC
    funcAddArrayElem( result, '1826', '1826-03-21 02:49', '1826-06-22 00:07', '1826-09-23 13:56', '1826-12-22 07:09' ); // CALL FUNC
    funcAddArrayElem( result, '1827', '1827-03-21 08:38', '1827-06-22 05:55', '1827-09-23 19:45', '1827-12-22 12:59' ); // CALL FUNC
    funcAddArrayElem( result, '1828', '1828-03-20 14:28', '1828-06-21 11:43', '1828-09-23 01:34', '1828-12-21 18:48' ); // CALL FUNC
    funcAddArrayElem( result, '1829', '1829-03-20 20:17', '1829-06-21 17:31', '1829-09-23 07:22', '1829-12-22 00:38' ); // CALL FUNC
    funcAddArrayElem( result, '1830', '1830-03-21 02:06', '1830-06-21 23:20', '1830-09-23 13:11', '1830-12-22 06:28' ); // CALL FUNC
    funcAddArrayElem( result, '1831', '1831-03-21 07:55', '1831-06-22 05:08', '1831-09-23 19:00', '1831-12-22 12:18' ); // CALL FUNC
    funcAddArrayElem( result, '1832', '1832-03-20 13:44', '1832-06-21 10:56', '1832-09-23 00:49', '1832-12-21 18:08' ); // CALL FUNC
    funcAddArrayElem( result, '1833', '1833-03-20 19:34', '1833-06-21 16:44', '1833-09-23 06:38', '1833-12-21 23:57' ); // CALL FUNC
    funcAddArrayElem( result, '1834', '1834-03-21 01:23', '1834-06-21 22:32', '1834-09-23 12:26', '1834-12-22 05:47' ); // CALL FUNC
    funcAddArrayElem( result, '1835', '1835-03-21 07:12', '1835-06-22 04:20', '1835-09-23 18:15', '1835-12-22 11:37' ); // CALL FUNC
    funcAddArrayElem( result, '1836', '1836-03-20 13:01', '1836-06-21 10:09', '1836-09-23 00:04', '1836-12-21 17:27' ); // CALL FUNC
    funcAddArrayElem( result, '1837', '1837-03-20 18:50', '1837-06-21 15:57', '1837-09-23 05:53', '1837-12-21 23:17' ); // CALL FUNC
    funcAddArrayElem( result, '1838', '1838-03-21 00:40', '1838-06-21 21:45', '1838-09-23 11:41', '1838-12-22 05:06' ); // CALL FUNC
    funcAddArrayElem( result, '1839', '1839-03-21 06:29', '1839-06-22 03:33', '1839-09-23 17:30', '1839-12-22 10:56' ); // CALL FUNC
    funcAddArrayElem( result, '1840', '1840-03-20 12:18', '1840-06-21 09:21', '1840-09-22 23:19', '1840-12-21 16:46' ); // CALL FUNC
    funcAddArrayElem( result, '1841', '1841-03-20 18:07', '1841-06-21 15:09', '1841-09-23 05:08', '1841-12-21 22:36' ); // CALL FUNC
    funcAddArrayElem( result, '1842', '1842-03-20 23:56', '1842-06-21 20:57', '1842-09-23 10:56', '1842-12-22 04:25' ); // CALL FUNC
    funcAddArrayElem( result, '1843', '1843-03-21 05:46', '1843-06-22 02:46', '1843-09-23 16:45', '1843-12-22 10:15' ); // CALL FUNC
    funcAddArrayElem( result, '1844', '1844-03-20 11:35', '1844-06-21 08:34', '1844-09-22 22:34', '1844-12-21 16:05' ); // CALL FUNC
    funcAddArrayElem( result, '1845', '1845-03-20 17:24', '1845-06-21 14:22', '1845-09-23 04:23', '1845-12-21 21:55' ); // CALL FUNC
    funcAddArrayElem( result, '1846', '1846-03-20 23:13', '1846-06-21 20:10', '1846-09-23 10:12', '1846-12-22 03:45' ); // CALL FUNC
    funcAddArrayElem( result, '1847', '1847-03-21 05:02', '1847-06-22 01:58', '1847-09-23 16:00', '1847-12-22 09:34' ); // CALL FUNC
    funcAddArrayElem( result, '1848', '1848-03-20 10:52', '1848-06-21 07:46', '1848-09-22 21:49', '1848-12-21 15:24' ); // CALL FUNC
    funcAddArrayElem( result, '1849', '1849-03-20 16:41', '1849-06-21 13:35', '1849-09-23 03:38', '1849-12-21 21:14' ); // CALL FUNC
    funcAddArrayElem( result, '1850', '1850-03-20 22:30', '1850-06-21 19:23', '1850-09-23 09:27', '1850-12-22 03:04' ); // CALL FUNC
    funcAddArrayElem( result, '1851', '1851-03-21 04:19', '1851-06-22 01:11', '1851-09-23 15:15', '1851-12-22 08:53' ); // CALL FUNC
    funcAddArrayElem( result, '1852', '1852-03-20 10:08', '1852-06-21 06:59', '1852-09-22 21:04', '1852-12-21 14:43' ); // CALL FUNC
    funcAddArrayElem( result, '1853', '1853-03-20 15:58', '1853-06-21 12:47', '1853-09-23 02:53', '1853-12-21 20:33' ); // CALL FUNC
    funcAddArrayElem( result, '1854', '1854-03-20 21:47', '1854-06-21 18:35', '1854-09-23 08:42', '1854-12-22 02:23' ); // CALL FUNC
    funcAddArrayElem( result, '1855', '1855-03-21 03:36', '1855-06-22 00:23', '1855-09-23 14:30', '1855-12-22 08:13' ); // CALL FUNC
    funcAddArrayElem( result, '1856', '1856-03-20 09:25', '1856-06-21 06:12', '1856-09-22 20:19', '1856-12-21 14:02' ); // CALL FUNC
    funcAddArrayElem( result, '1857', '1857-03-20 15:14', '1857-06-21 12:00', '1857-09-23 02:08', '1857-12-21 19:52' ); // CALL FUNC
    funcAddArrayElem( result, '1858', '1858-03-20 21:04', '1858-06-21 17:48', '1858-09-23 07:57', '1858-12-22 01:42' ); // CALL FUNC
    funcAddArrayElem( result, '1859', '1859-03-21 02:53', '1859-06-21 23:36', '1859-09-23 13:46', '1859-12-22 07:32' ); // CALL FUNC
    funcAddArrayElem( result, '1860', '1860-03-20 08:42', '1860-06-21 05:24', '1860-09-22 19:34', '1860-12-21 13:21' ); // CALL FUNC
    funcAddArrayElem( result, '1861', '1861-03-20 14:31', '1861-06-21 11:12', '1861-09-23 01:23', '1861-12-21 19:11' ); // CALL FUNC
    funcAddArrayElem( result, '1862', '1862-03-20 20:20', '1862-06-21 17:00', '1862-09-23 07:12', '1862-12-22 01:01' ); // CALL FUNC
    funcAddArrayElem( result, '1863', '1863-03-21 02:10', '1863-06-21 22:49', '1863-09-23 13:01', '1863-12-22 06:51' ); // CALL FUNC
    funcAddArrayElem( result, '1864', '1864-03-20 07:59', '1864-06-21 04:37', '1864-09-22 18:49', '1864-12-21 12:41' ); // CALL FUNC
    funcAddArrayElem( result, '1865', '1865-03-20 13:48', '1865-06-21 10:25', '1865-09-23 00:38', '1865-12-21 18:30' ); // CALL FUNC
    funcAddArrayElem( result, '1866', '1866-03-20 19:37', '1866-06-21 16:13', '1866-09-23 06:27', '1866-12-22 00:20' ); // CALL FUNC
    funcAddArrayElem( result, '1867', '1867-03-21 01:26', '1867-06-21 22:01', '1867-09-23 12:16', '1867-12-22 06:10' ); // CALL FUNC
    funcAddArrayElem( result, '1868', '1868-03-20 07:16', '1868-06-21 03:49', '1868-09-22 18:04', '1868-12-21 12:00' ); // CALL FUNC
    funcAddArrayElem( result, '1869', '1869-03-20 13:05', '1869-06-21 09:38', '1869-09-22 23:53', '1869-12-21 17:49' ); // CALL FUNC
    funcAddArrayElem( result, '1870', '1870-03-20 18:54', '1870-06-21 15:26', '1870-09-23 05:42', '1870-12-21 23:39' ); // CALL FUNC
    funcAddArrayElem( result, '1871', '1871-03-21 00:43', '1871-06-21 21:14', '1871-09-23 11:31', '1871-12-22 05:29' ); // CALL FUNC
    funcAddArrayElem( result, '1872', '1872-03-20 06:32', '1872-06-21 03:02', '1872-09-22 17:19', '1872-12-21 11:19' ); // CALL FUNC
    funcAddArrayElem( result, '1873', '1873-03-20 12:22', '1873-06-21 08:50', '1873-09-22 23:08', '1873-12-21 17:08' ); // CALL FUNC
    funcAddArrayElem( result, '1874', '1874-03-20 18:11', '1874-06-21 14:38', '1874-09-23 04:57', '1874-12-21 22:58' ); // CALL FUNC
    funcAddArrayElem( result, '1875', '1875-03-21 00:00', '1875-06-21 20:26', '1875-09-23 10:46', '1875-12-22 04:48' ); // CALL FUNC
    funcAddArrayElem( result, '1876', '1876-03-20 05:49', '1876-06-21 02:15', '1876-09-22 16:34', '1876-12-21 10:38' ); // CALL FUNC
    funcAddArrayElem( result, '1877', '1877-03-20 11:38', '1877-06-21 08:03', '1877-09-22 22:23', '1877-12-21 16:28' ); // CALL FUNC
    funcAddArrayElem( result, '1878', '1878-03-20 17:28', '1878-06-21 13:51', '1878-09-23 04:12', '1878-12-21 22:17' ); // CALL FUNC
    funcAddArrayElem( result, '1879', '1879-03-20 23:17', '1879-06-21 19:39', '1879-09-23 10:01', '1879-12-22 04:07' ); // CALL FUNC
    funcAddArrayElem( result, '1880', '1880-03-20 05:06', '1880-06-21 01:27', '1880-09-22 15:49', '1880-12-21 09:57' ); // CALL FUNC
    funcAddArrayElem( result, '1881', '1881-03-20 10:55', '1881-06-21 07:15', '1881-09-22 21:38', '1881-12-21 15:47' ); // CALL FUNC
    funcAddArrayElem( result, '1882', '1882-03-20 16:44', '1882-06-21 13:03', '1882-09-23 03:27', '1882-12-21 21:36' ); // CALL FUNC
    funcAddArrayElem( result, '1883', '1883-03-20 22:34', '1883-06-21 18:52', '1883-09-23 09:16', '1883-12-22 03:26' ); // CALL FUNC
    funcAddArrayElem( result, '1884', '1884-03-20 04:23', '1884-06-21 00:40', '1884-09-22 15:04', '1884-12-21 09:16' ); // CALL FUNC
    funcAddArrayElem( result, '1885', '1885-03-20 10:12', '1885-06-21 06:28', '1885-09-22 20:53', '1885-12-21 15:06' ); // CALL FUNC
    funcAddArrayElem( result, '1886', '1886-03-20 16:01', '1886-06-21 12:16', '1886-09-23 02:42', '1886-12-21 20:55' ); // CALL FUNC
    funcAddArrayElem( result, '1887', '1887-03-20 21:50', '1887-06-21 18:04', '1887-09-23 08:31', '1887-12-22 02:45' ); // CALL FUNC
    funcAddArrayElem( result, '1888', '1888-03-20 03:40', '1888-06-20 23:52', '1888-09-22 14:19', '1888-12-21 08:35' ); // CALL FUNC
    funcAddArrayElem( result, '1889', '1889-03-20 09:29', '1889-06-21 05:40', '1889-09-22 20:08', '1889-12-21 14:25' ); // CALL FUNC
    funcAddArrayElem( result, '1890', '1890-03-20 15:18', '1890-06-21 11:29', '1890-09-23 01:57', '1890-12-21 20:14' ); // CALL FUNC
    funcAddArrayElem( result, '1891', '1891-03-20 21:07', '1891-06-21 17:17', '1891-09-23 07:46', '1891-12-22 02:04' ); // CALL FUNC
    funcAddArrayElem( result, '1892', '1892-03-20 02:56', '1892-06-20 23:05', '1892-09-22 13:34', '1892-12-21 07:54' ); // CALL FUNC
    funcAddArrayElem( result, '1893', '1893-03-20 08:46', '1893-06-21 04:53', '1893-09-22 19:23', '1893-12-21 13:44' ); // CALL FUNC
    funcAddArrayElem( result, '1894', '1894-03-20 14:35', '1894-06-21 10:41', '1894-09-23 01:12', '1894-12-21 19:34' ); // CALL FUNC
    funcAddArrayElem( result, '1895', '1895-03-20 20:24', '1895-06-21 16:29', '1895-09-23 07:01', '1895-12-22 01:23' ); // CALL FUNC
    funcAddArrayElem( result, '1896', '1896-03-20 02:13', '1896-06-20 22:17', '1896-09-22 12:49', '1896-12-21 07:13' ); // CALL FUNC
    funcAddArrayElem( result, '1897', '1897-03-20 08:02', '1897-06-21 04:06', '1897-09-22 18:38', '1897-12-21 13:03' ); // CALL FUNC
    funcAddArrayElem( result, '1898', '1898-03-20 13:52', '1898-06-21 09:54', '1898-09-23 00:27', '1898-12-21 18:53' ); // CALL FUNC
    funcAddArrayElem( result, '1899', '1899-03-20 19:41', '1899-06-21 15:42', '1899-09-23 06:16', '1899-12-22 00:42' ); // CALL FUNC
    funcAddArrayElem( result, '1900', '1900-03-21 01:30', '1900-06-21 21:30', '1900-09-23 12:04', '1900-12-22 06:32' ); // CALL FUNC
    funcAddArrayElem( result, '1901', '1901-03-21 07:19', '1901-06-22 03:18', '1901-09-23 17:53', '1901-12-22 12:22' ); // CALL FUNC
    funcAddArrayElem( result, '1902', '1902-03-21 13:08', '1902-06-22 09:06', '1902-09-23 23:42', '1902-12-22 18:12' ); // CALL FUNC
    funcAddArrayElem( result, '1903', '1903-03-21 18:58', '1903-06-22 14:54', '1903-09-24 05:31', '1903-12-23 00:01' ); // CALL FUNC
    funcAddArrayElem( result, '1904', '1904-03-21 00:47', '1904-06-21 20:43', '1904-09-23 11:19', '1904-12-22 05:51' ); // CALL FUNC
    funcAddArrayElem( result, '1905', '1905-03-21 06:36', '1905-06-22 02:31', '1905-09-23 17:08', '1905-12-22 11:41' ); // CALL FUNC
    funcAddArrayElem( result, '1906', '1906-03-21 12:25', '1906-06-22 08:19', '1906-09-23 22:57', '1906-12-22 17:31' ); // CALL FUNC
    funcAddArrayElem( result, '1907', '1907-03-21 18:14', '1907-06-22 14:07', '1907-09-24 04:46', '1907-12-22 23:20' ); // CALL FUNC
    funcAddArrayElem( result, '1908', '1908-03-21 00:04', '1908-06-21 19:55', '1908-09-23 10:34', '1908-12-22 05:10' ); // CALL FUNC
    funcAddArrayElem( result, '1909', '1909-03-21 05:53', '1909-06-22 01:43', '1909-09-23 16:23', '1909-12-22 11:00' ); // CALL FUNC
    funcAddArrayElem( result, '1910', '1910-03-21 11:42', '1910-06-22 07:31', '1910-09-23 22:12', '1910-12-22 16:50' ); // CALL FUNC
    funcAddArrayElem( result, '1911', '1911-03-21 17:31', '1911-06-22 13:20', '1911-09-24 04:01', '1911-12-22 22:39' ); // CALL FUNC
    funcAddArrayElem( result, '1912', '1912-03-20 23:20', '1912-06-21 19:08', '1912-09-23 09:49', '1912-12-22 04:29' ); // CALL FUNC
    funcAddArrayElem( result, '1913', '1913-03-21 05:10', '1913-06-22 00:56', '1913-09-23 15:38', '1913-12-22 10:19' ); // CALL FUNC
    funcAddArrayElem( result, '1914', '1914-03-21 10:59', '1914-06-22 06:44', '1914-09-23 21:27', '1914-12-22 16:09' ); // CALL FUNC
    funcAddArrayElem( result, '1915', '1915-03-21 16:48', '1915-06-22 12:32', '1915-09-24 03:15', '1915-12-22 21:59' ); // CALL FUNC
    funcAddArrayElem( result, '1916', '1916-03-20 22:37', '1916-06-21 18:20', '1916-09-23 09:04', '1916-12-22 03:48' ); // CALL FUNC
    funcAddArrayElem( result, '1917', '1917-03-21 04:26', '1917-06-22 00:08', '1917-09-23 14:53', '1917-12-22 09:38' ); // CALL FUNC
    funcAddArrayElem( result, '1918', '1918-03-21 10:16', '1918-06-22 05:57', '1918-09-23 20:42', '1918-12-22 15:28' ); // CALL FUNC
    funcAddArrayElem( result, '1919', '1919-03-21 16:05', '1919-06-22 11:45', '1919-09-24 02:30', '1919-12-22 21:18' ); // CALL FUNC
    funcAddArrayElem( result, '1920', '1920-03-20 21:54', '1920-06-21 17:33', '1920-09-23 08:19', '1920-12-22 03:07' ); // CALL FUNC
    funcAddArrayElem( result, '1921', '1921-03-21 03:43', '1921-06-21 23:21', '1921-09-23 14:08', '1921-12-22 08:57' ); // CALL FUNC
    funcAddArrayElem( result, '1922', '1922-03-21 09:32', '1922-06-22 05:09', '1922-09-23 19:57', '1922-12-22 14:47' ); // CALL FUNC
    funcAddArrayElem( result, '1923', '1923-03-21 15:22', '1923-06-22 10:57', '1923-09-24 01:45', '1923-12-22 20:37' ); // CALL FUNC
    funcAddArrayElem( result, '1924', '1924-03-20 21:11', '1924-06-21 16:45', '1924-09-23 07:34', '1924-12-22 02:26' ); // CALL FUNC
    funcAddArrayElem( result, '1925', '1925-03-21 03:00', '1925-06-21 22:34', '1925-09-23 13:23', '1925-12-22 08:16' ); // CALL FUNC
    funcAddArrayElem( result, '1926', '1926-03-21 08:49', '1926-06-22 04:22', '1926-09-23 19:12', '1926-12-22 14:06' ); // CALL FUNC
    funcAddArrayElem( result, '1927', '1927-03-21 14:38', '1927-06-22 10:10', '1927-09-24 01:00', '1927-12-22 19:56' ); // CALL FUNC
    funcAddArrayElem( result, '1928', '1928-03-20 20:28', '1928-06-21 15:58', '1928-09-23 06:49', '1928-12-22 01:45' ); // CALL FUNC
    funcAddArrayElem( result, '1929', '1929-03-21 02:17', '1929-06-21 21:46', '1929-09-23 12:38', '1929-12-22 07:35' ); // CALL FUNC
    funcAddArrayElem( result, '1930', '1930-03-21 08:06', '1930-06-22 03:34', '1930-09-23 18:26', '1930-12-22 13:25' ); // CALL FUNC
    funcAddArrayElem( result, '1931', '1931-03-21 13:55', '1931-06-22 09:22', '1931-09-24 00:15', '1931-12-22 19:15' ); // CALL FUNC
    funcAddArrayElem( result, '1932', '1932-03-20 19:44', '1932-06-21 15:11', '1932-09-23 06:04', '1932-12-22 01:04' ); // CALL FUNC
    funcAddArrayElem( result, '1933', '1933-03-21 01:34', '1933-06-21 20:59', '1933-09-23 11:53', '1933-12-22 06:54' ); // CALL FUNC
    funcAddArrayElem( result, '1934', '1934-03-21 07:23', '1934-06-22 02:47', '1934-09-23 17:41', '1934-12-22 12:44' ); // CALL FUNC
    funcAddArrayElem( result, '1935', '1935-03-21 13:12', '1935-06-22 08:35', '1935-09-23 23:30', '1935-12-22 18:34' ); // CALL FUNC
    funcAddArrayElem( result, '1936', '1936-03-20 19:01', '1936-06-21 14:23', '1936-09-23 05:19', '1936-12-22 00:23' ); // CALL FUNC
    funcAddArrayElem( result, '1937', '1937-03-21 00:50', '1937-06-21 20:11', '1937-09-23 11:08', '1937-12-22 06:13' ); // CALL FUNC
    funcAddArrayElem( result, '1938', '1938-03-21 06:40', '1938-06-22 01:59', '1938-09-23 16:56', '1938-12-22 12:03' ); // CALL FUNC
    funcAddArrayElem( result, '1939', '1939-03-21 12:29', '1939-06-22 07:48', '1939-09-23 22:45', '1939-12-22 17:53' ); // CALL FUNC
    funcAddArrayElem( result, '1940', '1940-03-20 18:18', '1940-06-21 13:36', '1940-09-23 04:34', '1940-12-21 23:42' ); // CALL FUNC
    funcAddArrayElem( result, '1941', '1941-03-21 00:07', '1941-06-21 19:24', '1941-09-23 10:22', '1941-12-22 05:32' ); // CALL FUNC
    funcAddArrayElem( result, '1942', '1942-03-21 05:56', '1942-06-22 01:12', '1942-09-23 16:11', '1942-12-22 11:22' ); // CALL FUNC
    funcAddArrayElem( result, '1943', '1943-03-21 11:46', '1943-06-22 07:00', '1943-09-23 22:00', '1943-12-22 17:12' ); // CALL FUNC
    funcAddArrayElem( result, '1944', '1944-03-20 17:35', '1944-06-21 12:48', '1944-09-23 03:49', '1944-12-21 23:01' ); // CALL FUNC
    funcAddArrayElem( result, '1945', '1945-03-20 23:24', '1945-06-21 18:36', '1945-09-23 09:37', '1945-12-22 04:51' ); // CALL FUNC
    funcAddArrayElem( result, '1946', '1946-03-21 05:13', '1946-06-22 00:25', '1946-09-23 15:26', '1946-12-22 10:41' ); // CALL FUNC
    funcAddArrayElem( result, '1947', '1947-03-21 11:02', '1947-06-22 06:13', '1947-09-23 21:15', '1947-12-22 16:31' ); // CALL FUNC
    funcAddArrayElem( result, '1948', '1948-03-20 16:52', '1948-06-21 12:01', '1948-09-23 03:03', '1948-12-21 22:20' ); // CALL FUNC
    funcAddArrayElem( result, '1949', '1949-03-20 22:41', '1949-06-21 17:49', '1949-09-23 08:52', '1949-12-22 04:10' ); // CALL FUNC
    funcAddArrayElem( result, '1950', '1950-03-21 04:30', '1950-06-21 23:37', '1950-09-23 14:41', '1950-12-22 10:00' ); // CALL FUNC
    funcAddArrayElem( result, '1951', '1951-03-21 10:19', '1951-06-22 05:25', '1951-09-23 20:30', '1951-12-22 15:50' ); // CALL FUNC
    funcAddArrayElem( result, '1952', '1952-03-20 16:08', '1952-06-21 11:13', '1952-09-23 02:18', '1952-12-21 21:39' ); // CALL FUNC
    funcAddArrayElem( result, '1953', '1953-03-20 21:58', '1953-06-21 17:01', '1953-09-23 08:07', '1953-12-22 03:29' ); // CALL FUNC
    funcAddArrayElem( result, '1954', '1954-03-21 03:47', '1954-06-21 22:50', '1954-09-23 13:56', '1954-12-22 09:19' ); // CALL FUNC
    funcAddArrayElem( result, '1955', '1955-03-21 09:36', '1955-06-22 04:38', '1955-09-23 19:44', '1955-12-22 15:09' ); // CALL FUNC
    funcAddArrayElem( result, '1956', '1956-03-20 15:25', '1956-06-21 10:26', '1956-09-23 01:33', '1956-12-21 20:58' ); // CALL FUNC
    funcAddArrayElem( result, '1957', '1957-03-20 21:14', '1957-06-21 16:14', '1957-09-23 07:22', '1957-12-22 02:48' ); // CALL FUNC
    funcAddArrayElem( result, '1958', '1958-03-21 03:04', '1958-06-21 22:02', '1958-09-23 13:11', '1958-12-22 08:38' ); // CALL FUNC
    funcAddArrayElem( result, '1959', '1959-03-21 08:53', '1959-06-22 03:50', '1959-09-23 18:59', '1959-12-22 14:27' ); // CALL FUNC
    funcAddArrayElem( result, '1960', '1960-03-20 14:42', '1960-06-21 09:38', '1960-09-23 00:48', '1960-12-21 20:17' ); // CALL FUNC
    funcAddArrayElem( result, '1961', '1961-03-20 20:31', '1961-06-21 15:27', '1961-09-23 06:37', '1961-12-22 02:07' ); // CALL FUNC
    funcAddArrayElem( result, '1962', '1962-03-21 02:20', '1962-06-21 21:15', '1962-09-23 12:25', '1962-12-22 07:57' ); // CALL FUNC
    funcAddArrayElem( result, '1963', '1963-03-21 08:10', '1963-06-22 03:03', '1963-09-23 18:14', '1963-12-22 13:46' ); // CALL FUNC
    funcAddArrayElem( result, '1964', '1964-03-20 13:59', '1964-06-21 08:51', '1964-09-23 00:03', '1964-12-21 19:36' ); // CALL FUNC
    funcAddArrayElem( result, '1965', '1965-03-20 19:48', '1965-06-21 14:39', '1965-09-23 05:52', '1965-12-22 01:26' ); // CALL FUNC
    funcAddArrayElem( result, '1966', '1966-03-21 01:37', '1966-06-21 20:27', '1966-09-23 11:40', '1966-12-22 07:16' ); // CALL FUNC
    funcAddArrayElem( result, '1967', '1967-03-21 07:26', '1967-06-22 02:15', '1967-09-23 17:29', '1967-12-22 13:05' ); // CALL FUNC
    funcAddArrayElem( result, '1968', '1968-03-20 13:16', '1968-06-21 08:03', '1968-09-22 23:18', '1968-12-21 18:55' ); // CALL FUNC
    funcAddArrayElem( result, '1969', '1969-03-20 19:05', '1969-06-21 13:52', '1969-09-23 05:06', '1969-12-22 00:45' ); // CALL FUNC
    funcAddArrayElem( result, '1970', '1970-03-21 00:54', '1970-06-21 19:40', '1970-09-23 10:55', '1970-12-22 06:35' ); // CALL FUNC
    funcAddArrayElem( result, '1971', '1971-03-21 06:43', '1971-06-22 01:28', '1971-09-23 16:44', '1971-12-22 12:24' ); // CALL FUNC
    funcAddArrayElem( result, '1972', '1972-03-20 12:32', '1972-06-21 07:16', '1972-09-22 22:33', '1972-12-21 18:14' ); // CALL FUNC
    funcAddArrayElem( result, '1973', '1973-03-20 18:22', '1973-06-21 13:04', '1973-09-23 04:21', '1973-12-22 00:04' ); // CALL FUNC
    funcAddArrayElem( result, '1974', '1974-03-21 00:11', '1974-06-21 18:52', '1974-09-23 10:10', '1974-12-22 05:54' ); // CALL FUNC
    funcAddArrayElem( result, '1975', '1975-03-21 06:00', '1975-06-22 00:40', '1975-09-23 15:59', '1975-12-22 11:43' ); // CALL FUNC
    funcAddArrayElem( result, '1976', '1976-03-20 11:49', '1976-06-21 06:29', '1976-09-22 21:47', '1976-12-21 17:33' ); // CALL FUNC
    funcAddArrayElem( result, '1977', '1977-03-20 17:38', '1977-06-21 12:17', '1977-09-23 03:36', '1977-12-21 23:23' ); // CALL FUNC
    funcAddArrayElem( result, '1978', '1978-03-20 23:28', '1978-06-21 18:05', '1978-09-23 09:25', '1978-12-22 05:13' ); // CALL FUNC
    funcAddArrayElem( result, '1979', '1979-03-21 05:17', '1979-06-21 23:53', '1979-09-23 15:14', '1979-12-22 11:02' ); // CALL FUNC
    funcAddArrayElem( result, '1980', '1980-03-20 11:06', '1980-06-21 05:41', '1980-09-22 21:02', '1980-12-21 16:52' ); // CALL FUNC
    funcAddArrayElem( result, '1981', '1981-03-20 16:55', '1981-06-21 11:29', '1981-09-23 02:51', '1981-12-21 22:42' ); // CALL FUNC
    funcAddArrayElem( result, '1982', '1982-03-20 22:44', '1982-06-21 17:17', '1982-09-23 08:40', '1982-12-22 04:31' ); // CALL FUNC
    funcAddArrayElem( result, '1983', '1983-03-21 04:34', '1983-06-21 23:05', '1983-09-23 14:28', '1983-12-22 10:21' ); // CALL FUNC
    funcAddArrayElem( result, '1984', '1984-03-20 10:23', '1984-06-21 04:54', '1984-09-22 20:17', '1984-12-21 16:11' ); // CALL FUNC
    funcAddArrayElem( result, '1985', '1985-03-20 16:12', '1985-06-21 10:42', '1985-09-23 02:06', '1985-12-21 22:01' ); // CALL FUNC
    funcAddArrayElem( result, '1986', '1986-03-20 22:01', '1986-06-21 16:30', '1986-09-23 07:54', '1986-12-22 03:50' ); // CALL FUNC
    funcAddArrayElem( result, '1987', '1987-03-21 03:50', '1987-06-21 22:18', '1987-09-23 13:43', '1987-12-22 09:40' ); // CALL FUNC
    funcAddArrayElem( result, '1988', '1988-03-20 09:40', '1988-06-21 04:06', '1988-09-22 19:32', '1988-12-21 15:30' ); // CALL FUNC
    funcAddArrayElem( result, '1989', '1989-03-20 15:29', '1989-06-21 09:54', '1989-09-23 01:21', '1989-12-21 21:20' ); // CALL FUNC
    funcAddArrayElem( result, '1990', '1990-03-20 21:18', '1990-06-21 15:42', '1990-09-23 07:09', '1990-12-22 03:09' ); // CALL FUNC
    funcAddArrayElem( result, '1991', '1991-03-21 03:07', '1991-06-21 21:31', '1991-09-23 12:58', '1991-12-22 08:59' ); // CALL FUNC
    funcAddArrayElem( result, '1992', '1992-03-20 08:56', '1992-06-21 03:19', '1992-09-22 18:47', '1992-12-21 14:49' ); // CALL FUNC
    funcAddArrayElem( result, '1993', '1993-03-20 14:46', '1993-06-21 09:07', '1993-09-23 00:35', '1993-12-21 20:39' ); // CALL FUNC
    funcAddArrayElem( result, '1994', '1994-03-20 20:35', '1994-06-21 14:55', '1994-09-23 06:24', '1994-12-22 02:28' ); // CALL FUNC
    funcAddArrayElem( result, '1995', '1995-03-21 02:24', '1995-06-21 20:43', '1995-09-23 12:13', '1995-12-22 08:18' ); // CALL FUNC
    funcAddArrayElem( result, '1996', '1996-03-20 08:13', '1996-06-21 02:31', '1996-09-22 18:01', '1996-12-21 14:08' ); // CALL FUNC
    funcAddArrayElem( result, '1997', '1997-03-20 14:02', '1997-06-21 08:19', '1997-09-22 23:50', '1997-12-21 19:57' ); // CALL FUNC
    funcAddArrayElem( result, '1998', '1998-03-20 19:52', '1998-06-21 14:07', '1998-09-23 05:39', '1998-12-22 01:47' ); // CALL FUNC
    funcAddArrayElem( result, '1999', '1999-03-21 01:41', '1999-06-21 19:56', '1999-09-23 11:28', '1999-12-22 07:37' ); // CALL FUNC
    funcAddArrayElem( result, '2000', '2000-03-20 07:30', '2000-06-21 01:44', '2000-09-22 17:16', '2000-12-21 13:27' ); // CALL FUNC
    funcAddArrayElem( result, '2001', '2001-03-20 13:19', '2001-06-21 07:32', '2001-09-22 23:05', '2001-12-21 19:16' ); // CALL FUNC
    funcAddArrayElem( result, '2002', '2002-03-20 19:08', '2002-06-21 13:20', '2002-09-23 04:54', '2002-12-22 01:06' ); // CALL FUNC
    funcAddArrayElem( result, '2003', '2003-03-21 00:58', '2003-06-21 19:08', '2003-09-23 10:42', '2003-12-22 06:56' ); // CALL FUNC
    funcAddArrayElem( result, '2004', '2004-03-20 06:47', '2004-06-21 00:56', '2004-09-22 16:31', '2004-12-21 12:46' ); // CALL FUNC
    funcAddArrayElem( result, '2005', '2005-03-20 12:36', '2005-06-21 06:44', '2005-09-22 22:20', '2005-12-21 18:35' ); // CALL FUNC
    funcAddArrayElem( result, '2006', '2006-03-20 18:25', '2006-06-21 12:32', '2006-09-23 04:08', '2006-12-22 00:25' ); // CALL FUNC
    funcAddArrayElem( result, '2007', '2007-03-21 00:14', '2007-06-21 18:21', '2007-09-23 09:57', '2007-12-22 06:15' ); // CALL FUNC
    funcAddArrayElem( result, '2008', '2008-03-20 06:04', '2008-06-21 00:09', '2008-09-22 15:46', '2008-12-21 12:04' ); // CALL FUNC
    funcAddArrayElem( result, '2009', '2009-03-20 11:53', '2009-06-21 05:57', '2009-09-22 21:34', '2009-12-21 17:54' ); // CALL FUNC
    funcAddArrayElem( result, '2010', '2010-03-20 17:42', '2010-06-21 11:45', '2010-09-23 03:23', '2010-12-21 23:44' ); // CALL FUNC
    funcAddArrayElem( result, '2011', '2011-03-20 23:31', '2011-06-21 17:33', '2011-09-23 09:12', '2011-12-22 05:34' ); // CALL FUNC
    funcAddArrayElem( result, '2012', '2012-03-20 05:20', '2012-06-20 23:21', '2012-09-22 15:01', '2012-12-21 11:23' ); // CALL FUNC
    funcAddArrayElem( result, '2013', '2013-03-20 11:10', '2013-06-21 05:09', '2013-09-22 20:49', '2013-12-21 17:13' ); // CALL FUNC
    funcAddArrayElem( result, '2014', '2014-03-20 16:59', '2014-06-21 10:57', '2014-09-23 02:38', '2014-12-21 23:03' ); // CALL FUNC
    funcAddArrayElem( result, '2015', '2015-03-20 22:48', '2015-06-21 16:46', '2015-09-23 08:27', '2015-12-22 04:53' ); // CALL FUNC
    funcAddArrayElem( result, '2016', '2016-03-20 04:37', '2016-06-20 22:34', '2016-09-22 14:15', '2016-12-21 10:42' ); // CALL FUNC
    funcAddArrayElem( result, '2017', '2017-03-20 10:26', '2017-06-21 04:22', '2017-09-22 20:04', '2017-12-21 16:32' ); // CALL FUNC
    funcAddArrayElem( result, '2018', '2018-03-20 16:16', '2018-06-21 10:10', '2018-09-23 01:53', '2018-12-21 22:22' ); // CALL FUNC
    funcAddArrayElem( result, '2019', '2019-03-20 22:05', '2019-06-21 15:58', '2019-09-23 07:41', '2019-12-22 04:11' ); // CALL FUNC
    funcAddArrayElem( result, '2020', '2020-03-20 03:54', '2020-06-20 21:46', '2020-09-22 13:30', '2020-12-21 10:01' ); // CALL FUNC
    funcAddArrayElem( result, '2021', '2021-03-20 09:43', '2021-06-21 03:34', '2021-09-22 19:19', '2021-12-21 15:51' ); // CALL FUNC
    funcAddArrayElem( result, '2022', '2022-03-20 15:32', '2022-06-21 09:23', '2022-09-23 01:07', '2022-12-21 21:41' ); // CALL FUNC
    funcAddArrayElem( result, '2023', '2023-03-20 21:22', '2023-06-21 15:11', '2023-09-23 06:56', '2023-12-22 03:30' ); // CALL FUNC
    funcAddArrayElem( result, '2024', '2024-03-20 03:11', '2024-06-20 20:59', '2024-09-22 12:45', '2024-12-21 09:20' ); // CALL FUNC
    funcAddArrayElem( result, '2025', '2025-03-20 09:00', '2025-06-21 02:47', '2025-09-22 18:33', '2025-12-21 15:10' ); // CALL FUNC
    funcAddArrayElem( result, '2026', '2026-03-20 14:49', '2026-06-21 08:35', '2026-09-23 00:22', '2026-12-21 20:59' ); // CALL FUNC
    funcAddArrayElem( result, '2027', '2027-03-20 20:38', '2027-06-21 14:23', '2027-09-23 06:11', '2027-12-22 02:49' ); // CALL FUNC
    funcAddArrayElem( result, '2028', '2028-03-20 02:28', '2028-06-20 20:11', '2028-09-22 11:59', '2028-12-21 08:39' ); // CALL FUNC
    funcAddArrayElem( result, '2029', '2029-03-20 08:17', '2029-06-21 01:59', '2029-09-22 17:48', '2029-12-21 14:29' ); // CALL FUNC
    funcAddArrayElem( result, '2030', '2030-03-20 14:06', '2030-06-21 07:48', '2030-09-22 23:37', '2030-12-21 20:18' ); // CALL FUNC
    funcAddArrayElem( result, '2031', '2031-03-20 19:55', '2031-06-21 13:36', '2031-09-23 05:26', '2031-12-22 02:08' ); // CALL FUNC
    funcAddArrayElem( result, '2032', '2032-03-20 01:44', '2032-06-20 19:24', '2032-09-22 11:14', '2032-12-21 07:58' ); // CALL FUNC
    funcAddArrayElem( result, '2033', '2033-03-20 07:34', '2033-06-21 01:12', '2033-09-22 17:03', '2033-12-21 13:48' ); // CALL FUNC
    funcAddArrayElem( result, '2034', '2034-03-20 13:23', '2034-06-21 07:00', '2034-09-22 22:52', '2034-12-21 19:37' ); // CALL FUNC
    funcAddArrayElem( result, '2035', '2035-03-20 19:12', '2035-06-21 12:48', '2035-09-23 04:40', '2035-12-22 01:27' ); // CALL FUNC
    funcAddArrayElem( result, '2036', '2036-03-20 01:01', '2036-06-20 18:36', '2036-09-22 10:29', '2036-12-21 07:17' ); // CALL FUNC
    funcAddArrayElem( result, '2037', '2037-03-20 06:50', '2037-06-21 00:24', '2037-09-22 16:18', '2037-12-21 13:06' ); // CALL FUNC
    funcAddArrayElem( result, '2038', '2038-03-20 12:40', '2038-06-21 06:13', '2038-09-22 22:06', '2038-12-21 18:56' ); // CALL FUNC
    funcAddArrayElem( result, '2039', '2039-03-20 18:29', '2039-06-21 12:01', '2039-09-23 03:55', '2039-12-22 00:46' ); // CALL FUNC
    funcAddArrayElem( result, '2040', '2040-03-20 00:18', '2040-06-20 17:49', '2040-09-22 09:44', '2040-12-21 06:36' ); // CALL FUNC
    funcAddArrayElem( result, '2041', '2041-03-20 06:07', '2041-06-20 23:37', '2041-09-22 15:32', '2041-12-21 12:25' ); // CALL FUNC
    funcAddArrayElem( result, '2042', '2042-03-20 11:56', '2042-06-21 05:25', '2042-09-22 21:21', '2042-12-21 18:15' ); // CALL FUNC
    funcAddArrayElem( result, '2043', '2043-03-20 17:46', '2043-06-21 11:13', '2043-09-23 03:10', '2043-12-22 00:05' ); // CALL FUNC
    funcAddArrayElem( result, '2044', '2044-03-19 23:35', '2044-06-20 17:01', '2044-09-22 08:58', '2044-12-21 05:54' ); // CALL FUNC
    funcAddArrayElem( result, '2045', '2045-03-20 05:24', '2045-06-20 22:49', '2045-09-22 14:47', '2045-12-21 11:44' ); // CALL FUNC
    funcAddArrayElem( result, '2046', '2046-03-20 11:13', '2046-06-21 04:37', '2046-09-22 20:36', '2046-12-21 17:34' ); // CALL FUNC
    funcAddArrayElem( result, '2047', '2047-03-20 17:02', '2047-06-21 10:26', '2047-09-23 02:24', '2047-12-21 23:24' ); // CALL FUNC
    funcAddArrayElem( result, '2048', '2048-03-19 22:52', '2048-06-20 16:14', '2048-09-22 08:13', '2048-12-21 05:13' ); // CALL FUNC
    funcAddArrayElem( result, '2049', '2049-03-20 04:41', '2049-06-20 22:02', '2049-09-22 14:02', '2049-12-21 11:03' ); // CALL FUNC
    funcAddArrayElem( result, '2050', '2050-03-20 10:30', '2050-06-21 03:50', '2050-09-22 19:50', '2050-12-21 16:53' ); // CALL FUNC
    funcAddArrayElem( result, '2051', '2051-03-20 16:19', '2051-06-21 09:38', '2051-09-23 01:39', '2051-12-21 22:42' ); // CALL FUNC
    funcAddArrayElem( result, '2052', '2052-03-19 22:08', '2052-06-20 15:26', '2052-09-22 07:28', '2052-12-21 04:32' ); // CALL FUNC
    funcAddArrayElem( result, '2053', '2053-03-20 03:58', '2053-06-20 21:14', '2053-09-22 13:16', '2053-12-21 10:22' ); // CALL FUNC
    funcAddArrayElem( result, '2054', '2054-03-20 09:47', '2054-06-21 03:02', '2054-09-22 19:05', '2054-12-21 16:12' ); // CALL FUNC
    funcAddArrayElem( result, '2055', '2055-03-20 15:36', '2055-06-21 08:51', '2055-09-23 00:54', '2055-12-21 22:01' ); // CALL FUNC
    funcAddArrayElem( result, '2056', '2056-03-19 21:25', '2056-06-20 14:39', '2056-09-22 06:42', '2056-12-21 03:51' ); // CALL FUNC
    funcAddArrayElem( result, '2057', '2057-03-20 03:14', '2057-06-20 20:27', '2057-09-22 12:31', '2057-12-21 09:41' ); // CALL FUNC
    funcAddArrayElem( result, '2058', '2058-03-20 09:04', '2058-06-21 02:15', '2058-09-22 18:20', '2058-12-21 15:30' ); // CALL FUNC
    funcAddArrayElem( result, '2059', '2059-03-20 14:53', '2059-06-21 08:03', '2059-09-23 00:08', '2059-12-21 21:20' ); // CALL FUNC
    funcAddArrayElem( result, '2060', '2060-03-19 20:42', '2060-06-20 13:51', '2060-09-22 05:57', '2060-12-21 03:10' ); // CALL FUNC
    funcAddArrayElem( result, '2061', '2061-03-20 02:31', '2061-06-20 19:39', '2061-09-22 11:46', '2061-12-21 09:00' ); // CALL FUNC
    funcAddArrayElem( result, '2062', '2062-03-20 08:20', '2062-06-21 01:27', '2062-09-22 17:34', '2062-12-21 14:49' ); // CALL FUNC
    funcAddArrayElem( result, '2063', '2063-03-20 14:10', '2063-06-21 07:16', '2063-09-22 23:23', '2063-12-21 20:39' ); // CALL FUNC
    funcAddArrayElem( result, '2064', '2064-03-19 19:59', '2064-06-20 13:04', '2064-09-22 05:12', '2064-12-21 02:29' ); // CALL FUNC
    funcAddArrayElem( result, '2065', '2065-03-20 01:48', '2065-06-20 18:52', '2065-09-22 11:00', '2065-12-21 08:18' ); // CALL FUNC
    funcAddArrayElem( result, '2066', '2066-03-20 07:37', '2066-06-21 00:40', '2066-09-22 16:49', '2066-12-21 14:08' ); // CALL FUNC
    funcAddArrayElem( result, '2067', '2067-03-20 13:26', '2067-06-21 06:28', '2067-09-22 22:38', '2067-12-21 19:58' ); // CALL FUNC
    funcAddArrayElem( result, '2068', '2068-03-19 19:16', '2068-06-20 12:16', '2068-09-22 04:26', '2068-12-21 01:47' ); // CALL FUNC
    funcAddArrayElem( result, '2069', '2069-03-20 01:05', '2069-06-20 18:04', '2069-09-22 10:15', '2069-12-21 07:37' ); // CALL FUNC
    funcAddArrayElem( result, '2070', '2070-03-20 06:54', '2070-06-20 23:52', '2070-09-22 16:04', '2070-12-21 13:27' ); // CALL FUNC
    funcAddArrayElem( result, '2071', '2071-03-20 12:43', '2071-06-21 05:41', '2071-09-22 21:52', '2071-12-21 19:17' ); // CALL FUNC
    funcAddArrayElem( result, '2072', '2072-03-19 18:32', '2072-06-20 11:29', '2072-09-22 03:41', '2072-12-21 01:06' ); // CALL FUNC
    funcAddArrayElem( result, '2073', '2073-03-20 00:22', '2073-06-20 17:17', '2073-09-22 09:30', '2073-12-21 06:56' ); // CALL FUNC
    funcAddArrayElem( result, '2074', '2074-03-20 06:11', '2074-06-20 23:05', '2074-09-22 15:18', '2074-12-21 12:46' ); // CALL FUNC
    funcAddArrayElem( result, '2075', '2075-03-20 12:00', '2075-06-21 04:53', '2075-09-22 21:07', '2075-12-21 18:35' ); // CALL FUNC
    funcAddArrayElem( result, '2076', '2076-03-19 17:49', '2076-06-20 10:41', '2076-09-22 02:56', '2076-12-21 00:25' ); // CALL FUNC
    funcAddArrayElem( result, '2077', '2077-03-19 23:38', '2077-06-20 16:29', '2077-09-22 08:44', '2077-12-21 06:15' ); // CALL FUNC
    funcAddArrayElem( result, '2078', '2078-03-20 05:28', '2078-06-20 22:17', '2078-09-22 14:33', '2078-12-21 12:05' ); // CALL FUNC
    funcAddArrayElem( result, '2079', '2079-03-20 11:17', '2079-06-21 04:05', '2079-09-22 20:22', '2079-12-21 17:54' ); // CALL FUNC
    funcAddArrayElem( result, '2080', '2080-03-19 17:06', '2080-06-20 09:54', '2080-09-22 02:10', '2080-12-20 23:44' ); // CALL FUNC
    funcAddArrayElem( result, '2081', '2081-03-19 22:55', '2081-06-20 15:42', '2081-09-22 07:59', '2081-12-21 05:34' ); // CALL FUNC
    funcAddArrayElem( result, '2082', '2082-03-20 04:44', '2082-06-20 21:30', '2082-09-22 13:48', '2082-12-21 11:23' ); // CALL FUNC
    funcAddArrayElem( result, '2083', '2083-03-20 10:34', '2083-06-21 03:18', '2083-09-22 19:36', '2083-12-21 17:13' ); // CALL FUNC
    funcAddArrayElem( result, '2084', '2084-03-19 16:23', '2084-06-20 09:06', '2084-09-22 01:25', '2084-12-20 23:03' ); // CALL FUNC
    funcAddArrayElem( result, '2085', '2085-03-19 22:12', '2085-06-20 14:54', '2085-09-22 07:14', '2085-12-21 04:52' ); // CALL FUNC
    funcAddArrayElem( result, '2086', '2086-03-20 04:01', '2086-06-20 20:42', '2086-09-22 13:02', '2086-12-21 10:42' ); // CALL FUNC
    funcAddArrayElem( result, '2087', '2087-03-20 09:50', '2087-06-21 02:30', '2087-09-22 18:51', '2087-12-21 16:32' ); // CALL FUNC
    funcAddArrayElem( result, '2088', '2088-03-19 15:40', '2088-06-20 08:19', '2088-09-22 00:39', '2088-12-20 22:22' ); // CALL FUNC
    funcAddArrayElem( result, '2089', '2089-03-19 21:29', '2089-06-20 14:07', '2089-09-22 06:28', '2089-12-21 04:11' ); // CALL FUNC
    funcAddArrayElem( result, '2090', '2090-03-20 03:18', '2090-06-20 19:55', '2090-09-22 12:17', '2090-12-21 10:01' ); // CALL FUNC
    funcAddArrayElem( result, '2091', '2091-03-20 09:07', '2091-06-21 01:43', '2091-09-22 18:05', '2091-12-21 15:51' ); // CALL FUNC
    funcAddArrayElem( result, '2092', '2092-03-19 14:56', '2092-06-20 07:31', '2092-09-21 23:54', '2092-12-20 21:40' ); // CALL FUNC
    funcAddArrayElem( result, '2093', '2093-03-19 20:46', '2093-06-20 13:19', '2093-09-22 05:43', '2093-12-21 03:30' ); // CALL FUNC
    funcAddArrayElem( result, '2094', '2094-03-20 02:35', '2094-06-20 19:07', '2094-09-22 11:31', '2094-12-21 09:20' ); // CALL FUNC
    funcAddArrayElem( result, '2095', '2095-03-20 08:24', '2095-06-21 00:55', '2095-09-22 17:20', '2095-12-21 15:09' ); // CALL FUNC
    funcAddArrayElem( result, '2096', '2096-03-19 14:13', '2096-06-20 06:43', '2096-09-21 23:09', '2096-12-20 20:59' ); // CALL FUNC
    funcAddArrayElem( result, '2097', '2097-03-19 20:02', '2097-06-20 12:32', '2097-09-22 04:57', '2097-12-21 02:49' ); // CALL FUNC
    funcAddArrayElem( result, '2098', '2098-03-20 01:52', '2098-06-20 18:20', '2098-09-22 10:46', '2098-12-21 08:39' ); // CALL FUNC
    funcAddArrayElem( result, '2099', '2099-03-20 07:41', '2099-06-21 00:08', '2099-09-22 16:35', '2099-12-21 14:28' ); // CALL FUNC
    funcAddArrayElem( result, '2100', '2100-03-20 13:30', '2100-06-21 05:56', '2100-09-22 22:23', '2100-12-21 20:18' ); // CALL FUNC
    //**************************************************************************
    //**************************************************************************
    //**************************************************************************
    //**************************************************************************
    //**************************************************************************
  end;

  //--------------------------------------------------------------------------80
  function funcFindDateTimeByYear(AYear: WideString;
                                  ADateTime: TidElement): Integer;
  var
    i: Integer;
    AElem: TidElement;
  begin
    Result := -1; // value if no match found
    for i := 0 to ADateTime.Elements.Count - 1 do
    begin
      AElem := ADateTime.Elements.Items[i];
      if (AElem.Prop['Year'] = AYear) then
      begin
        Result := i; // value if match found
        Exit; // exit function
      end;
    end;
    ADateTime.Free;
  end;

  //--------------------------------------------------------------------------80
  function funcFormatDateTimeString(ADateTimeString: WideString): WideString;
  // convert specified input format to TDateTime format
  //
  // input format:  yyyy-mm-dd hh:nn:ss
  // output format: dd/mm/yyyy hh:nn:ss
  //
  // NOTE For input format, 'ss' and 'nn' may both be omitted,
  //      ie the following are acceptable:
  //        yyyy-mm-dd hh:nn:ss
  //        yyyy-mm-dd hh:nn
  //        yyyy-mm-dd hh
  var
    i: Integer;
    yyyy, mm, dd, hhnnss: WideString;
    ATokens: TTntStringList;
    ASubTokens: TTntStringList;
  begin
    result := 'bad datetime string';

    yyyy := ''; mm := ''; dd := ''; hhnnss := '';

    ATokens := TTntStringList.Create;
    ASubTokens := TTntStringList.Create;
    try
      Tokenize(ADateTimeString, '-', ATokens);
      for i := 0 to ATokens.Count - 1 do
      begin
        if (Pos (' ', ATokens.Strings[i]) = 0) then
          ASubTokens.Add(ATokens.Strings[i]);
        else
          Tokenize(ATokens.Strings[i], ' ', ASubTokens);
      end;
      if ASubTokens.Count >= 4 then
      begin
        yyyy := ASubTokens.Strings[0];
        mm := ASubTokens.Strings[1];
        dd := ASubTokens.Strings[2];
        hhnnss := ASubTokens.Strings[3];
      end;
      result := dd + '/' + mm + '/' + yyyy + ' ' + hhnnss;
    finally
      ATokens.Free;
      ASubTokens.Free;
    end;
  end;

  //--------------------------------------------------------------------------80
  function funcFormatISODateTimeString(ADateTimeString: WideString): WideString;
  // convert specified input format to TDateTime format
  //
  // input format:  yyyy-mm-dd hh:nn:ss
  // output format: yyyy-mm-ddThh:nn:ss.zzzZ
  //
  // NOTE For input format, 'ss' and 'nn' may both be omitted,
  //      ie the following are acceptable:
  //        yyyy-mm-dd hh:nn:ss
  //        yyyy-mm-dd hh:nn
  //        yyyy-mm-dd hh
  var
    i: Integer;
    yyyy, mm, dd, hhnnss: WideString;
    ATokens: TTntStringList;
    ASubTokens: TTntStringList;
  begin
    result := 'bad datetime string';

    yyyy := ''; mm := ''; dd := ''; hhnnss := '';

    ATokens := TTntStringList.Create;
    ASubTokens := TTntStringList.Create;
    try
      Tokenize(ADateTimeString, '-', ATokens);
      for i := 0 to ATokens.Count - 1 do
      begin
        if (Pos (' ', ATokens.Strings[i]) = 0) then
          ASubTokens.Add(ATokens.Strings[i]);
        else
          Tokenize(ATokens.Strings[i], ' ', ASubTokens);
      end;
      if ASubTokens.Count >= 4 then
      begin
        yyyy := ASubTokens.Strings[0];
        mm := ASubTokens.Strings[1];
        dd := ASubTokens.Strings[2];
        hhnnss := ASubTokens.Strings[3];
      end;
      result :=  yyyy + '-' + mm + '-' + dd + 'T' + hhnnss + '.000Z';
    finally
      ATokens.Free;
      ASubTokens.Free;
    end;
  end;

  //--------------------------------------------------------------------------80
  function funcGetSeasonAstroNorth(APhotoDate: TDateTime): WideString;
  {
     CompareDateTime compares two TDateTime values A and B and returns:
        < 0     if A is earlier than B
        = 0     if A and B are the same date/time
        > 0     if A is later than B
  }
  var
    AArrayIndex: Integer;
    AYear: WideString;
    ATokens: TTntStringList;
    ADT1, ADT2: TDateTime;
    AArrayDateTime, AElem: TidElement;
    ATimeZoneOffset: Double;
  begin
    result := '';
    ATokens := TTntStringList.Create;
    Tokenize(DateTimeToISODateString(APhotoDate, TimeZoneOffset, dtkDateTime), '-', ATokens);
    if ATokens.Count >= 2 then
    begin
      AYear := ATokens.Strings[0];
      AArrayDateTime := funcInitArray(); // CALL FUNC
      AArrayIndex := funcFindDateTimeByYear(AYear, AArrayDateTime); // CALL FUNC
      if (AArrayIndex = -1) then
        result := 'YEAR MATCH NOT FOUND';
      else
      begin
        ATimeZoneOffset := 0.0;
        AElem := AArrayDateTime.Elements.Items[AArrayIndex];
        ADT1 := APhotoDate;
        ADT2 := ISODateStringToDateTime(funcFormatISODateTimeString(AElem.Prop['MarE']), ATimeZoneOffset); // CALL FUNC
        if CompareDateTime(ADT1, ADT2) < 0 then
          result := 'Winter';
        if CompareDateTime(ADT1, ADT2) >= 0 then
          result := 'Spring';
        ADT2 := ISODateStringToDateTime(funcFormatISODateTimeString(AElem.Prop['JunS']), ATimeZoneOffset); // CALL FUNC
        if CompareDateTime(ADT1, ADT2) >= 0 then
          result := 'Summer';
        ADT2 := ISODateStringToDateTime(funcFormatISODateTimeString(AElem.Prop['SepE']), ATimeZoneOffset); // CALL FUNC
        if CompareDateTime(ADT1, ADT2) >= 0 then
          result := 'Autumn';
        ADT2 := ISODateStringToDateTime(funcFormatISODateTimeString(AElem.Prop['DecS']), ATimeZoneOffset); // CALL FUNC
        if CompareDateTime(ADT1, ADT2) >= 0 then
          result := 'Winter';
      end;
    end
    else
      result := 'INVALID PHOTO DATE';
    ATokens.Free;
  end;

  //--------------------------------------------------------------------------80
  function funcGetSeasonAstroSouth(APhotoDate: TDateTime): WideString;
  {
     CompareDateTime compares two TDateTime values A and B and returns:
        < 0     if A is earlier than B
        = 0     if A and B are the same date/time
        > 0     if A is later than B
  }
  var
    AArrayIndex: Integer;
    AYear: WideString;
    ATokens: TTntStringList;
    ADT1, ADT2: TDateTime;
    AArrayDateTime, AElem: TidElement;
    ATimeZoneOffset: Double;
  begin
    result := '';
    ATokens := TTntStringList.Create;
    Tokenize(DateTimeToISODateString(APhotoDate, TimeZoneOffset, dtkDateTime), '-', ATokens);
    if ATokens.Count >= 2 then
    begin
      AYear := ATokens.Strings[0];
      AArrayDateTime := funcInitArray(); // CALL FUNC
      AArrayIndex := funcFindDateTimeByYear(AYear, AArrayDateTime); // CALL FUNC
      if (AArrayIndex = -1) then
        result := 'YEAR MATCH NOT FOUND';
      else
      begin
        ATimeZoneOffset := 0.0;
        AElem := AArrayDateTime.Elements.Items[AArrayIndex];
        ADT1 := APhotoDate;
        ADT2 := ISODateStringToDateTime(funcFormatISODateTimeString(AElem.Prop['MarE']), ATimeZoneOffset); // CALL FUNC
        if CompareDateTime(ADT1, ADT2) < 0 then
          result := 'Summer';
        if CompareDateTime(ADT1, ADT2) >= 0 then
          result := 'Autumn';
        ADT2 := ISODateStringToDateTime(funcFormatISODateTimeString(AElem.Prop['JunS']), ATimeZoneOffset); // CALL FUNC
        if CompareDateTime(ADT1, ADT2) >= 0 then
          result := 'Winter';
        ADT2 := ISODateStringToDateTime(funcFormatISODateTimeString(AElem.Prop['SepE']), ATimeZoneOffset); // CALL FUNC
        if CompareDateTime(ADT1, ADT2) >= 0 then
          result := 'Spring';
        ADT2 := ISODateStringToDateTime(funcFormatISODateTimeString(AElem.Prop['DecS']), ATimeZoneOffset); // CALL FUNC
        if CompareDateTime(ADT1, ADT2) >= 0 then
          result := 'Summer';
      end;
    end
    else
      result := 'INVALID PHOTO DATE';
    ATokens.Free;
  end;

  //--------------------------------------------------------------------------80
  function funcGetSeasonMeteoNorth(APhotoDate: TDateTime): WideString;
  var
    AMonth: Integer;
    ATokens: TTntStringList;
  begin
    result := '';
    ATokens := TTntStringList.Create;
    Tokenize(DateTimeToISODateString(APhotoDate, TimeZoneOffset, dtkDateTime), '-', ATokens);
    if ATokens.Count >= 3 then
    begin
      AMonth := StrToInt(ATokens.Strings[1]);
      if (AMonth >= 3) AND (AMonth < 6) then
        result := 'Spring';
      if (AMonth >= 6) AND (AMonth < 9) then
        result := 'Summer';
      if (AMonth >= 9) AND (AMonth < 12) then
        result := 'Autumn';
      if (AMonth = 12) OR (AMonth = 1) OR (AMonth = 2) then
        result := 'Winter';
    end
    else
      result := 'INVALID PHOTO DATE';
    ATokens.Free;
  end;

  //--------------------------------------------------------------------------80
  function funcGetSeasonMeteoSouth(APhotoDate: TDateTime): WideString;
  var
    AMonth: Integer;
    ATokens: TTntStringList;
  begin
    result := '';
    ATokens := TTntStringList.Create;
    Tokenize(DateTimeToISODateString(APhotoDate, TimeZoneOffset, dtkDateTime), '-', ATokens);
    if ATokens.Count >= 3 then
    begin
      AMonth := StrToInt(ATokens.Strings[1]);
      if (AMonth >= 3) AND (AMonth < 6) then
        result := 'Autumn';
      if (AMonth >= 6) AND (AMonth < 9) then
        result := 'Winter';
      if (AMonth >= 9) AND (AMonth < 12) then
        result := 'Spring';
      if (AMonth = 12) OR (AMonth = 1) OR (AMonth = 2) then
        result := 'Summer';
    end
    else
      result := 'INVALID PHOTO DATE';
    ATokens.Free;
  end;

//----------------------------------------------------------------------------80
var { main procedure }
  i: Integer;
  AIntAskButton: Integer;
  ABlnAskChecked: Boolean;
  ABlnInvalidDir: Boolean;
  AWStrCollName: WideString;
  AWStrCollDescription: WideString;
  AWStrDateTimeDescription: WideString;
  AWStrDateTimeSuffix: WideString;
  AWStrReportFile: WideString;
  AWStrReportName: WideString;
  AWStrReportPath: WideString;
  AWStrItemName: WideString;
  AWStrMessage: WideString;
  AWStrParentGUID: WideString;
  AWStrParentName: WideString;
  AWStrPortName: WideString;
  AWStrPortDescription: WideString;
  AWStrSeasonAstro: WideString;
  AWStrSeasonMeteo: WideString;
  AWStrSelectedObject: WideString;
  AWStrWarning: WideString;
  AWStrWarningAstro: WideString;
  AWStrWarningMeteo: WideString;
  AWStrListReportLine: TStringList;
  AWStrListReportText: TStringList;
  AStrListParents: TStringList;
  ATStrListAskOptions: TTntStringList;
  ATStrListImgItemAstro: TTntStringList;
  ATStrListImgItemMeteo: TTntStringList;
  ACatPropGroup: TCatalogPropGroup;
  AImgItem: TImageItem;
  AImgColl: TImageCollection;
  AImgColls: TImageCollections;
  AImgCollSeason: TImageCollection;
  AImgCollSeasonDateTime: TImageCollection;
  AImgCollSeasonAstro: TImageCollection;
  AImgCollSeasonAstroWinter: TImageCollection;
  AImgCollSeasonAstroSpring: TImageCollection;
  AImgCollSeasonAstroSummer: TImageCollection;
  AImgCollSeasonAstroAutumn: TImageCollection;
  AImgCollSeasonAstronotassigned: TImageCollection;
  AImgCollSeasonMeteo: TImageCollection;
  AImgCollSeasonMeteoWinter: TImageCollection;
  AImgCollSeasonMeteoSpring: TImageCollection;
  AImgCollSeasonMeteoSummer: TImageCollection;
  AImgCollSeasonMeteoAutumn: TImageCollection;
  AImgCollSeasonMeteonotassigned: TImageCollection;
  AImgModel: TImageModel;
  AImgGallery: TImageGallery;
  AxomProgress: TxomProgress;
  // ACatItemElem: TidElement; // FOR ARRAY METHOD
begin
  // check at least one season constant set to True
  if not cASeasonAstroSort and not cASeasonMeteoSort then
  begin
    Say2('No Seasons Sorted',
         'Please edit script to sort at least one season type.' + CrLf +
         'Current settings are:' + CrLf2 +
         '    (0=no, 1=yes)' + CrLf +
         '    cASeasonAstroSort = ' + IntToStr(cASeasonAstroSort) + CrLf +
         '    cASeasonAstroDataSet = ' + WideString(cASeasonAstroDataSet) + CrLf +
         '    cASeasonMeteoSort = ' + IntToStr(cASeasonMeteoSort) + CrLf +
         '    cASeasonHemisphere = ' + WideString(cASeasonHemisphere) + CrLf +
         '    cASeasonAddLabel = ' + IntToStr(cASeasonAddLabel));
    Exit; // exit script
  end;
  // prepare date time strings
  AWStrDateTimeDescription := FormatDateTime('yyyy-mm-dd hh:mm:ss', Now); // global var assign
  AWStrDateTimeSuffix := StringReplace(AWStrDateTimeDescription, '-', '', [0]); // THIS WORKS
  AWStrDateTimeSuffix := StringReplace(AWStrDateTimeSuffix, ':', '', [0]);  // THIS WORKS
  AWStrDateTimeSuffix := StringReplace(AWStrDateTimeSuffix, ' ', '_', [0]); // THIS WORKS
  // initialise report text string list
  AWStrListReportText := TStringList.Create;
  AWStrListReportText.Add(UTF8Encode(''));

  // STEP 00 - GET SELECTED ITEM(S)
  ACatPropGroup := SearchGroup;

  // STEP 01 - CREATE
  // SELECTED ITEM IS AN IMAGE OR A COLLECTION
  // create season collection and date time collection
  if ACatPropGroup.Collections.Count > 0 then
  begin
    // get collection parent portfolio, gallery and collections
    AImgModel := TImageModel.Create(nil);
    AImgGallery := TImageGallery.Create(nil);
    AStrListParents := TStringList.Create;
    AImgColls := TImageCollections.Create(TImageCollection, '');
    PublicCatalog.EnumModelForCollection(ACatPropGroup.Collections.Items[0], AImgModel);
    PublicCatalog.EnumGalleryForCollection(ACatPropGroup.Collections.Items[0], AImgGallery);
    PublicCatalog.EnumCollectionParents(ACatPropGroup.Collections.Items[0].GUID, AStrListParents);
    PublicCatalog.EnumCollectionsforParent(ACatPropGroup.Collections.Items[0].GUID, AImgColls);
    if AStrListParents <> nil then
    begin
      // assign parent GUID and name
      if AStrListParents.Count = 1 then // COLLECTION PARENT IS A PORTFOLIO
      begin
        AWStrParentGUID := AImgGallery.GUID;
        AWStrParentName := AImgModel.ModelName;
      end
      else                              // COLLECTION PARENT IS A COLLECTION
      begin
        AImgColl := TImageCollection.Create(nil);
        PublicCatalog.EnumCollectionByGUID(AStrListParents.Strings[AStrListParents.Count-2], AImgColl);
        AWStrParentGUID := AImgColl.GUID;
        AWStrParentName := AImgColl.CollectionName;
        AImgColl.Free;
      end;
      // create parent collections
      AWStrCollName := ACatPropGroup.Collections.Items[0].CollectionName + ' - Season';
      AWStrCollDescription := 'created: ' + AWStrDateTimeDescription + CrLf +
                              'original collection: ' + ACatPropGroup.Collections.Items[0].CollectionName + CrLf +
                              'original collection parent: ' + AWStrParentName + CrLf +
                              'original collection gallery: ' + AImgGallery.GalleryName + CrLf +
                              'original collection portfolio: ' + AImgModel.ModelName;
      AImgCollSeason := funcCreateCollection(AWStrParentGUID, AWStrCollName, AWStrCollDescription); // CALL FUNC
      AImgCollSeasonDateTime := funcCreateCollection(AImgCollSeason.GUID, 'Season_' + AWStrDateTimeSuffix, AWStrCollDescription); // CALL FUNC
    end;
    AImgModel.Free;
    AImgGallery.Free;
    AStrListParents.Free;
    AImgColls.Free;
  end

  // STEP 02 - CREATE
  // SELECTED ITEM IS A PORTFOLIO
  // create season portfolio and date time collection
  else if ACatPropGroup.Albums.Count > 0 then
  begin
    AImgModel := TImageModel.Create(nil);
    AImgGallery := TImageGallery.Create(nil);
    // create parent portfolio
    AWStrPortName := ACatPropGroup.Albums.Items[0].ModelName + ' - Season';
    AWStrPortDescription:= 'created: ' + AWStrDateTimeDescription + CrLf +
                           'original portfolio: ' + ACatPropGroup.Albums.Items[0].ModelName;
    procCreatePortfolioNamed(AWStrPortName, AWStrPortDescription); // CALL PROC
    // create parent collection
    PublicCatalog.EnumModelNamed(AWStrPortName, AImgModel);
    PublicCatalog.EnumModelGalleryNamed(AWStrPortName, AImgModel, AImgGallery);
    AImgCollSeasonDateTime := funcCreateCollection(AImgGallery.GUID, 'Season_' + AWStrDateTimeSuffix, AWStrPortDescription); // CALL FUNC
    AImgModel.Free;
    AImgGallery.Free;
  end

  // STEP 03 - CREATE
  // SELECTED ITEM IS NOT AN IMAGE, A COLLECTION OR A PORTFOLIO
  else
  begin
     Say('Please select an Image, Collection or Portfolio (under Portfolios tab).');
     Exit; // exit script
  end;

  // STEP 04 - CREATE
  // CREATE SEASON SUB COLLECTIONS
  if cASeasonAstroSort then
  begin
    AWStrCollDescription := cASeasonHemisphere + ' Hemisphere' + CrLf + cASeasonAstroDataSet;
    // create astronomical season collection for season date time collection
    AImgCollSeasonAstro := funcCreateCollection(AImgCollSeasonDateTime.GUID, 'Astronomical', AWStrCollDescription); // CALL FUNC
    // create seasons collections for astronomical season collection
    AImgCollSeasonAstroWinter := funcCreateCollection(AImgCollSeasonAstro.GUID, 'Winter', AWStrCollDescription); // CALL FUNC
    AImgCollSeasonAstroSpring := funcCreateCollection(AImgCollSeasonAstro.GUID, 'Spring', AWStrCollDescription); // CALL FUNC
    AImgCollSeasonAstroSummer := funcCreateCollection(AImgCollSeasonAstro.GUID, 'Summer', AWStrCollDescription); // CALL FUNC
    AImgCollSeasonAstroAutumn := funcCreateCollection(AImgCollSeasonAstro.GUID, 'Autumn', AWStrCollDescription); // CALL FUNC
    AImgCollSeasonAstronotassigned := funcCreateCollection(AImgCollSeasonAstro.GUID, 'not assigned', 'Photo Date Issue: no year match found.'); // CALL FUNC
  end;
  if cASeasonMeteoSort then
  begin
    AWStrCollDescription := cASeasonHemisphere + ' Hemisphere';
    // create meteorological season collection for season date time collection
    AImgCollSeasonMeteo := funcCreateCollection(AImgCollSeasonDateTime.GUID, 'Meteorological', AWStrCollDescription); // CALL FUNC
    // create seasons collections for meteorological season collection
    AImgCollSeasonMeteoWinter := funcCreateCollection(AImgCollSeasonMeteo.GUID, 'Winter', AWStrCollDescription); // CALL FUNC
    AImgCollSeasonMeteoSpring := funcCreateCollection(AImgCollSeasonMeteo.GUID, 'Spring', AWStrCollDescription); // CALL FUNC
    AImgCollSeasonMeteoSummer := funcCreateCollection(AImgCollSeasonMeteo.GUID, 'Summer', AWStrCollDescription); // CALL FUNC
    AImgCollSeasonMeteoAutumn := funcCreateCollection(AImgCollSeasonMeteo.GUID, 'Autumn', AWStrCollDescription); // CALL FUNC
    AImgCollSeasonMeteonotassigned := funcCreateCollection(AImgCollSeasonMeteo.GUID, 'not assigned', 'Photo Date Issue: no month match found.'); // CALL FUNC
  end;

  // STEP 05 - PROCESS
  // SELECTED ITEM IS AN IMAGE
  if Selected.Count > 0 then
  begin
    // initialise progress bar
    AxomProgress := TxomProgress.Create(nil);
    AxomProgress.Caption := 'Processing Selected Items...';
    AxomProgress.Pos := 0;
    AxomProgress.Max := Selected.Count;
    AxomProgress.CanCancel := True;
    AxomProgress.Show;
    // sort selected items
    ATStrListImgItemAstro := TTntStringList.Create;
    ATStrListImgItemMeteo := TTntStringList.Create;
    for i := 0 to Selected.Count - 1 do
    begin
      // '.ImageName' is no longer working
      // // some items return AImgItem.ImageName without extension:
      // if ExtractFileExt(Selected.Items[i].ImageName) = '' then
      //   AWStrItemName := Selected.Items[i].ImageName + ExtractFileExt(Selected.Items[i].FileName);
      // else
      //   AWStrItemName := Selected.Items[i].ImageName;
      // get item name
      AWStrItemName := WideExtractFileName(Selected.Items[i].FileName);
      // update progress bar
      AxomProgress.Pos := i + 1;
      AxomProgress.ProgressText := 'item ' + IntToStr(i) + ' of ' +
                                   IntToStr(Selected.Count) + ': ' +
                                   AWStrItemName;
      if AxomProgress.Cancel then
        Break; // exit for-loop
      // get item season
      AWStrWarningAstro := '';
      AWStrWarningMeteo := '';
      // store as astronomical season if sort switch on
      if cASeasonAstroSort then
      begin
        AWStrSeasonAstro := iif(cASeasonHemisphere = 'Northern',
                                funcGetSeasonAstroNorth(Selected.Items[i].PhotoDate),
                                funcGetSeasonAstroSouth(Selected.Items[i].PhotoDate)); // CALL FUNC
        // add season label to item
        if cASeasonAddLabel and (Length(AWStrSeasonAstro) = 6) then // if switch on and valid season
          procLabelImgItemKeywords(Selected.Items[i], 'astronomical ' + WideLowerCase(AWStrSeasonAstro)); // CALL PROC
        // store item to collection
        Case funcChangeToTitleCase(AWStrSeasonAstro) of // CALL FUNC
          'Winter': PublicCatalog.StoreItemToCollection(Selected.Items[i], AImgCollSeasonAstroWinter, PublicOptions.XMPSyncReadSettings, False);
          'Spring': PublicCatalog.StoreItemToCollection(Selected.Items[i], AImgCollSeasonAstroSpring, PublicOptions.XMPSyncReadSettings, False);
          'Summer': PublicCatalog.StoreItemToCollection(Selected.Items[i], AImgCollSeasonAstroSummer, PublicOptions.XMPSyncReadSettings, False);
          'Autumn': PublicCatalog.StoreItemToCollection(Selected.Items[i], AImgCollSeasonAstroAutumn, PublicOptions.XMPSyncReadSettings, False);
        else
          begin
            AWStrWarningAstro := 'Astro warning: some seasons not assigned' + CrLf;
            PublicCatalog.StoreItemToCollection(Selected.Items[i], AImgCollSeasonAstronotassigned, PublicOptions.XMPSyncReadSettings, False);
          end;
        end;
        AWStrListReportLine := TStringList.Create;
        AWStrListReportLine.Add(UTF8Encode(IntToStr(i)));
        AWStrListReportLine.Add(UTF8Encode('ASTRO'));
        AWStrListReportLine.Add(UTF8Encode(funcChangeToTitleCase(AWStrSeasonAstro))); // CALL FUNC
        AWStrListReportLine.Add(UTF8Encode(DateTimeToExifDate(Selected.Items[i].PhotoDate)));
        AWStrListReportLine.Add(UTF8Encode(AWStrItemName));
        AWStrListReportLine.Add(UTF8Encode(Selected.Items[i].FileName));
        AWStrListReportText.Add(AWStrListReportLine.CommaText);
        AWStrListReportLine.Free;
      end;
      // store as meteorological season if sort switch on
      if cASeasonMeteoSort then
      begin
        AWStrSeasonMeteo := iif(cASeasonHemisphere = 'Northern',
                                funcGetSeasonMeteoNorth(Selected.Items[i].PhotoDate),
                                funcGetSeasonMeteoSouth(Selected.Items[i].PhotoDate)); // CALL FUNC
        // add season label to item
        if cASeasonAddLabel and (Length(AWStrSeasonMeteo) = 6) then // if switch on and valid season
          procLabelImgItemKeywords(Selected.Items[i], 'meteorological ' + WideLowerCase(AWStrSeasonMeteo)); // CALL PROC
        // store item to collection
        Case funcChangeToTitleCase(AWStrSeasonMeteo) of // CALL FUNC
          'Winter': PublicCatalog.StoreItemToCollection(Selected.Items[i], AImgCollSeasonMeteoWinter, PublicOptions.XMPSyncReadSettings, False);
          'Spring': PublicCatalog.StoreItemToCollection(Selected.Items[i], AImgCollSeasonMeteoSpring, PublicOptions.XMPSyncReadSettings, False);
          'Summer': PublicCatalog.StoreItemToCollection(Selected.Items[i], AImgCollSeasonMeteoSummer, PublicOptions.XMPSyncReadSettings, False);
          'Autumn': PublicCatalog.StoreItemToCollection(Selected.Items[i], AImgCollSeasonMeteoAutumn, PublicOptions.XMPSyncReadSettings, False);
        else
          begin
            AWStrWarningMeteo := 'Meteo warning: some seasons not assigned' + CrLf;
            PublicCatalog.StoreItemToCollection(Selected.Items[i], AImgCollSeasonMeteonotassigned, PublicOptions.XMPSyncReadSettings, False);
          end;
        end;
        AWStrListReportLine := TStringList.Create;
        AWStrListReportLine.Add(UTF8Encode(IntToStr(i)));
        AWStrListReportLine.Add(UTF8Encode('METEO'));
        AWStrListReportLine.Add(UTF8Encode(funcChangeToTitleCase(AWStrSeasonMeteo))); // CALL FUNC
        AWStrListReportLine.Add(UTF8Encode(DateTimeToExifDate(Selected.Items[i].PhotoDate)));
        AWStrListReportLine.Add(UTF8Encode(AWStrItemName));
        AWStrListReportLine.Add(UTF8Encode(Selected.Items[i].FileName));
        AWStrListReportText.Add(AWStrListReportLine.CommaText);
        AWStrListReportLine.Free;
      end;
    end;
    // send feedback
    SendVisualFeedback('season sort complete', 3000);
    // close progress bar
    if AxomProgress.Cancel then
    begin
      Say('AxomProgress Cancelled.');
      Exit; // exit procedure
    end;
    AxomProgress.Hide;
    AxomProgress.Free;
    ATStrListImgItemAstro.Free;
    ATStrListImgItemMeteo.Free;
  end

  // STEP 06 - PROCESS
  // SELECTED ITEM IS A COLLECTION OR A PORTFOLIO
  else if (ACatPropGroup.Collections.Count > 0) or (ACatPropGroup.Albums.Count > 0) then
  begin
    //gACatItemsArray := TidElement.Create(nil); // global var // FOR ARRAY METHOD
    // get image items for all sub collections
    gATStrListCatItemGUID := TTntStringList.Create; // global var
    gATStrListCatItemGUID.Duplicates := dupAccept; // global var
    gATStrListCatItemParentGUID := TTntStringList.Create; // global var
    gATStrListCatItemParentGUID.Duplicates := dupAccept; // global var
    if ACatPropGroup.Collections.Count > 0 then
    begin
      AWStrSelectedObject := 'Collection: ' + ACatPropGroup.Collections.Items[0].CollectionName;
      procGetCollAllCatItems(ACatPropGroup.Collections.Items[0]); // CALL PROC
    end
    else if ACatPropGroup.Albums.Count > 0 then
    begin
      AWStrSelectedObject := 'Portfolio: ' + ACatPropGroup.Albums.Items[0].ModelName;
      AImgColls := TImageCollections.Create(TImageCollection, '');
      PublicCatalog.EnumCollectionsforParent(ACatPropGroup.Albums.Items[0].GUID, AImgColls);
      procGetCollsAllCatItems(AImgColls); // CALL PROC
    end;
    procDeleteTStrListDupCatItem; // CALL PROC
    // initialise progress bar
    AxomProgress := TxomProgress.Create(nil);
    AxomProgress.Caption := 'Processing ' + AWStrSelectedObject;
    AxomProgress.Pos := 0;
    AxomProgress.Max := gATStrListCatItemGUID.Count; // global var
    AxomProgress.CanCancel := True;
    AxomProgress.Show;
    // sort items for all sub collections
    ATStrListImgItemAstro := TTntStringList.Create;
    ATStrListImgItemMeteo := TTntStringList.Create;
    //for i := 0 to gACatItemsArray.Count - 1 do // global var // FOR ARRAY METHOD
    for i := 0 to gATStrListCatItemGUID.Count - 1 do // global var
    begin
      //ACatItemElem := gACatItemsArray.Elements.Items[i]; // global var // FOR ARRAY METHOD
      //PublicCatalog.EnumCollectionItem(ACatItemElem.Prop['CatItemParentGUID'], ACatItemElem.Prop['CatItemGUID'], AImgItem); // FOR ARRAY METHOD
      AImgItem := TImageItem.Create(nil);
      PublicCatalog.EnumCollectionItem(gATStrListCatItemParentGUID.Strings[i], gATStrListCatItemGUID.Strings[i], AImgItem); // global var
      // '.ImageName' is no longer working (use '.FileName' instead)
      // // some items return AImgItem.ImageName without extension:
      // if ExtractFileExt(AImgItem.ImageName) = '' then
      //   AWStrItemName := AImgItem.ImageName + ExtractFileExt(AImgItem.FileName);
      // else
      //   AWStrItemName := AImgItem.ImageName;
      // get item name
      AWStrItemName := WideExtractFileName(AImgItem.FileName);
      // update progress bar
      AxomProgress.Pos := i + 1;
      AxomProgress.ProgressText := 'item ' + IntToStr(i) + ' of ' +
                                   IntToStr(gATStrListCatItemGUID.Count) +
                                   ': ' + AWStrItemName; // global var
      if AxomProgress.Cancel then
        Break; // exit for-loop
      // get item season
      AWStrWarningAstro := '';
      AWStrWarningMeteo := '';
      // store as astronomical season if sort switch on
      if cASeasonAstroSort then
      begin
        AWStrSeasonAstro := iif(cASeasonHemisphere = 'Northern',
                                funcGetSeasonAstroNorth(AImgItem.PhotoDate),
                                funcGetSeasonAstroSouth(AImgItem.PhotoDate)); // CALL FUNC
        // add season label to item
        if cASeasonAddLabel and (Length(AWStrSeasonAstro) = 6) then // if switch on and valid season
          procLabelImgItemKeywords(AImgItem, 'astronomical ' + WideLowerCase(AWStrSeasonAstro)); // CALL PROC
        // store item to collection
        Case funcChangeToTitleCase(AWStrSeasonAstro) of // CALL FUNC
          'Winter': PublicCatalog.StoreItemToCollection(AImgItem, AImgCollSeasonAstroWinter, PublicOptions.XMPSyncReadSettings, False);
          'Spring': PublicCatalog.StoreItemToCollection(AImgItem, AImgCollSeasonAstroSpring, PublicOptions.XMPSyncReadSettings, False);
          'Summer': PublicCatalog.StoreItemToCollection(AImgItem, AImgCollSeasonAstroSummer, PublicOptions.XMPSyncReadSettings, False);
          'Autumn': PublicCatalog.StoreItemToCollection(AImgItem, AImgCollSeasonAstroAutumn, PublicOptions.XMPSyncReadSettings, False);
        else
          begin
            AWStrWarningAstro := 'Astro warning: some seasons not assigned' + CrLf;
            PublicCatalog.StoreItemToCollection(AImgItem, AImgCollSeasonAstronotassigned, PublicOptions.XMPSyncReadSettings, False);
          end;
        end;
        AWStrListReportLine := TStringList.Create;
        AWStrListReportLine.Add(UTF8Encode(IntToStr(i)));
        AWStrListReportLine.Add(UTF8Encode('ASTRO'));
        AWStrListReportLine.Add(UTF8Encode(funcChangeToTitleCase(AWStrSeasonAstro))); // CALL FUNC
        AWStrListReportLine.Add(UTF8Encode(DateTimeToExifDate(AImgItem.PhotoDate)));
        AWStrListReportLine.Add(UTF8Encode(AWStrItemName));
        AWStrListReportLine.Add(UTF8Encode(AImgItem.FileName));
        AWStrListReportText.Add(AWStrListReportLine.CommaText);
        AWStrListReportLine.Free;
      end;
      // store as meteorological season if sort switch on
      if cASeasonMeteoSort then
      begin
        AWStrSeasonMeteo := iif(cASeasonHemisphere = 'Northern',
                                funcGetSeasonMeteoNorth(AImgItem.PhotoDate),
                                funcGetSeasonMeteoSouth(AImgItem.PhotoDate)); // CALL FUNC
        // add season label to item
        if cASeasonAddLabel and (Length(AWStrSeasonMeteo) = 6) then // if switch on and valid season
          procLabelImgItemKeywords(AImgItem, 'meteorological ' + WideLowerCase(AWStrSeasonMeteo)); // CALL PROC
        // store item to collection
        Case funcChangeToTitleCase(AWStrSeasonMeteo) of // CALL FUNC
          'Winter': PublicCatalog.StoreItemToCollection(AImgItem, AImgCollSeasonMeteoWinter, PublicOptions.XMPSyncReadSettings, False);
          'Spring': PublicCatalog.StoreItemToCollection(AImgItem, AImgCollSeasonMeteoSpring, PublicOptions.XMPSyncReadSettings, False);
          'Summer': PublicCatalog.StoreItemToCollection(AImgItem, AImgCollSeasonMeteoSummer, PublicOptions.XMPSyncReadSettings, False);
          'Autumn': PublicCatalog.StoreItemToCollection(AImgItem, AImgCollSeasonMeteoAutumn, PublicOptions.XMPSyncReadSettings, False);
        else
          begin
            AWStrWarningMeteo := 'Meteo warning: some seasons not assigned' + CrLf;
            PublicCatalog.StoreItemToCollection(AImgItem, AImgCollSeasonMeteonotassigned, PublicOptions.XMPSyncReadSettings, False);
          end;
        end;
        AWStrListReportLine := TStringList.Create;
        AWStrListReportLine.Add(UTF8Encode(IntToStr(i)));
        AWStrListReportLine.Add(UTF8Encode('METEO'));
        AWStrListReportLine.Add(UTF8Encode(funcChangeToTitleCase(AWStrSeasonMeteo))); // CALL FUNC
        AWStrListReportLine.Add(UTF8Encode(DateTimeToExifDate(AImgItem.PhotoDate)));
        AWStrListReportLine.Add(UTF8Encode(AWStrItemName));
        AWStrListReportLine.Add(UTF8Encode(AImgItem.FileName));
        AWStrListReportText.Add(AWStrListReportLine.CommaText);
        AWStrListReportLine.Free;
      end;
      AImgItem.Free;
    end;
    // send feedback
    SendVisualFeedback('season sort complete', 3000);
    // close progress bar
    if AxomProgress.Cancel then
    begin
      Say('AxomProgress Cancelled.');
      Exit; // exit procedure
    end;
    AxomProgress.Hide;
    AxomProgress.Free;
    ATStrListImgItemAstro.Free;
    ATStrListImgItemMeteo.Free;
    gATStrListCatItemGUID.Free; // global var
    gATStrListCatItemParentGUID.Free; // global var
    if ACatPropGroup.Albums.Count > 0 then
      AImgColls.Free;
  end

  // STEP 07 - PROCESS
  // SELECTED ITEM IS NOT AN IMAGE, A COLLECTION OR A PORTFOLIO
  else
  begin
     Say('Please select an Image, Collection or Portfolio (under Portfolios tab).');
     Exit; // exit script
  end;

  // STEP 08 - DIALOG
  // save sorted items to file
  if cASaveReport then
  begin
    // prepare report file strings
    AWStrReportPath := iif(cAScriptReportPath = '',
                           OMPublic.WindowsMyDocumentsDir,
                           cAScriptReportPath);
    AWStrReportPath := AWStrReportPath + cAScriptReportDir + '\';
    AWStrReportName := WideChangeFileExt(cAScriptName, '') + '_' +
                       WideChangeFileExt(cAScriptReportName, '') + '_' +
                       AWStrDateTimeSuffix + '.csv';
    AWStrReportFile := AWStrReportPath + AWStrReportName;
    // create report directory if it doesn't already exist
    ABlnInvalidDir := False;
    if not WideDirectoryExists(AWStrReportPath) then
      if not WideForceDirectories(AWStrReportPath) then
        ABlnInvalidDir := True;
    if not ABlnInvalidDir then
      AWStrListReportText.SaveToFile(AWStrReportFile);
    // prepare message
    AWStrMessage := 'Items saved to file:' +
                    sLineBreak + sLineBreak +
                    AWStrReportFile;
    // send feedback
    SendVisualFeedback(AWStrMessage, 5000);
    if cAShowDialog then
      begin
      // prepare warning
      AWStrWarning := AWStrWarningAstro + AWStrWarningMeteo;
      if AWStrWarning <> '' then
        AWStrWarning := AWStrWarning + 'Please see saved file for details.';
      // show dialog
      ABlnAskChecked := False;
      ATStrListAskOptions := TTntStringList.Create;
      AIntAskButton := AskCustom(
                         'Season Sort Complete',
                         AWStrWarning + CrLf2 + AWStrMessage,
                         'Edit script to specify editor to open report ' +
                         '''.csv'' file.' ,             // 'hidden details'
                         'Open report folder and file', // 'check box'
                         ABlnAskChecked,
                         ATStrListAskOptions);
      ATStrListAskOptions.Free;
      // open report folder and file
      // if button OK clicked     AIntAskButton = -99
      // if button Cancel clicked AIntAskButton = -1
      if AIntAskButton <> -1 then
      begin
        if ABlnAskChecked = True then
        begin
          ShellDoExecute(nil, AWStrReportPath);
          if cAEditor = '' then
            ShellDoExecute(nil, AWStrReportFile);
          else
            RunCommand(cAEditor + ' "' + AWStrReportFile + '"');
        end;
      end;
    end;
  end;
  AWStrListReportText.Free;

  AImgCollSeason.Free;
  AImgCollSeasonDateTime.Free;
  AImgCollSeasonAstro.Free;
  AImgCollSeasonAstroWinter.Free;
  AImgCollSeasonAstroSpring.Free;
  AImgCollSeasonAstroSummer.Free;
  AImgCollSeasonAstroAutumn.Free;
  AImgCollSeasonAstronotassigned.Free;
  AImgCollSeasonMeteo.Free;
  AImgCollSeasonMeteoWinter.Free;
  AImgCollSeasonMeteoSpring.Free;
  AImgCollSeasonMeteoSummer.Free;
  AImgCollSeasonMeteoAutumn.Free;
  AImgCollSeasonMeteonotassigned.Free;
end;