Search notes:

Oracle scriptlets

ash-awr - awr - AWRDataToExcel.bas

'
'      See also
'          o https://github.com/ReneNyffenegger/development_misc/blob/master/vba/excel/some_data_import.bas    and
'          o https://github.com/ReneNyffenegger/development_misc/blob/master/vba/excel/CSV_import.bas
'
option explicit

public sub Run(csvFileName as string, lineCharacteristics as string) ' {

    dim diagram as chart

    createDataAndDiagramSheet

    importCsv csvFileName

    set diagram = application.sheets("diagram")

    assignDataToChart diagram
    formatChart       diagram, lineCharacteristics


end sub ' }

private sub createDataAndDiagramSheet() ' {

   ' There need to be two work sheets. One for the data (that is �imported� 
   ' from a csv file, and one for the created diagram that is based on that
   ' data
   '
   ' When Excel starts, there is one sheet.

   dim sh_diagram as chart 

   if application.sheets.count <> 1 then
      msgBox "Assumption about count of sheets was wrong, the count is: " & application.sheets.count
   end if

   ' Name this first sheet data

   application.sheets(1).name = "data"

   ' Insert the second sheet for the diagram:

   set sh_diagram = application.sheets.add (type := xlChart)

   sh_diagram.name = "diagram"

   
end sub ' }

private sub importCsv(csvFileName as string) ' {
'
'       https://github.com/ReneNyffenegger/development_misc/blob/master/vba/excel/some_data_import.bas
'

    dim qt      as queryTable
    dim dest    as range
    dim sh      as workSheet

    set sh   = application.sheets("data")
    set dest = application.range("data!$a$1")

    set qt   = sh.queryTables.add(connection   := "TEXT;" & csvFileName, _
                                  destination  :=  dest)


    qt.textFileParseType          = xlDelimited
    qt.textFileSemicolonDelimiter = true

    qt.name = "imported_data"

    qt.refresh

end sub ' }

private sub assignDataToChart(diagram as chart) ' {

  diagram.setSourceData source := range("data!imported_data")

end sub ' }

private sub setPageUp(diagram as chart) ' {

  dim ps as pageSetup

  set ps = diagram.pageSetup

  ps.leftMargin   = application.centimetersToPoints(0.5)
  ps.rightMargin  = application.centimetersToPoints(0.5)
  ps.topMargin    = application.centimetersToPoints(0.5)
  ps.bottomMargin = application.centimetersToPoints(0.5)

  ps.headerMargin = application.centimetersToPoints( 0 )
  ps.footerMargin = application.centimetersToPoints( 0 )

end sub ' }

private sub formatChart(diagram as chart, lineCharacteristics as string) ' {

  dim leg as legend
  dim ser as series

  dim characteristicsArray() as string
  dim columnNameAndvalues () as string
  dim columnValues           as string
  dim valuesArray         () as string
  dim rgb_s                  as string
  dim width                  as double
  dim rgbArray            () as string
  dim i                      as long

  dim columnName as string

  dim s as string

  diagram.chartType = xlLine

  diagram.plotArea.top    =   9
  diagram.plotArea.left   =  45
  diagram.plotArea.width  = 748
  diagram.plotArea.height = 480

  setPageUp diagram

  ' { legend

  set leg = diagram.legend

  leg.includeInLayout = false

  leg.format.fill.foreColor.objectThemeColor = msoThemeColorBackground1
  leg.format.fill.transparency = 0.3
  leg.format.fill.solid

  ' }


  '   Split the line charactersistics into its components...
  characteristicsArray = split(lineCharacteristics, ";")

  '   and iterate over each element for the line characteristics
  for i = lbound(characteristicsArray) to ubound(characteristicsArray) ' {

  '   A component is supposed to be
  '
  '  "Column Name:values...."
  '
  '   So, we split on the ":" ...

      columnNameAndvalues = split(characteristicsArray(i), ":")

  '   in order to get columnName and columnNameAndvalues
      columnName   = columnNameAndvalues(0)
      columnValues = columnNameAndvalues(1)

  '   The values itself are supposed to be divided by a "|":

      valuesArray  = split(columnValues, "|")

  '   Left of the bar is the desired rgb value ("red,green,blue"), right of the
  '   bar the width of the line

      rgb_s   = valuesArray(0)
      width   = valuesArray(1)

      rgbArray = split(rgb_s, ",")

   '  cstr()? 
   '  See http://stackoverflow.com/questions/12620239/what-is-the-difference-between-string-variable-and-cstrstring-variable
      set ser = diagram.seriesCollection.item(cstr(columnName))

      ser.format.line.foreColor.rgb = rgb(rgbArray(0),rgbArray(1),rgbArray(2))
      ser.format.line.weight        = width

    ' i = i + 1

  next i ' }

end sub ' }
Github repository oracle_scriptlets, path: /ash-awr/awr/AWRDataToExcel.bas

ash-awr - awr - SQLToExcel.sql

set    verify off
define SnapBegin=&1
define SnapEnd=&2
define SQLFile=&3
define LineCharacteristics=&4

set termout off

-- https://github.com/ReneNyffenegger/oracle_scriptlets/blob/master/sqlpath/to_csv.sql
@to_csv &SQLFile u:/temp/awr_data.csv

set termout on

-- https://github.com/ReneNyffenegger/development_misc/blob/master/vba/runVBAFilesInOffice.vbs
$u:\dev1\githup_development_misc\vba\runVBAFilesInOffice.vbs -excel AWRDataToExcel -c Run u:\temp\awr_data.csv "&LineCharacteristics"
Github repository oracle_scriptlets, path: /ash-awr/awr/SQLToExcel.sql

bmp - body.plsql

create or replace package body bmp as

  headersize constant pls_integer := 14;
  infosize   constant pls_integer := 40;
  offset     constant pls_integer := infosize + headersize;

  bmpWidth            pls_integer;
  bmpHeight           pls_integer;
  lineLen             pls_integer;
  filesize            pls_integer; 

  output_file         utl_file.file_type;

  the_bits            blob;


  function  unsigned_short(s in pls_integer) return raw is/*{*/
    ret raw(2);
    v   pls_integer;
    r   pls_integer;
  begin

    v := trunc (s/256); r := s-v; ret := utl_raw.cast_to_raw(chr(v));
    v := trunc (s    ); r := s-v; ret := utl_raw.cast_to_raw(chr(v)) || ret;
    
   return ret;

  end unsigned_short;/*}*/

  function  unsigned_rgb(r in pls_integer, g in pls_integer, b in pls_integer) return raw is /*{*/
    ret raw(3);
  begin

    ret := utl_raw.cast_to_raw(chr(r));
    ret := utl_raw.cast_to_raw(chr(g)) || ret;
    ret := utl_raw.cast_to_raw(chr(b)) || ret;
    
   return ret;

  end unsigned_rgb;/*}*/

  function  unsigned_int(i in pls_integer) return raw is /*{*/

    /* i = ret(4) * 256*256*256  +
           ret(3) * 256*256      +
           ret(2) * 256          +
           ret(1)                   */


--  ret raw(4);
--  v   pls_integer;
--  r   pls_integer;
  begin

--  v := trunc (i/256/256/256); r := i-v; ret := utl_raw.cast_to_raw(chr(v));
--  v := trunc (i/256/256    ); r := i-v; ret := utl_raw.cast_to_raw(chr(v)) || ret;
--  v := trunc (i/256        ); r := i-v; ret := utl_raw.cast_to_raw(chr(v)) || ret;
--  v := trunc (i            ); r := i-v; ret := utl_raw.cast_to_raw(chr(v)) || ret;

    return utl_raw.cast_from_binary_integer(i, utl_raw.little_endian);
    
-- return ret;

  end unsigned_int;/*}*/

  procedure WriteHeader is /*{*/
    imagesize pls_integer;
  begin
    imagesize := bmpHeight * lineLen;
    filesize  := imagesize + offset;

    -- Header
    dbms_lob.append(the_bits, utl_raw.cast_to_raw('BM')); -- Pos  0

    dbms_lob.append(the_bits, unsigned_int(filesize));    -- Pos  2

    dbms_lob.append(the_bits, unsigned_short(0));         -- Pos  6, reserved 1
    dbms_lob.append(the_bits, unsigned_short(0));         -- Pos  8, reserved 2
    dbms_lob.append(the_bits, unsigned_int(offset));      -- Pos 10, offset to image

    -- Information
    dbms_lob.append(the_bits, unsigned_int(infosize));    -- Pos 14
    dbms_lob.append(the_bits, unsigned_int(bmpWidth));    -- Pos 18
    dbms_lob.append(the_bits, unsigned_int(bmpHeight));   -- Pos 22

    dbms_lob.append(the_bits, unsigned_short( 1));        -- Pos 26, planes
    dbms_lob.append(the_bits, unsigned_short(24));        -- Pos 28, bits per pixel
    dbms_lob.append(the_bits, unsigned_int  ( 0));        -- Pos 30, no compression
    dbms_lob.append(the_bits, unsigned_int  (imagesize)); -- Pos 34

    dbms_lob.append(the_bits, unsigned_int  (7874));      -- Pos 38, x pixels/meter (???)
    dbms_lob.append(the_bits, unsigned_int  (7874));      -- Pos 42, y pixels/meter (???)
    dbms_lob.append(the_bits, unsigned_int  (0));         -- Pos 46, Number of colors
    dbms_lob.append(the_bits, unsigned_int  (0));         -- Pos 50, Important colors
  end WriteHeader;/*}*/

  procedure Init(width pls_integer, height pls_integer, r in pls_integer, g in pls_integer, b in pls_integer) is/*{*/
    bgColor raw(3);
  begin
    bmpWidth  := width;
    bmpHeight := height;

    -- lineLen must be divisible by 4
    lineLen := 4*ceil(3*bmpWidth/4);

    bgColor  := unsigned_rgb(r,g,b);
    the_bits := empty_blob();
    dbms_lob.createTemporary(the_bits, true);
    dbms_lob.open(the_bits, dbms_lob.lob_readwrite);

    WriteHeader;

    for x in 0 .. bmpWidth-1 loop for Y in 0 .. bmpHeight-1 loop
      dbms_lob.append(the_bits, bgColor);
    end loop; end loop;

  end Init;/*}*/

  function  AsBlob return blob is begin/*{*/
    return the_bits;
  end AsBlob;/*}*/

  procedure PixelAt(x in pls_integer, y in pls_integer, rgb in raw) is begin/*{*/
    
    if x < 0 or y < 0 or x >= bmpWidth or y >= bmpHeight then
      return;
    end if;

    dbms_lob.write(the_bits, 3, 1+offset+ (bmpHeight-y-1)*lineLen + x*3, rgb);
  end PixelAt;/*}*/

  procedure PixelAt(x pls_integer, /*{*/
                    y pls_integer, 
                    r pls_integer, 
                    g pls_integer, 
                    b pls_integer) is 
    rgb raw(3); 
  begin
    rgb := unsigned_rgb(r,g,b); 

    PixelAt(x, y, rgb);
  end PixelAt;/*}*/
 
  procedure Line (xFrom pls_integer, /*{*/
                  yFrom pls_integer, 
                  xTo   pls_integer, 
                  yTo   pls_integer, 
                  r     pls_integer, 
                  g     pls_integer, 
                  b     pls_integer) 
  is

    rgb    raw(3); 
    c      pls_integer;
    m      pls_integer;
    x      pls_integer;
    y      pls_integer;
    D      pls_integer;
    HX     pls_integer;
    HY     pls_integer;
    xInc   pls_integer;
    yInc   pls_integer;

  begin 

    rgb := unsigned_rgb(r,g,b); 

    x    :=       xFrom;
    y    :=       yFrom;
    D    :=           0;
    HX   := xTo - xfrom;
    HY   := yTo - yfrom;
    xInc :=           1;
    yInc :=           1;

    if HX < 0 then xInc := -1; HX   := -HX; end if;
    if HY < 0 then yInc := -1; HY   := -HY; end if;

    if HY <= HX then
      c := 2*HX;
      M := 2*HY;

      loop
        PixelAt(x, y, rgb);
        exit when x = xTo;

        x := x + xInc;
        D := D + M; 

        if D > HX then y := y+yInc; D := D-c; end if;
      end loop;

    else

      c := 2*HY;
      M := 2*HX;

      loop
        PixelAt(x, y, rgb);
        exit when y = yTo;

        y := y + yInc;
        D := D + M; 

        if D > HY then
          x := x + xInc;
          D := D - c;
        end if;
      end loop;

    end if;
  end Line;/*}*/

  procedure Circle_(x      pls_integer,/*{*/
                    y      pls_integer,
                    xx     pls_integer,
                    yy     pls_integer, 
                    rgb    raw)         
  is begin

    if xx = 0 then

      PixelAt(x      , y + yy , rgb);
      PixelAt(x      , y - yy , rgb);
      PixelAt(x  + yy, y      , rgb);
      PixelAt(x  - yy, y      , rgb);

    elsif xx = yy then

      PixelAt(x  + xx , y + yy , rgb);
      PixelAt(x  - xx , y + yy , rgb);
      PixelAt(x  + xx , y - yy , rgb);
      PixelAt(x  - xx , y - yy , rgb);

    elsif xx < yy then

      PixelAt(x  + xx , y + yy , rgb);
      PixelAt(x  - xx , y + yy , rgb);
      PixelAt(x  + xx , y - yy , rgb);
      PixelAt(x  - xx , y - yy , rgb);

      PixelAt(x  + yy , y + xx , rgb);
      PixelAt(x  - yy , y + xx , rgb);
      PixelAt(x  + yy , y - xx , rgb);
      PixelAt(x  - yy , y - xx , rgb);

    end if;
  end Circle_;/*}*/

  procedure Circle (x      pls_integer,/*{*/
                    y      pls_integer,
                    radius pls_integer,
                    r      pls_integer, 
                    g      pls_integer, 
                    b      pls_integer) 
  is

    xx  pls_integer := 0;
    yy  pls_integer := radius;
    pp  pls_integer := (5-radius*4)/4;
    rgb raw(3);

  begin

    rgb := unsigned_rgb(r,g,b); 

    Circle_(x, y, xx, yy, rgb);

    while xx < yy loop

      xx := xx+1;

      if pp < 0 then
        pp := pp + 2*xx+1;
      else
        yy := yy - 1;
        pp := pp + 2*(xx-yy) + 1;
      end if;

      Circle_(x, y, xx, yy, rgb);

    end loop;

  end Circle;/*}*/

  procedure Ellipse (/*{*/
  -------------------------------------------
  -- 
  --        Thanks to Thierry Vergote
  --        for implementing ellipse
  --        and fixing an endian bug 
  --        in unsigned_int.
  --
  -------------------------------------------
    x       pls_integer,
    y       pls_integer,
    xradius pls_integer,
    yradius pls_integer,
    r       pls_integer,
    g       pls_integer,
    b       pls_integer
  ) is
    x_           pls_integer;
    y_           pls_integer;
    xchange      pls_integer;
    ychange      pls_integer;
    ellipseerror pls_integer;
    twoasquare   pls_integer;
    twobsquare   pls_integer;
    stoppingx    pls_integer;
    stoppingy    pls_integer;
    rgb          raw(3);

    procedure plot4ellipsepoints (/*{*/
      xp4 pls_integer,
      yp4 pls_integer
    ) IS
    begin
      PixelAt(x + xp4, y + yp4, rgb); -- point in quadrant 1
      PixelAt(x - xp4, y + yp4, rgb); -- point in quadrant 2
      PixelAt(x - xp4, y - yp4, rgb); -- point in quadrant 3
      PixelAt(x + xp4, y - yp4, rgb); -- point in quadrant 4
    end plot4ellipsepoints;/*}*/

  begin
    rgb          := unsigned_rgb(r,g,b); 
    twoasquare   := 2 * xradius * xradius;
    twobsquare   := 2 * yradius * yradius;
    x_           := xradius;
    y_           := 0;
    xchange      := yradius * yradius * (1 - 2 * xradius);
    ychange      := xradius * xradius;
    ellipseerror := 0;
    stoppingx    := twobsquare * xradius;
    stoppingy    := 0;
    while stoppingx >= stoppingy loop/*{*/
      -- 1st set of points, y_' > 1
      plot4ellipsepoints(x_, y_); 
      y_           := y_ + 1;
      stoppingy    := stoppingy    + twoasquare;
      ellipseerror := ellipseerror + ychange;
      ychange      := ychange      + twoasquare;
      if 2 * ellipseerror + xchange > 0 then
        x_           := x_ - 1; 
        stoppingx    := stoppingx - twobsquare; 
        ellipseerror := ellipseerror + xchange;
        xchange      := xchange + twobsquare; 
      end if;
    end loop;/*}*/
    -- 1st point set is done; start the 2nd set of points 
    x_            := 0;
    y_            := yradius;
    xchange      := yradius * yradius;
    ychange      := xradius * xradius * (1 - 2 * yradius);
    ellipseerror := 0;
    stoppingx    := 0;
    stoppingy    := twoasquare * yradius;
    while stoppingx <= stoppingy loop/*{*/
      -- 2nd set of points, y_'< 1
      plot4ellipsepoints(x_, y_); 
      x_            := x_ + 1; 
      stoppingx    := stoppingx + twobsquare; 
      ellipseerror := ellipseerror + xchange; 
      xchange      := xchange + twobsquare;
      if 2 * ellipseerror + ychange > 0 then
        y_            := y_ - 1; 
        stoppingy    := stoppingy - twoasquare; 
        ellipseerror := ellipseerror + ychange; 
        ychange      := ychange + twoasquare; 
      end if;
    end loop;/*}*/
  end Ellipse;/*}*/

end bmp;
/
Github repository oracle_scriptlets, path: /bmp/body.plsql

bmp - spec.plsql

create or replace package bmp as 

/* 
   Package bmp (spec.plsql and body.plsql)

   Copyright (C) René Nyffenegger

   This source code is provided 'as-is', without any express or implied
   warranty. In no event will the author be held liable for any damages
   arising from the use of this software.

   Permission is granted to anyone to use this software for any purpose,
   including commercial applications, and to alter it and redistribute it
   freely, subject to the following restrictions:

   1. The origin of this source code must not be misrepresented; you must not
      claim that you wrote the original source code. If you use this source code
      in a product, an acknowledgment in the product documentation would be
      appreciated but is not required.

   2. Altered source versions must be plainly marked as such, and must not be
      misrepresented as being the original source code.

   3. This notice may not be removed or altered from any source distribution.

   René Nyffenegger rene.nyffenegger@adp-gmbh.ch

*/

  procedure Init   (width  pls_integer, 
                    height pls_integer,
                    r      pls_integer := 0, 
                    g      pls_integer := 0, 
                    b      pls_integer := 0);

  procedure PixelAt(x      pls_integer, 
                    y      pls_integer, 
                    r      pls_integer, 
                    g      pls_integer, 
                    b      pls_integer);

  procedure Line   (xFrom  pls_integer, 
                    yFrom  pls_integer, 
                    xTo    pls_integer, 
                    yTo    pls_integer, 
                    r      pls_integer, 
                    g      pls_integer, 
                    b      pls_integer);

  procedure Circle (x      pls_integer,
                    y      pls_integer,
                    radius pls_integer,
                    r      pls_integer, 
                    g      pls_integer, 
                    b      pls_integer);

  procedure Ellipse (/*{*/
  -------------------------------------------
  -- 
  --        Thanks to Thierry Vergote
  --        for implementing ellipse
  --        and fixing an endian bug 
  --        in this package.
  --
  -------------------------------------------
                   x       pls_integer,
                   y       pls_integer,
                   xradius pls_integer,
                   yradius pls_integer,
                   r       pls_integer,
                   g       pls_integer,
                   b       pls_integer);/*}*/

  function  AsBlob return blob;

end bmp;
/
Github repository oracle_scriptlets, path: /bmp/spec.plsql

bmp - test - create_directory.sql

create directory bmp_out_dir as 'c:\temp';
Github repository oracle_scriptlets, path: /bmp/test/create_directory.sql

bmp - test - drop_directory.sql

drop directory bmp_out_dir;
Github repository oracle_scriptlets, path: /bmp/test/drop_directory.sql

bmp - test - run.sql

@create_directory
@test_01
@test_02
@test_03_png
@drop_directory
Github repository oracle_scriptlets, path: /bmp/test/run.sql

bmp - test - test_01.sql

begin
  bmp.Init(300, 200, 238, 238, 204);

  bmp.Line(  0,   0,   0, 199,  66, 166, 194);
  bmp.Line(  0, 199, 299, 199,  66, 166, 194);
  bmp.Line(299, 199, 299,   0,  66, 166, 194);
  bmp.Line(299,   0,   0,   0,  66, 166, 194);

  for i in 1 .. 36 loop 
    bmp.Line(150, 100, 150+sin(i/18*3.141)* 80, 100+cos(i/18*3.141)*80, 55, 0, 180);
  end loop;

  bmp.Circle(150, 100, 80, 255, 0, 0);

  blob_wrapper.to_file('BMP_OUT_DIR', 'test_01.bmp', bmp.AsBlob);
end;
/
Github repository oracle_scriptlets, path: /bmp/test/test_01.sql

bmp - test - test_02.sql

begin
  bmp.Init   (300, 200, 238, 238, 204);
  bmp.Ellipse(150, 100, 120, 80, 250, 100, 10);

  blob_wrapper.to_file('BMP_OUT_DIR', 'test_02.bmp', bmp.AsBlob);
end;
/
Github repository oracle_scriptlets, path: /bmp/test/test_02.sql

bmp - test - test_03_png.sql

declare

--    -------------------------------------------------
--
--    August 2017: Thanks to Brian McGinity for
--    demonstrating on how to
--    create a png
--
--    -------------------------------------------------

  srcImg     ordsys.ordImage; 
  readyImg   ordsys.ordImage;
begin

  bmp.Init   (300, 200, 238, 238, 204);
  bmp.Ellipse(150, 100, 120,  80, 250, 100, 10);


  srcImg  := ordsys.ordimage.init();
  srcImg.source.localdata := bmp.AsBlob;
  srcImg.setProperties();
 

  readyImg := ordsys.ordimage.init();
  dbms_lob.createtemporary(readyImg.source.localdata, true);

  ordsys.ordimage.processcopy(srcImg,'fileFormat=png', readyImg);

  blob_wrapper.to_file('BMP_OUT_DIR', 'test_03.png', readyImg.getContent());
  
end;
/
Github repository oracle_scriptlets, path: /bmp/test/test_03_png.sql

calendar - body.plsql

create or replace package body calendar as

  function EasterSunday(yr in number) return date /*{*/
  is
    a        number;
    b        number;
    c        number;
    d        number;
    e        number;
    m        number;
    n        number;
    day_     number;
    month_   number;

  begin

    if yr < 1583 or yr > 2299 then
       return null;
    end if;

    if    yr < 1700 then m := 22; n :=  2;
    elsif yr < 1800 then m := 23; n :=  3;
    elsif yr < 1900 then m := 23; n :=  4;
    elsif yr < 2100 then m := 24; n :=  5;
    elsif yr < 2200 then m := 24; n :=  6;
    else                 m := 25; n :=  0;
    end if;

    a := mod (yr,19);
    b := mod (yr, 4);
    c := mod (yr, 7);
    d := mod (19*a + m, 30);
    e := mod (2*b + 4*c + 6*d + n,7);

    day_   := 22 + d + e;
    month_ := 3;

    if day_ > 31 then
       day_  := day_-31;
       month_:= month_+1;
    end if;

    if day_ = 26 and  month_ = 4 then
       day_ := 19;
    end if;

    if day_ = 25 and month_ = 4 and d = 28 and e = 6 and a > 10 then
       day_:=18;
    end if;

   return to_date(
          to_char(day_,    '00') || '.' ||
          to_char(month_,  '00') || '.' ||
          to_char(yr,   '0000'),
         'DD.MM.YYYY'
   );

  end EasterSunday;/*}*/

  function CarnivalMonday      (yr in number) return date is begin return EasterSunday(yr) -48; end;
  function MardiGras           (yr in number) return date is begin return EasterSunday(yr) -47; end;
  function AshWednesday        (yr in number) return date is begin return EasterSunday(yr) -46; end;
  function PalmSunday          (yr in number) return date is begin return EasterSunday(yr) - 7; end;
  function EasterFriday        (yr in number) return date is begin return EasterSunday(yr) - 2; end;
  function EasterSaturday      (yr in number) return date is begin return EasterSunday(yr) - 1; end;
  function EasterMonday        (yr in number) return date is begin return EasterSunday(yr) + 1; end;
  function AscensionOfChrist   (yr in number) return date is begin return EasterSunday(yr) +39; end;
  function Whitsunday          (yr in number) return date is begin return EasterSunday(yr) +49; end;
  function Whitmonday          (yr in number) return date is begin return EasterSunday(yr) +50; end;
  function FeastOfCorpusChristi(yr in number) return date is begin return EasterSunday(yr) +60; end;

end;
/
Github repository oracle_scriptlets, path: /calendar/body.plsql

calendar - spec.plsql

create or replace package calendar as

  function EasterSunday           (yr in number) return date;
  function CarnivalMonday         (yr in number) return date;
  function MardiGras              (yr in number) return date;
  function AshWednesday           (yr in number) return date;
  function PalmSunday             (yr in number) return date;
  function EasterFriday           (yr in number) return date;
  function EasterSaturday         (yr in number) return date;
  function EasterMonday           (yr in number) return date;
  function AscensionOfChrist      (yr in number) return date;
  function Whitsunday             (yr in number) return date;
  function Whitmonday             (yr in number) return date;
  function FeastofCorpusChristi   (yr in number) return date;

end;
/
Github repository oracle_scriptlets, path: /calendar/spec.plsql

call_stack - body.plsql

create or replace package body call_stack as

  function who_am_i(p_lvl in number := 0) return who_am_i_r is -- {
  -- return the full ORACLE name of your object including schema and package names -- {
  -- --
  -- call_stack.who_am_i(0) - returns the name of your object
  -- call_stack.who_am_i(1) - returns the name of calling object
  -- call_stack.who_am_i(2) - returns the name of object, who called calling object
  -- -------------------------------------------------------------------------------------------------
  -- Copyrigth GARBUYA 2010

    v_stack           varchar2(2048) := upper(dbms_utility.format_call_stack);
    v_pkg_name        varchar2(  32);
    v_idx             number := 0;
    v_pos1            number := 0;
    v_line            varchar2(200);

    ret               who_am_i_r;
    type_and_name     source_code.type_and_name;


    function cut_a_line(p_callstack in out varchar2) return varchar2 is -- {
      line   varchar2(200);
      pos_nl number;
    begin

      pos_nl := instr (p_callstack, chr(10));

      if pos_nl = 0 then
         line := p_callstack;
         p_callstack := '';
         return line;
      end if;

      line        := substr(p_callstack, 1, pos_nl - 1);
      p_callstack := substr(p_callstack,    pos_nl + 1);

      return line;

    end cut_a_line; -- }
    
  -- }
  begin

  

    v_line := cut_a_line(v_stack);
    if v_line != '----- PL/SQL CALL STACK -----' then raise_application_error(-20800, 'Wrong assumption, v_line: ' || v_line || '<'); end if;

    v_line := cut_a_line(v_stack);
    if v_line != '  OBJECT      LINE  OBJECT'    then raise_application_error(-20800, 'Wrong assumption, v_line: ' || v_line || '<'); end if;

    v_line := cut_a_line(v_stack);
    if v_line != '  HANDLE    NUMBER  NAME'      then raise_application_error(-20800, 'Wrong assumption, v_line: ' || v_line || '<'); end if;

 -- Remove myself
    v_line := cut_a_line(v_stack);
    if not regexp_like(v_line, '^[0-9A-FX]+        12  PACKAGE BODY .*\.CALL_STACK$') then raise_application_error(-20800, 'Wrong assumption, v_line: ' || v_line || '<'); end if;
  
    for v_pos2 in 0 .. p_lvl loop  -- advance to the input level
        v_line := cut_a_line(v_stack);
    end loop;


    ret.line     := regexp_replace(v_line, '^[0-9A-FX]+ +(\d+).*'              , '\1');
    ret.type_    := regexp_replace(v_line, '^[0-9A-FX]+ +\d+ +(.*) +([^ ]+)$'  , '\1');
    ret.owner    := regexp_replace(v_line, '^[0-9A-FX]+ +\d+ +.* +([^.]+).*$'  , '\1');
    ret.pkg_name := regexp_replace(v_line, '^[0-9A-FX]+ +\d+ +.* +[^.]+\.(.*)$', '\1');


$if false $then
    dbms_output.put_line('ret.line     = ' || ret.line     || '<');
    dbms_output.put_line('ret.type_    = ' || ret.type_    || '<');
    dbms_output.put_line('ret.owner    = ' || ret.owner    || '<');
    dbms_output.put_line('ret.pkg_name = ' || ret.pkg_name || '<');
$end

--
--  v_pos1    := instr (v_stack, ' ', v_pos1 + 2);  -- find end of object type

--  ret.type_ := substr(v_stack, 1  , v_pos1 - 1);

--  v_stack   := trim(substr(v_stack, v_pos1 + 1));  -- get package name
--  v_pos1    := instr(v_stack, '.');

--  ret.owner := substr(v_stack, 1, v_pos1 - 1);
--  ret.pkg_name := substr(v_stack, v_pos1 + 1);

    if ret.type_ not like '%BODY' then
       ret.name_    := ret.pkg_name;
       ret.pkg_name := null;
    else

      type_and_name := source_code.name_from_line(ret.pkg_name, ret.type_, ret.line, ret.owner);

      ret.type_ := type_and_name.type_;
      ret.name_ := type_and_name.name_;

    end if;

$if false $then
    dbms_output.put_line('ret.type_    = ' || ret.type_    || '<');
    dbms_output.put_line('ret.name_    = ' || ret.name_    || '<');
$end

    return ret;
  
  
  end who_am_i; -- }

end call_stack;
/
Github repository oracle_scriptlets, path: /call_stack/body.plsql

call_stack - spec.plsql

create or replace package call_stack as

    type who_am_i_r is record (

      type_    varchar2( 32),
      name_    varchar2(255), -- 2016-11-22 Because of »0X459AF82320        40  ANONYMOUS BLOCK«
      pkg_name varchar2(255), -- 2016-11-22
      line     number,
      owner    varchar2( 30)

    );

    function who_am_i(p_lvl in number := 0) return who_am_i_r;

end call_stack;
/
show errors
Github repository oracle_scriptlets, path: /call_stack/spec.plsql

call_stack - test.plsql

create or replace package test_who_am_i as -- {

   procedure g;
   procedure h;
   procedure i;

end test_who_am_i; -- }
/

create or replace procedure    test_who_am_i_proc as -- {
     w call_stack.who_am_i_r;
begin

     w := call_stack.who_am_i(0);

     if w.pkg_name  is not null             then raise_application_error(-20800, 'pkg_name: ' || w.pkg_name); end if;
     if w.name_     != 'TEST_WHO_AM_I_PROC' then raise_application_error(-20800, 'name: '     || w.name_   ); end if;
     if w.type_     != 'PROCEDURE'          then raise_application_error(-20800, 'type'                    ); end if;
     if w.line      !=  5                   then raise_application_error(-20800, 'line: '     || w.line    ); end if;
     if w.owner     != user                 then raise_application_error(-20800, 'owner'                   ); end if;


end test_who_am_i_proc; -- }
/

create or replace package body test_who_am_i as -- {

   procedure i is -- {
   begin
     h();
   end i; -- }

   procedure h is -- {
     w call_stack.who_am_i_r;
   begin

     w := call_stack.who_am_i(0);

     if nvl(w.pkg_name, '?')  != 'TEST_WHO_AM_I' then raise_application_error(-20800, 'pkg_name: ' || w.pkg_name); end if;
     if nvl(w.name_   , '?')  != 'H'             then raise_application_error(-20800, 'name: '     || w.name_   ); end if;
     if nvl(w.type_   , '?')  != 'PROCEDURE'     then raise_application_error(-20800, 'type: '     || w.type_   ); end if;
     if nvl(w.line    ,  0 )  !=  12             then raise_application_error(-20800, 'line: '     || w.line    ); end if;
     if nvl(w.owner   , '?')  != user            then raise_application_error(-20800, 'owner: '    || w.owner   ); end if;

     w := call_stack.who_am_i(1);

     if nvl(w.pkg_name, '?')  != 'TEST_WHO_AM_I' then raise_application_error(-20800, 'pkg_name: ' || w.pkg_name); end if;
     if nvl(w.name_   , '?')  != 'I'             then raise_application_error(-20800, 'name: ' || w.name_); end if;
     if nvl(w.type_   , '?')  != 'PROCEDURE'     then raise_application_error(-20800, 'type'); end if;
     if nvl(w.line    ,  0 )  !=  5              then raise_application_error(-20800, 'line: ' || w.line); end if;
     if nvl(w.owner   , '?')  != user            then raise_application_error(-20800, 'owner'); end if;

     w := call_stack.who_am_i(2);

     if nvl(w.pkg_name, '?')  != 'TEST_WHO_AM_I' then raise_application_error(-20800, 'pkg_name: ' || w.pkg_name); end if;
     if nvl(w.name_   , '?')  != 'G'             then raise_application_error(-20800, 'name: ' || w.name_); end if;
     if nvl(w.type_   , '?')  != 'PROCEDURE'     then raise_application_error(-20800, 'type'); end if;
     if nvl(w.line    ,  0 )  !=  43             then raise_application_error(-20800, 'line: ' || w.line); end if;
     if nvl(w.owner   , '?')  != user            then raise_application_error(-20800, 'owner'); end if;

     test_who_am_i_proc;
  
   end h; -- }

   procedure g is -- {
   begin

     i();

   end g; -- }
  
end test_who_am_i; -- }
/

exec test_who_am_i.g;

select text  from user_source where name = 'TEST_WHO_AM_I' and type = 'PACKAGE BODY' and line in (12, 5, 43);
Github repository oracle_scriptlets, path: /call_stack/test.plsql

ch_coordinates_conversion - ch_coordinates_conversion.pkb

create or replace package body ch_coordinates_conversion as

-- The MIT License (MIT) -- {
-- 
-- Copyright (c) 2014 Federal Office of Topography swisstopo, Wabern, CH and Joerg Schmidt, Rola AG, Zürich, CH
-- 
-- Permission is hereby granted, free of charge, to any person obtaining a copy
--  of this software and associated documentation files (the "Software"), to deal
--  in the Software without restriction, including without limitation the rights
--  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
--  copies of the Software, and to permit persons to whom the Software is
--  furnished to do so, subject to the following conditions:
-- 
-- The above copyright notice and this permission notice shall be included in
--  all copies or substantial portions of the Software.
-- 
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
--  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
--   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
--  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
--   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
--  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
--   THE SOFTWARE.
--

-- Source: http://www.swisstopo.admin.ch/internet/swisstopo/en/home/topics/survey/sys/refsys/projections.html (see PDFs under "Documentation")
--
-- Translated from python to oracle by Joerg Schmidt (Rola AG)
--
-- Please validate your results with NAVREF on-line service: http://www.swisstopo.admin.ch/internet/swisstopo/en/home/apps/calc/navref.html (difference ~ 1-2m) -- }

--
-- TODO Do the lat and lng really need to be in out parameters?
--

  function WGStoCHy(lat in out float, lng in out float) return float -- {
  -- Convert WGS lat/long (° dec) to CH y
  is
    lat_aux float;
    lng_aux float;
    y float;
   begin

    lat := DECtoSEX(lat);
    lng := DECtoSEX(lng);

    lat_aux := (lat - 169028.66)/10000;
    lng_aux := (lng - 26782.5  )/10000;


    y := (600072.37
         + 211455.93 * lng_aux
         - 10938.51 * lng_aux * lat_aux
         - 0.36 * lng_aux * power( lat_aux, 2 )
         - 44.54 * power( lng_aux, 3 ) );
    return y;

  end WGStoCHy; -- }

  function WGStoCHx(lat in out float, lng in out float) return float -- {
  -- Convert WGS lat/long (° dec) to CH x
  is
    lat_aux float;
    lng_aux float;
    x float;
   begin

    lat := DECtoSEX(lat);
    lng := DECtoSEX(lng);

    lat_aux := (lat - 169028.66)/10000;
    lng_aux := (lng - 26782.5  )/10000;

    x := (200147.07
         + 308807.95 * lat_aux
         + 3745.25 * power(lng_aux, 2 )
         + 76.63 * power( lat_aux, 2 )
         - 194.56 * power( lng_aux, 2) * lat_aux
         + 119.79 * power( lat_aux, 3) );

    return x;

  end WGStoCHx; -- }

  function CHtoWGSlat(y float, x float) return float -- {
  -- Convert CH y/x to WGS lat
  is
    y_aux float;
    x_aux float;
    lat   float;

  begin
    y_aux := (y - 600000)/1000000;
    x_aux := (x - 200000)/1000000;

    lat := (16.9023892
           + 3.238272 * x_aux
           - 0.270978 * power( y_aux, 2 )
           - 0.002528 * power( x_aux, 2 )
           - 0.0447 * power( y_aux, 2 ) * x_aux
           - 0.0140 * power( x_aux, 3 ) );

    lat := lat * 100/36;
    return lat;

  end CHtoWGSlat; -- }

  function CHtoWGSlng(y float, x float) return float -- {
  -- Convert CH y/x to WGS long
  is
    y_aux float;
    x_aux float;
    lng   float;
  begin

    y_aux := (y - 600000)/1000000;
    x_aux := (x - 200000)/1000000;

    lng := (2.6779094
          + 4.728982 * y_aux
          + 0.791484 * y_aux * x_aux
          + 0.1306   * y_aux * power( x_aux, 2 )
          - 0.0436   *         power( y_aux, 3 )
       );

    --  Unit 10000" to 1 " and converts seconds to degrees (dec)
    lng := lng * 100/36;
    return lng;

    end CHtoWGSlng; -- }

  function DECtoSEX(angle float) return float -- {
   -- Convert decimal angle to sexagesimal seconds
   is
     deg float;
     mnt float;
     sec float;
  begin

    deg := angle;
    mnt := (angle-deg)*60;
    sec := (((angle-deg)*60)-mnt)*60;


    return sec + mnt * 60 + deg * 3600;
  end DECtoSEX; -- }

end ch_coordinates_conversion;
/
Github repository oracle_scriptlets, path: /ch_coordinates_conversion/ch_coordinates_conversion.pkb

ch_coordinates_conversion - ch_coordinates_conversion.pks

create or replace package ch_coordinates_conversion as

-- The MIT License (MIT) -- {
-- 
-- Copyright (c) 2014 Federal Office of Topography swisstopo, Wabern, CH and Joerg Schmidt, Rola AG, Zürich, CH
-- 
-- Permission is hereby granted, free of charge, to any person obtaining a copy
--  of this software and associated documentation files (the "Software"), to deal
--  in the Software without restriction, including without limitation the rights
--  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
--  copies of the Software, and to permit persons to whom the Software is
--  furnished to do so, subject to the following conditions:
-- 
-- The above copyright notice and this permission notice shall be included in
--  all copies or substantial portions of the Software.
-- 
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
--  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
--   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
--  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
--   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
--  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
--   THE SOFTWARE.
--

-- Source: http://www.swisstopo.admin.ch/internet/swisstopo/en/home/topics/survey/sys/refsys/projections.html (see PDFs under "Documentation")
--
-- Translated from python to oracle by Joerg Schmidt (Rola AG)
--
-- Please validate your results with NAVREF on-line service: http://www.swisstopo.admin.ch/internet/swisstopo/en/home/apps/calc/navref.html (difference ~ 1-2m) -- }

   function WGStoCHy(lat in out float, lng in out float) return float;
   function WGStoCHx(lat in out float, lng in out float) return float;
   function CHtoWGSlat(y float, x float) return float;
   function CHtoWGSlng(y float, x float) return float;
   function DECtoSEX(angle float) return float;

-- Convert WGS lat/long (° dec) to CH y

end ch_coordinates_conversion;
/
Github repository oracle_scriptlets, path: /ch_coordinates_conversion/ch_coordinates_conversion.pks

create_db_from_cmd.exe - build_data_dictionary.sql

shutdown
startup

-- @ runs a script
-- ? points to %ORACLE_HOME%

@?/rdbms/admin/catalog.sql
@?/rdbms/admin/catproc.sql

exit
Github repository oracle_scriptlets, path: /create_db_from_cmd.exe/build_data_dictionary.sql

create_db_from_cmd.exe - go.bat

@rem
@rem        This script should create an Oracle Database.
@rem        The values specified are quite minimal, on purpose.
@rem        The Idea is to have a quick database at hand, when needed.
@rem        The created database won't be good enough for a production
@rem        database.
@rem
@rem
@rem        Most probably, this script should be run as administrator
@rem       (cf comment below regarding DIM-00014)
@rem

@     SET   ORACLE_HOME=c:\Oracle\product\11.2.0\dbhome_1
@     SET   ORACLE_SID=ORA_MANUALLY_CREATED
@     SET   DB_NAME=DBMANUAL


@     SET   SYSDBA_PASSWORD=IamSysdba
@     SET   SYSTEM_PASSWORD=IamSystem

@rem  SET   Used in 'create database' statement:
@     SET   CHARACTER_SET=AL32UTF8
@     SET   NATIONAL_CHARACTER_SET=AL16UTF16

@     SET   DB_BLOCK_SIZE=8192

@rem  SET   Where will 'create database' statement go?
@     SET   TEMP_DIR=c:\temp

@rem        Make sure, correct oradim, sqlplus etc will be invoked.
@rem        The variable might already have been set by
@rem        Oracle's installer.
@rem  SET   PATH=%ORACLE_HOME%\bin;%PATH%


@rem 'file root directory'
@rem  ----------------------------------------------------
@rem  
@rem        As we're creating a simple database, we
@rem        specify one single root for the files to
@rem        be created by the database:

@set        DB_FILE_ROOT=c:\tools\Oracle\%DB_NAME%_Files
@rmdir      /q /s %DB_FILE_ROOT% > nul
@mkdir      %DB_FILE_ROOT%


@rem 'Control Files'
@rem  ----------------------------------------------------
@rem  
@rem        We need to decide for control files.
@rem  
@rem        The value of this environement variable will be
@rem        used when the Initialization Parameter Files are
@rem        created.
@rem        Currently, only one control file is used.
@rem  
@     SET   CONTROL_FILES=(%DB_FILE_ROOT%\control_file_01.ctl)


@rem  The 'Initialization Parameter File'
@rem  ----------------------------------------------------

@rem        On Windows, the default directory for the
@rem        Initialization Parameter File is: ORACLE_HOME\database
@rem        The following environment variable will
@rem        point to this location:

@     SET   PFILE_PATH=%ORACLE_HOME%\database
@rem  
@rem        Note: on Unix, the default is ORACLE_HOME/dbs
@rem        ----------------------------------------------------

@rem        On Windows, the default filename for the
@rem        Initialization Parameter File is: initORACLE_SID.ora
@rem        The following environment variable will
@rem        point to this location:

@set        PFILE_NAME=init%ORACLE_SID%.ora


@rem        Full Name (path and name) of Initialization Parameter File:

@     SET   PFILE=%PFILE_PATH%\%PFILE_NAME%


@rem        oh, oh, dangerous: %PFILE_PATH% might contain
@rem        other important pfiles   
@     REM   rmdir /s %PFILE_PATH% 2> nul
@     REM   mkdir %PFILE_PATH%

@rem        Creating the 'Initialization Parameter File'
@rem        ----------------------------------------------------


@echo       DB_NAME=%DB_NAME%>               %PFILE%
@echo       DB_BLOCK_SIZE=%DB_BLOCK_SIZE%>>  %PFILE%
@echo       CONTROL_FILES=%CONTROL_FILES%>>  %PFILE%
@echo       UNDO_TABLESPACE=UNDO_TS>>        %PFILE%
@rem
@rem  TODO: For the following parameter, see http://dba.stackexchange.com/questions/8434
@rem
@rem        local_listener='(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))' >> %PFILE%



@rem
@rem  Create the Oracle Instance.
@rem  ----------------------------------------------------
@rem       
@rem        In Windows, the instance is implemented
@rem        as a service.

@           oradim -NEW -SID %ORACLE_SID% -STARTMODE MANUAL

@rem        Note:
@rem        If the command throws a 'DIM-00014' error message, the
@rem        command should be run as administrator


@rem        ----------------------------------------------------
@rem        The 'Password File'
@rem
@rem        The Password File is needed so as to be able
@rem        to connect "as sysdba" (see later.)

@rem        On Windows, the default directory for the
@rem        Password File is: ORACLE_HOME\database (as is for the 
@rem        Initialization Parameter File).
@rem        The following environment variable will
@rem        point to this location:

@     SET   PWD_PATH=%ORACLE_HOME%\database

@rem        Note: on Unix, the default is ORACLE_HOME/dbs
@rem        ----------------------------------------------------

@rem       On Windows, the default filename for the
@rem       Password File is: pwdORACLE_SID.ora
@rem      (ORACLE_SID should have been set in 001.sid.bat)
@rem       The following environment variable will
@rem       point to this location:

@     SET  PWD_NAME=pwd%ORACLE_SID%.ora

@rem       -----------------------------------
@rem       Full Name (path and name) of Password File
@rem
@     SET  PWDFILE=%PWD_PATH%\%PWD_NAME%

@     DEL  %PWDFILE% 2> nul

@rem       Create password file using 'orapwd':
@          orapwd file=%PWDFILE% password=%SYSDBA_PASSWORD%


@rem       Create the 'SQL Script' that will create the database
@rem       ----------------------------------------------------


@set       SCRIPT=%TEMP_DIR%\create_db_script.sql

@echo   startup nomount > %SCRIPT%
@REM    ---------------------------------------------------
@echo   CREATE DATABASE %DB_NAME% >> %SCRIPT%
@echo      USER SYS IDENTIFIED BY %SYSDBA_PASSWORD% >> %SCRIPT%
@echo      USER SYSTEM IDENTIFIED BY %SYSTEM_PASSWORD% >> %SCRIPT%
@echo      LOGFILE GROUP 1 ('%DB_FILE_ROOT%\redo01a.log','%DB_FILE_ROOT%\redo01b.log') SIZE 100M BLOCKSIZE 512, >> %SCRIPT%
@echo              GROUP 2 ('%DB_FILE_ROOT%\redo02a.log','%DB_FILE_ROOT%\redo02b.log') SIZE 100M BLOCKSIZE 512 >> %SCRIPT%

@rem       currently, only two log file group. At least two are required to prevent
@rem          ORA-01518: CREATE DATABASE must specify more than one log file
@rem       Make sure to have the commas right when uncommenting the following line:
@rem
@rem @echo              GROUP 3 ('%DB_FILE_ROOT%\redo03a.log','%DB_FILE_ROOT%\redo03b.log') SIZE 100M BLOCKSIZE 512  >> %SCRIPT%

@echo      -- MAXLOGFILES 5 >> %SCRIPT%
@echo      MAXLOGMEMBERS 5 >> %SCRIPT%
@echo      MAXLOGHISTORY 1 >> %SCRIPT%
@echo      MAXDATAFILES 100 >> %SCRIPT%
@echo      CHARACTER SET %CHARACTER_SET%  >> %SCRIPT%
@echo      NATIONAL CHARACTER SET %NATIONAL_CHARACTER_SET%  >> %SCRIPT%
@REM       ---------------------------------------------------
@echo      EXTENT MANAGEMENT LOCAL >> %SCRIPT%
@echo      DATAFILE '%DB_FILE_ROOT%\system01.dbf' SIZE 325M REUSE >> %SCRIPT%
@echo      SYSAUX DATAFILE '%DB_FILE_ROOT%\sysaux01.dbf' SIZE 325M REUSE >> %SCRIPT%
@REM       ---------------------------------------------------
@echo      DEFAULT TABLESPACE users >> %SCRIPT%
@echo         DATAFILE '%DB_FILE_ROOT%\users01.dbf' >> %SCRIPT%
@echo         SIZE 500M REUSE AUTOEXTEND ON MAXSIZE UNLIMITED >> %SCRIPT%
@REM       ---------------------------------------------------
@echo      DEFAULT TEMPORARY TABLESPACE temp_ts >> %SCRIPT%
@echo         TEMPFILE '%DB_FILE_ROOT%\temp01.dbf' >> %SCRIPT%
@echo         SIZE 20M REUSE >> %SCRIPT%
@REM       ---------------------------------------------------
@REM       -- TODO: NOte UNDO_TS also specified in Initialization Paramter File!
@echo      UNDO TABLESPACE undo_ts >> %SCRIPT%
@echo         DATAFILE '%DB_FILE_ROOT%\undo01.dbf' >> %SCRIPT%
@echo         SIZE 200M REUSE AUTOEXTEND ON MAXSIZE UNLIMITED; >> %SCRIPT%
@REM    ---------------------------------------------------
@echo   exit >> %SCRIPT%


@       sqlplus sys/%SYSDBA_PASSWORD% as sysdba @%SCRIPT%

@       sqlplus sys/%SYSDBA_PASSWORD% as sysdba @build_data_dictionary.sql

@       sqlplus system/%SYSTEM_PASSWORD% @install_product_user_profile.sql

@rem    -------------------------------------------
@rem    Create listener service

@       sc create OracleOraDb11g_home1TNSListener binPath= %ORACLE_HOME%\bin\tnslsnr.exe start= demand

@rem    The listener service can be deleted with
@rem        sc delete OracleOraDb11g_home1TNSListener
@rem
@rem    The service can be started with
@rem        net start OracleOraDb11g_home1TNSListener
@rem    and stopped with
@rem        net stop OracleOraDb11g_home1TNSListener

@rem    --------------------------------------------
@rem    Create tnsadmin.ora file

@echo %DB_NAME%= >> %ORACLE_HOME%\NETWORK\ADMIN\tnsnames.ora
@echo    (DESCRIPTION= >> %ORACLE_HOME%\NETWORK\ADMIN\tnsnames.ora
@echo      (ADDRESS= >> %ORACLE_HOME%\NETWORK\ADMIN\tnsnames.ora
@echo         (PROTOCOL=tcp) >> %ORACLE_HOME%\NETWORK\ADMIN\tnsnames.ora
@echo         (HOST=localhost) >> %ORACLE_HOME%\NETWORK\ADMIN\tnsnames.ora
@echo         (PORT=1521) >> %ORACLE_HOME%\NETWORK\ADMIN\tnsnames.ora
@echo      ) >> %ORACLE_HOME%\NETWORK\ADMIN\tnsnames.ora
@echo      (CONNECT_DATA= >> %ORACLE_HOME%\NETWORK\ADMIN\tnsnames.ora
@echo         (SID=%ORACLE_SID%) >> %ORACLE_HOME%\NETWORK\ADMIN\tnsnames.ora
@echo         (GLOBAL_NAME=%DB_NAME%) >> %ORACLE_HOME%\NETWORK\ADMIN\tnsnames.ora
@echo      ) >> %ORACLE_HOME%\NETWORK\ADMIN\tnsnames.ora
@echo   ) >> %ORACLE_HOME%\NETWORK\ADMIN\tnsnames.ora

@rem    --------------------------------------------
@rem    Create listener.ora file

@echo   listener=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521)) >> %ORACLE_HOME%\NETWORK\ADMIN\listener.ora
Github repository oracle_scriptlets, path: /create_db_from_cmd.exe/go.bat

create_db_from_cmd.exe - install_product_user_profile.sql

-- Must (should?) be run as system.
--
-- Installs the SQL*Plus PRODUCT_USER_PROFILE tables. These
-- tables allow SQL*Plus to disable commands per user. The tables
-- are used only by SQL*Plus and do not affect other client tools
-- that access the database.  Refer to the SQL*Plus manual for table
-- usage information.
-- This script should be run on every database that SQL*Plus connects
-- to, even if the tables are not used to restrict commands.

@?/sqlplus/admin/pupbld.sql
exit
Github repository oracle_scriptlets, path: /create_db_from_cmd.exe/install_product_user_profile.sql

db_tools - db_tools.spb

create or replace package body &tq84_prefix.db_tools as

    procedure search_views(p_regexp varchar2, p_owner varchar2 := null) is -- {
    
      view_text_clob clob;
    
      function extract_view_text(owner varchar2, name varchar2) return clob is -- {
          ret  clob;
          stmt integer;
          rc   number;
    
          long_val long;
          long_len integer;
          buf_len  integer := 32760;
          pos      number  :=     0;
    
      begin
    
          stmt := dbms_sql.open_cursor;
    
          dbms_sql.parse(stmt, 'select text from all_views where owner = :owner and view_name = :name', dbms_sql.native);
    
          dbms_sql.bind_variable(stmt, 'owner', owner);
          dbms_sql.bind_variable(stmt, 'name' , name );
    
          dbms_sql.define_column_long(stmt, 1);
    
          rc := dbms_sql.execute(stmt);
          if rc != 0 then
             raise_application_error(-20800, 'rc != 0');
          end if;
    
          rc := dbms_sql.fetch_rows(stmt);
          if rc != 1 then
             raise_application_error(-20800, 'rc != 1');
          end if;
    
    
          dbms_lob.createtemporary(ret, false, dbms_lob.call);
          
          loop
    
            dbms_sql.column_value_long(stmt, 1 /* col position */, buf_len, pos, long_val, long_len);
            exit when long_len = 0;
    
            dbms_lob.append(ret, long_val);
            pos := pos + long_len;
    
          end loop;
    
          dbms_sql.close_cursor(stmt);
    
          return ret;
    
      end extract_view_text; -- }
    
    begin
      
      for vw in (select owner, view_name from all_views where owner = nvl(p_owner, owner)) loop
          view_text_clob := extract_view_text(vw.owner, vw.view_name);
    
          if regexp_like(view_text_clob, p_regexp) then
             dbms_output.put_line('matches:        ' || vw.owner || '.' || vw.view_name);
    --    else
    --       dbms_output.put_line('does not match: ' || vw.owner || '.' || vw.view_name);
          end if;
    
      end loop;
      
    end search_views; -- }

end &tq84_prefix.db_tools;
/
Github repository oracle_scriptlets, path: /db_tools/db_tools.spb

db_tools - db_tools.sps

create or replace package &tq84_prefix.db_tools as

    procedure search_views(p_regexp varchar2, p_owner varchar2 := null;

end &tq84_prefix.db_tools;
/
Github repository oracle_scriptlets, path: /db_tools/db_tools.sps

db_tools - test-search_views.sql

create or replace view tq84_test_view as
  select
    'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' a,
    'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' b,
    'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc' c,
    'dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd' d,
    'eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' e,
    'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' f,
    'gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg' g,
    'hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh' h,
    'iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii' i,
    'jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj' j,
    'kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk' k,
    'llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll' l,
    'mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm' m,
    'nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn' n,
    'oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' o,
    'pppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp' p,
    'qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq' q,
    'rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr' r,
    'ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss' s,
    'tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt' t,
    'uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu' u,
    'vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv' v,
    'wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww' w,
    'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' x,
    'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy' y,
    'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz' z,
    'last_column'                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      lst_col
from
  dual;


select
  text_length
from
  user_views
where
  lower(view_name) = 'tq84_test_view';


--
--  Expected output:
--     matches:   ..... TQ84_TEST_VIEW
--
exec &tq84_prefix.db_tools.search_views('l.t.*col*', user);

drop view tq84_test_view;
Github repository oracle_scriptlets, path: /db_tools/test-search_views.sql

debugger - body.plsql

create or replace package body debugger as

  procedure abort is/*{*/
    runinfo dbms_debug.runtime_info;
    ret     binary_integer;
  begin
    continue_(dbms_debug.abort_execution);
  end abort;/*}*/

  procedure backtrace is/*{*/
    pkgs dbms_debug.backtrace_table;
    i    number;
  begin
    dbms_debug.print_backtrace(pkgs);
    i := pkgs.first();
    dbms_output.put_line('backtrace');
    while i is not null loop
      dbms_output.put_line('  ' || i || ': ' || pkgs(i).name || ' (' || pkgs(i).line# ||')');
      i := pkgs.next(i);
    end loop;
   exception
    when others then
     dbms_output.put_line('  backtrace exception: ' || sqlcode);
     dbms_output.put_line('                       ' || sqlerrm(sqlcode));
  end backtrace;/*}*/
  
  procedure breakpoints is/*{*/
    brkpts dbms_debug.breakpoint_table;
    i      number;
    v_line number;
  begin
    dbms_debug.show_breakpoints(brkpts); 
    i := brkpts.first();
    dbms_output.put_line('');
    while i is not null loop
      if v_line is not null then
      dbms_output.put( to_char(v_line , '99999'));
      null;
      else
      dbms_output.put('      ');
      end if;

      dbms_output.put( ' ');

      dbms_output.put(to_char(i,'999') || ': ');
      dbms_output.put(rpad(coalesce(brkpts(i).name, ' '), 31));

      dbms_output.put(rpad(coalesce(brkpts(i).owner,' '), 31));

      v_line:=brkpts(i).line#;


      dbms_output.put( ' ');
      dbms_output.put(libunittype_as_string(brkpts(i).libunittype));
      dbms_output.put( ' ');
      dbms_output.put(bp_status_as_string  (brkpts(i).status     ));
     
      dbms_output.put_line('');
      i := brkpts.next(i);
    end loop;
  end breakpoints;/*}*/

  function libunittype_as_string(lut binary_integer) /*{*/
  /* 

      dbms_debug.continue can be called with the following breakflags:
       o  break_next_line       ( Break at next source line (step over calls) ) 
       o  break_any_call        ( Break at next source line (step into calls) )
       o  break_any_return    
       o  break_return        
       o  break_exception     
       o  break_handler       
       o  abort_execution     

       As the user of debugger might want to use continue with variying breakflags, continue_ (with the
       underscore) is the generic wrapper. (I hope this makes sense)

  */
  return varchar2 is
  begin

    if lut = dbms_debug.libunitType_cursor         then return 'Cursor'; end if;
    if lut = dbms_debug.libunitType_procedure      then return 'Proc'  ; end if;
    if lut = dbms_debug.libunitType_function       then return 'Func'  ; end if;
    if lut = dbms_debug.libunitType_function       then return 'Func'  ; end if;
    if lut = dbms_debug.libunitType_package        then return 'Pkg'   ; end if;
    if lut = dbms_debug.libunitType_package_body   then return 'Pkg Bd'; end if;
    if lut = dbms_debug.libunitType_trigger        then return 'Trig'  ; end if;
    if lut = dbms_debug.libunitType_unknown        then return 'Unk'   ; end if;

    return '???';

  end libunittype_as_string;/*}*/

  function  bp_status_as_string(bps binary_integer) return varchar2 is/*{*/
  -- "User friendly" name for breakpoint_status_*
  begin
   
    if bps = dbms_debug.breakpoint_status_unused   then return 'unused'  ; end if;
    if bps = dbms_debug.breakpoint_status_active   then return 'active'  ; end if;
    if bps = dbms_debug.breakpoint_status_disabled then return 'disabled'; end if;
    if bps = dbms_debug.breakpoint_status_remote   then return 'remote'  ; end if;
    
    return '???';

  end bp_status_as_string;/*}*/

  procedure continue_(break_flags in number) is/*{*/
    ret     binary_integer;
    v_err   varchar2(100);
  begin
    dbms_output.put_line('');

    ret := dbms_debug.continue(
      cur_line_,
        break_flags,
       0             +
       dbms_debug.info_getlineinfo   +
       dbms_debug.info_getbreakpoint +
       dbms_debug.info_getstackdepth +
       dbms_debug.info_getoerinfo    +
       0);
  
     if ret = dbms_debug.success then
       dbms_output.put_line('  reason for break: ' ||   str_for_reason_in_runtime_info(cur_line_.reason));
       if cur_line_.reason  = dbms_debug.reason_knl_exit then
         return;
       end if;
       if cur_line_.reason  = dbms_debug.reason_exit then
         return;
       end if;
       --print_runtime_info_with_source(cur_line_,cont_lines_before_, cont_lines_after_,cont_lines_width_);
       print_source(cur_line_, cont_lines_before_, cont_lines_after_);
     elsif ret = dbms_debug.error_timeout then 
       dbms_output.put_line('  continue: error_timeout');
     elsif ret = dbms_debug.error_communication then
       dbms_output.put_line('  continue: error_communication');
     else
       v_err := general_error(ret);
       dbms_output.put_line('  continue: general error' || v_err);
     end if;
  end continue_;/*}*/

  procedure detach is/*{*/
  begin
    dbms_debug.detach_session;
  end detach;/*}*/

  procedure continue is/*{*/
  /*
      continue (calling continue_ with break_flags = 0 ) will run until
      the program hits a breakpoint
  */
  begin
      continue_(0);
  end continue;/*}*/

  procedure delete_bp(breakpoint in binary_integer) is/*{*/
    ret binary_integer;
  begin
    ret := dbms_debug.delete_breakpoint(breakpoint);


    if    ret = dbms_debug.success                then dbms_output.put_line('  breakpoint deleted');
    elsif ret = dbms_debug.error_no_such_breakpt  then dbms_output.put_line('  No such breakpoint exists');
    elsif ret = dbms_debug.error_idle_breakpt     then dbms_output.put_line('  Cannot delete an unused breakpoint');
    elsif ret = dbms_debug.error_stale_breakpt    then dbms_output.put_line('  The program unit was redefined since the breakpoint was set');
    else                                               dbms_output.put_line('  Unknown error');
    end if;
  end delete_bp;/*}*/

  procedure print_var(name in varchar2) is/*{*/
    ret   binary_integer;
    val   varchar2(4000);
    frame number;
  begin

    frame := 0;

    ret := dbms_debug.get_value(
      name,
      frame,
      val,
      null);


    if    ret = dbms_debug.success              then dbms_output.put_line('  ' || name || ' = ' || val);
    elsif ret = dbms_debug.error_bogus_frame    then dbms_output.put_line('  print_var: frame does not exist');
    elsif ret = dbms_debug.error_no_debug_info  then dbms_output.put_line('  print_var: Entrypoint has no debug info');
    elsif ret = dbms_debug.error_no_such_object then dbms_output.put_line('  print_var: variable ' || name || ' does not exist in in frame ' || frame);
    elsif ret = dbms_debug.error_unknown_type   then dbms_output.put_line('  print_var: The type information in the debug information is illegible');
    elsif ret = dbms_debug.error_nullvalue      then dbms_output.put_line('  ' || name || ' = NULL');
    elsif ret = dbms_debug.error_indexed_table  then dbms_output.put_line('  print_var: The object is a table, but no index was provided.');
    else                                             dbms_output.put_line('  print_var: unknown error');
    end if;
 
  end print_var;/*}*/

  procedure start_debugger(debug_session_id in varchar2) is/*{*/
  /*

     This is the first call the debugging session must make. It, in turn, calls
     dbms_debug.attach_session.

     After attaching to the session, it waits for the first event (wait_until_running), which is interpreter starting.

  */
  begin
    dbms_debug.attach_session(debug_session_id);
    --cont_lines_before_ :=   5;
    --cont_lines_after_  :=   5;
    --cont_lines_width_  := 100;

    wait_until_running;
  end start_debugger;/*}*/

--function  start_debugee return varchar2 as/*{*/
--/* This is the first call the debugged session must make. 
--
--   The return value must be passed to the debugging session and used in start_debugger
--*/
--  debug_session_id varchar2(20); 
--begin
--  --select dbms_debug.initialize into debug_session_id from dual;
--  debug_session_id := dbms_debug.initialize;
--  dbms_debug.debug_on;
--  return debug_session_id;
--end start_debugee;/*}*/

  procedure print_proginfo(prginfo dbms_debug.program_info) as/*{*/
  begin
    dbms_output.put_line('  Namespace:  ' || str_for_namespace(prginfo.namespace));
    dbms_output.put_line('  Name:       ' || prginfo.name);
    dbms_output.put_line('  owner:      ' || prginfo.owner);
    dbms_output.put_line('  dblink:     ' || prginfo.dblink);
    dbms_output.put_line('  Line#:      ' || prginfo.Line#);
    dbms_output.put_line('  lib unit:   ' || prginfo.libunittype);
    dbms_output.put_line('  entrypoint: ' || prginfo.entrypointname);
  end print_proginfo;/*}*/

  procedure print_runtime_info(runinfo dbms_debug.runtime_info) as/*{*/
    --rsnt varchar2(40);
  begin
      --rsnt := str_for_reason_in_runtime_info(runinfo.reason);
      dbms_output.put_line('');
      dbms_output.put_line('Runtime Info');
      dbms_output.put_line('Prg Name:      ' || runinfo.program.name);
      dbms_output.put_line('Line:          ' || runinfo.line#);
      dbms_output.put_line('Terminated:    ' || runinfo.terminated);
      dbms_output.put_line('Breakpoint:    ' || runinfo.breakpoint);
      dbms_output.put_line('Stackdepth     ' || runinfo.stackdepth);
      dbms_output.put_line('Interpr depth: ' || runinfo.interpreterdepth);
      --dbms_output.put_line('Reason         ' || rsnt);
      dbms_output.put_line('Reason:        ' || str_for_reason_in_runtime_info(runinfo.reason));
      
      print_proginfo(runinfo.program);
  end print_runtime_info;/*}*/

  procedure print_source (/*{*/
    runinfo       dbms_debug.runtime_info,
    lines_before  number default 0,
    lines_after   number default 0
  ) is
    first_line binary_integer;
    last_line  binary_integer;

    prefix varchar2(  99);
    suffix varchar2(4000);

    --source_lines                 vc2_table;
    source_lines dbms_debug.vc2_table;

    cur_line         binary_integer;
    cur_real_line    number;
  begin

    first_line := greatest(runinfo.line# - cont_lines_before_,1);
    last_line  :=          runinfo.line# + cont_lines_after_    ;

    if first_line is null or last_line is null then
      dbms_output.put_line('first_line or last_line is null');
      print_runtime_info(runinfo);
      return;
    end if;

    if runinfo.program.name is not null and runinfo.program.owner is not null then

      dbms_output.put_line('');
      dbms_output.put_line('  ' || runinfo.program.owner || '.' || runinfo.program.name);

        --select 
        --   cast(multiset(
          for r in (
                select
                  -- 90 is the length in dbms_debug.vc2_table....
                  rownum line,
                  substr(text,1,90) text
                from 
                  all_source 
                where 
                  name   = runinfo.program.name   and
                  owner  = runinfo.program.owner  and
                  type  <> 'PACKAGE'              and
                  line  >= first_line             and 
                  line  <= last_line
                order by 
                  line )-- as vc2_table)
              loop 
--        into
--          source_lines
--        from 
--          dual;
        source_lines(r.line) := r.text;      

      end loop;

    else
     
      dbms_debug.show_source(first_line, last_line, source_lines);

--      select
--        cast(
--          multiset(
--            select culumn_value from 
--              table(
--                cast(source_lines_dbms as dbms_debug.vc2_table)
--              )
--        )as vc2_table)
--      into
--        source_lines
--      from 
--        dual;
    
    end if;

    dbms_output.put_line('');

    cur_line := source_lines.first();
    while cur_line is not null loop
      cur_real_line := cur_line + first_line -1;
    
   -- for r in (select column_value text from table(source_lines)) loop
        prefix := to_char(cur_real_line,'9999');

        if cur_real_line = runinfo.line# then 
           prefix := prefix || ' -> ';
        else
           prefix := prefix || '    ';
        end if;
  
  
        -- TODO, most probably superfluos, 90 is the max width.... (ts, ts)
        --if length(r.text) > v_lines_width then
        --  suffix := substr(r.text,1,v_lines_width);
        --else
        --  suffix := r.text;
        --end if;
  
        suffix := source_lines(cur_line);
        suffix := translate(suffix,chr(10),' ');
        suffix := translate(suffix,chr(13),' ');
        
        --dbms_output.put_line(prefix || suffix);
        dbms_output.put_line(prefix || suffix);
  
    --    line_printed := 'Y';
      
      cur_line := source_lines.next(cur_line);
      --cur_line := cur_line + 1;
    end loop;

    dbms_output.put_line('');

  end print_source;/*}*/

  procedure print_runtime_info_with_source(/*{*/
    runinfo dbms_debug.runtime_info 
    ) is


  begin

    print_runtime_info(runinfo);

    --dbms_output.put_line('line#: ' || runinfo.line#);
    --dbms_output.put_line(' -   : ' || (runinfo.line# - cont_lines_before_));

      --dbms_output.put_line('first_line: ' || first_line);
      --dbms_output.put_line('last_line:  ' || last_line);

    print_source(runinfo);

  end print_runtime_info_with_source;/*}*/

  procedure self_check as/*{*/
    ret binary_integer;
  begin
    dbms_debug.self_check(5);
  exception
    when dbms_debug.pipe_creation_failure  then dbms_output.put_line('  self_check: pipe_creation_failure');
    when dbms_debug.pipe_send_failure      then dbms_output.put_line('  self_check: pipe_send_failure');
    when dbms_debug.pipe_receive_failure   then dbms_output.put_line('  self_check: pipe_receive_failure');
    when dbms_debug.pipe_datatype_mismatch then dbms_output.put_line('  self_check: pipe_datatype_mismatch');
    when dbms_debug.pipe_data_error        then dbms_output.put_line('  self_check: pipe_data_error');
    when others then                            dbms_output.put_line('  self_check: unknown error');
  end self_check;/*}*/

  procedure set_breakpoint(/*{*/
  /* 
     
     Out of the four parameters
       p_cursor, p_toplevel, p_body, p_trigger,
     at most one should be set to zero. They set the
     proginfo.namespace

  */
    p_line     in number, p_name in varchar2 default null, p_owner in varchar2 default null,
    p_cursor   in boolean default false,
    p_toplevel in boolean default false,
    p_body     in boolean default false,
    p_trigger  in boolean default false) 
  as
    proginfo dbms_debug.program_info;
    ret      binary_integer;
    bp       binary_integer;
  begin

    if    p_cursor   then proginfo.namespace := dbms_debug.namespace_cursor;
    elsif p_toplevel then proginfo.namespace := dbms_debug.namespace_pkgspec_or_toplevel;
    elsif p_body     then proginfo.namespace := dbms_debug.namespace_pkg_body;
    elsif p_trigger  then proginfo.namespace := dbms_debug.namespace_trigger;
    else                  proginfo.namespace := null;
    end if;

    proginfo.name           := p_name;
    proginfo.owner          := p_owner;
    proginfo.dblink         := null;
    proginfo.entrypointname := null;
  
    ret := dbms_debug.set_breakpoint(
            proginfo,
            p_line,
            bp);
  
    if    ret = dbms_debug.success            then dbms_output.put_line('  breakpoint set: ' || bp);
    elsif ret = dbms_debug.error_illegal_line then dbms_output.put_line('  set_breakpoint: error_illegal_line');
    elsif ret = dbms_debug.error_bad_handle   then dbms_output.put_line('  set_breakpoint: error_bad_handle');
    else                                           dbms_output.put_line('  set_breakpoint: unknown error (' || ret || ')');
    end if;
  
  end set_breakpoint;/*}*/

  procedure step is/*{*/
  begin
    continue_(dbms_debug.break_next_line);
  end step;/*}*/
 
  procedure step_into is/*{*/
  begin
    continue_(dbms_debug.break_any_call);
  end step_into;/*}*/

  procedure step_out is/*{*/
  begin
    continue_(dbms_debug.break_any_return);
  end step_out; /*}*/
  
  function str_for_namespace(nsp in binary_integer) return varchar2 is/*{*/
    nsps   varchar2(40);
  begin
    if nsp = dbms_debug.Namespace_cursor                 then nsps := 'Cursor (anonymous block)';
    elsif nsp = dbms_debug.Namespace_pkgspec_or_toplevel then nsps := 'package, proc, func or obj type';
    elsif nsp = dbms_debug.Namespace_pkg_body            then nsps := 'package body or type body';
    elsif nsp = dbms_debug.Namespace_trigger             then nsps := 'Triggers';
    else                                                      nsps := 'Unknown namespace';
    end if;

    return nsps;
  end str_for_namespace;/*}*/
  
  function  str_for_reason_in_runtime_info(rsn in binary_integer) return varchar2 is/*{*/
    rsnt varchar2(40);
  begin
    if rsn = dbms_debug.reason_none                    then rsnt := 'none';
    elsif rsn = dbms_debug.reason_interpreter_starting then rsnt := 'Interpreter is starting.';
    elsif rsn = dbms_debug.reason_breakpoint           then rsnt := 'Hit a breakpoint';
    elsif rsn = dbms_debug.reason_enter                then rsnt := 'Procedure entry';
    elsif rsn = dbms_debug.reason_return               then rsnt := 'Procedure is about to return';
    elsif rsn = dbms_debug.reason_finish               then rsnt := 'Procedure is finished';
    elsif rsn = dbms_debug.reason_line                 then rsnt := 'Reached a new line';
    elsif rsn = dbms_debug.reason_interrupt            then rsnt := 'An interrupt occurred';
    elsif rsn = dbms_debug.reason_exception            then rsnt := 'An exception was raised';
    elsif rsn = dbms_debug.reason_exit                 then rsnt := 'Interpreter is exiting (old form)';
    elsif rsn = dbms_debug.reason_knl_exit             then rsnt := 'Kernel is exiting';
    elsif rsn = dbms_debug.reason_handler              then rsnt := 'Start exception-handler';
    elsif rsn = dbms_debug.reason_timeout              then rsnt := 'A timeout occurred';
    elsif rsn = dbms_debug.reason_instantiate          then rsnt := 'Instantiation block';
    elsif rsn = dbms_debug.reason_abort                then rsnt := 'Interpreter is aborting';
    else                                                    rsnt := 'Unknown reason';
    end if;

    return rsnt;
  end str_for_reason_in_runtime_info;/*}*/

  procedure wait_until_running as/*{*/
    runinfo dbms_debug.runtime_info;
    ret     binary_integer;
    v_err   varchar2(100);
  begin
    ret:=dbms_debug.synchronize( runinfo, 0 /*+
      dbms_debug.info_getstackdepth +
      dbms_debug.info_getbreakpoint +
      dbms_debug.info_getlineinfo   +
      dbms_debug.info_getoerinfo    +
      0 */
    );
  
    if ret = dbms_debug.success then 
      print_runtime_info(runinfo);
    elsif ret = dbms_debug.error_timeout then
      dbms_output.put_line('  synchronize: error_timeout');
    elsif ret = dbms_debug.error_communication then
      dbms_output.put_line('  synchronize: error_communication');
    else
       v_err := general_error(ret);
       dbms_output.put_line('  synchronize: general error' || v_err);
      --dbms_output.put_line('  synchronize: unknown error');
    end if;
  
  end wait_until_running;/*}*/

  procedure is_running is/*{*/
  begin
    if dbms_debug.target_program_running then
      dbms_output.put_line('  target (debugee) is running');
    else
      dbms_output.put_line('  target (debugee) is not running');
    end if;
  end is_running;/*}*/

  function  general_error(e in binary_integer) return varchar2 is/*{*/
  begin

    if e = dbms_debug.error_unimplemented then return 'unimplemented'       ; end if;
    if e = dbms_debug.error_deferred      then return 'deferred'            ; end if;
    if e = dbms_debug.error_exception     then return 'probe exception'     ; end if;
    if e = dbms_debug.error_communication then return 'communication error' ; end if;
    if e = dbms_debug.error_unimplemented then return 'unimplemented'       ; end if;
    if e = dbms_debug.error_timeout       then return 'timeout'             ; end if;

    return '???';

  end general_error;/*}*/

  procedure version as/*{*/
    major binary_integer;
    minor binary_integer;
  begin
    dbms_debug.probe_version(major,minor);
    dbms_output.put_line('  probe version is: ' || major || '.' || minor);
  end version;/*}*/

  procedure current_prg is/*{*/
    ri dbms_debug.runtime_info;
    pi dbms_debug.program_info;
    ret binary_integer;
  begin

    ret := dbms_debug.get_runtime_info(
               0             +
               dbms_debug.info_getlineinfo   +
               dbms_debug.info_getbreakpoint +
               dbms_debug.info_getstackdepth +
               dbms_debug.info_getoerinfo    +
               0,
               ri);

     pi := ri.program;

     print_proginfo(pi);
  end current_prg;/*}*/

  begin

    cont_lines_before_ :=   5;
    cont_lines_after_  :=   5;

end debugger;
/
Github repository oracle_scriptlets, path: /debugger/body.plsql

debugger - spec.plsql

create or replace package debugger as

/* 
   Package debugger (spec.plsql and body.plsql)

   Copyright (C) René Nyffenegger

   This source code is provided 'as-is', without any express or implied
   warranty. In no event will the author be held liable for any damages
   arising from the use of this software.

   Permission is granted to anyone to use this software for any purpose,
   including commercial applications, and to alter it and redistribute it
   freely, subject to the following restrictions:

   1. The origin of this source code must not be misrepresented; you must not
      claim that you wrote the original source code. If you use this source code
      in a product, an acknowledgment in the product documentation would be
      appreciated but is not required.

   2. Altered source versions must be plainly marked as such, and must not be
      misrepresented as being the original source code.

   3. This notice may not be removed or altered from any source distribution.

   René Nyffenegger rene.nyffenegger@adp-gmbh.ch

*/

  procedure abort;   

  procedure backtrace;

  -- highly expermiental
  procedure current_prg;

  procedure breakpoints;

  procedure continue_(break_flags in number);
 
  procedure continue;

  procedure delete_bp(breakpoint in binary_integer);

  procedure print_var(name in varchar2);

  procedure start_debugger(debug_session_id in varchar2);

--function  start_debugee return varchar2;
 
  procedure print_proginfo(prginfo dbms_debug.program_info);
 
  procedure print_runtime_info(runinfo dbms_debug.runtime_info);

  procedure print_source(
    runinfo       dbms_debug.runtime_info,
    lines_before  number default 0,
    lines_after   number default 0
  );


  procedure print_runtime_info_with_source(
                 runinfo        dbms_debug.runtime_info 
                 --v_lines_before in number, 
                 --v_lines_after  in number,
                -- v_lines_width  in number
                 );
 
  procedure self_check;

  procedure set_breakpoint(p_line in number, p_name in varchar2 default null, p_owner in varchar2 default null,
    p_cursor   in boolean default false,
    p_toplevel in boolean default false,
    p_body     in boolean default false,
    p_trigger  in boolean default false);

  procedure step;
 
  procedure step_into;

  procedure step_out;

  function  str_for_namespace(nsp in binary_integer) return varchar2;

  function  str_for_reason_in_runtime_info(rsn in binary_integer) return varchar2;

  procedure wait_until_running;

  procedure is_running;

  procedure version;

  procedure detach;

  function  libunittype_as_string(lut binary_integer) return varchar2;

  function  bp_status_as_string(bps binary_integer) return varchar2;

  function  general_error(e in binary_integer) return varchar2;

  -- the following vars are used whenever continue returnes and shows
  -- the lines arount line
  cont_lines_before_ number;
  cont_lines_after_  number;
--cont_lines_width_  number;

--Store the current line of execution
  cur_line_ dbms_debug.runtime_info;

end debugger;
/
Github repository oracle_scriptlets, path: /debugger/spec.plsql

debugger - sqlplus is_r.sql

exec debugger.is_running
Github repository oracle_scriptlets, path: /debugger/sqlplus is_r.sql

debugger - sqlplus so.sql

exwec debugger.step_out
Github repository oracle_scriptlets, path: /debugger/sqlplus so.sql

debugger - sqlplus - abort.sql

exec debugger.abort
Github repository oracle_scriptlets, path: /debugger/sqlplus/abort.sql

debugger - sqlplus - breakpoints.sql

exec debugger.breakpoints
Github repository oracle_scriptlets, path: /debugger/sqlplus/breakpoints.sql

debugger - sqlplus - brl.sql

-- This script sets a breakpoint on a line
--   Most probably to be used for anonymous blocks
exec debugger.set_breakpoint(p_line=>&1)
Github repository oracle_scriptlets, path: /debugger/sqlplus/brl.sql

debugger - sqlplus - cont.sql

exec debugger.continue
Github repository oracle_scriptlets, path: /debugger/sqlplus/cont.sql

debugger - sqlplus - dbe.sql

alter session set plsql_debug=true;

-- Starting the debugee (The target session).
variable debug_session_id varchar2(20)

exec :debug_session_id := dbms_debug.initialize;
print debug_session_id

exec dbms_debug.debug_on;

--exec :debug_session_id := debugger.start_debugee;

--begin
--  dbms_output.put_line(debugger.start_debugee);
--end;
--/


-- TODO:
--     alter session set plsql_debug = true;
Github repository oracle_scriptlets, path: /debugger/sqlplus/dbe.sql

debugger - sqlplus - dbr.sql

-- Starts the debugger, asks for a string that identifies 
-- the debugee. This string is obtained through running dbe.
exec debugger.start_debugger('&debugee_id')
Github repository oracle_scriptlets, path: /debugger/sqlplus/dbr.sql

debugger - sqlplus - delbp.sql

exec debugger.delete_bp(&breakpoint_number)
Github repository oracle_scriptlets, path: /debugger/sqlplus/delbp.sql

debugger - sqlplus - s.sql

exec debugger.step
Github repository oracle_scriptlets, path: /debugger/sqlplus/s.sql

debugger - sqlplus - si.sql

exec debugger.step_into
Github repository oracle_scriptlets, path: /debugger/sqlplus/si.sql

debugger - sqlplus - var.sql

exec debugger.print_var('&1');
Github repository oracle_scriptlets, path: /debugger/sqlplus/var.sql

debugger - test - debugged_package.plsql

create or replace package debugged_package as/*{*/
  function tst_1(i in integer) return integer;
  function tst_2(i in integer) return integer;
end debugged_package;/*}*/
/

create or replace package body debugged_package as/*{*/

  function tst_1(i in integer) return integer is/*{*/
  begin
    if i between 5 and 10 then 
       return 2*i; 
    end if;
    
    if i between 0 and 4 then
       return tst_2(3+i);
    end if;

    if i between 6 and 10 then
       return tst_2(i-2);
    end if;

    return i;
  end tst_1;/*}*/

  function tst_2(i in integer) return integer is/*{*/
  begin
    if i between 6 and 8 then
       return tst_1(i-1);
    end if;

    if i between 1 and 5 then
       return i*2;
    end if;

    return i-1;
  end tst_2;/*}*/

end debugged_package;/*}*/
/

alter package debugged_package compile debug;
Github repository oracle_scriptlets, path: /debugger/test/debugged_package.plsql

debugger - test - run.sql

declare
  v_result integer;
begin
  v_result := debugged_package.tst_1(4);
  dbms_output.put_line('v_result: ' || v_result);
end;
/
Github repository oracle_scriptlets, path: /debugger/test/run.sql

desc_table - body.plsql

create or replace package body desc_table as 

  function describe(table_name in varchar2) return description is /*{*/
    -- used for dbms_utility.name_resolve:
    util_context       number := 2;
    util_schema        varchar2(30);
    util_part1         varchar2(30);
    util_part2         varchar2(30);
    util_dblink        varchar2(128);
    util_part1_type    number;
    util_object_number number;

    tab                table_t;
  begin
    dbms_utility.name_resolve(table_name, util_context, util_schema, util_part1, util_part2, util_dblink, util_part1_type, util_object_number);

    tab.own := util_schema;
    tab.nam := util_part1;

    return describe(tab);

  exception
    when others then 
      case 
        when sqlcode = -6564 then 
        raise table_does_not_exist;
      else
        dbms_output.put_line('exception: ' || sqlerrm || '(' || sqlcode || ')' ); 
    end case;

  end describe;/*}*/

  function describe(tab in table_t) return description is/*{*/
    col_r         col_t;
    ret           description;
    v_table_name  varchar2(30);
    v_table_owner varchar2(30);
    col_pos            number;

  begin

    ret.tab          := tab;

    ret.cols         := cols_t        ();
    ret.col_comments := col_comments_t();
    ret.parents      := tables_t      ();
    ret.children     := tables_t      ();

    select comments,table_type into ret.tab_comment, ret.tab_type from all_tab_comments 
     where table_name = tab.nam and owner = tab.own;

    col_pos := 1;

    for r in (/*{*/
      select
        t.column_name, t.data_type, t.data_length, t.data_precision, t.data_scale, t.nullable, c.comments
      from
        all_tab_cols t join all_col_comments c on 
          t.table_name  = c.table_name  and 
          t.column_name = c.column_name and
          t.owner       = c.owner
      where
        t.table_name = tab.nam and t.owner = tab.own
      order by
        column_id) loop

      col_r.name       := r.column_name;
      col_r.nullable   := case when r.nullable = 'Y' then true else false end;
      col_r.datatype   := r.data_type;
      col_r.checks     := check_t();

      if r.data_length is not null and r.data_precision is null then
        if r.data_type <> 'DATE' then
          col_r.datatype := col_r.datatype || '(' || r.data_length || ')';
        end if;
      end if;

      if r.data_precision is not null then
        col_r.datatype := col_r.datatype || '(' || r.data_precision;

        if r.data_scale is not null and r.data_scale > 0 then
          col_r.datatype := col_r.datatype || ',' || r.data_scale;
        end if;

        col_r.datatype := col_r.datatype || ')';
      end if;

      ret.cols.extend;
      ret.cols(ret.cols.count) := col_r;

      if r.comments is not null then
        ret.col_comments.extend;
        ret.col_comments(ret.col_comments.count).pos     := col_pos; 
        ret.col_comments(ret.col_comments.count).comment := r.comments;
      end if;
      
      col_pos := col_pos+1;
    end loop;/*}*/

    for r in (/*{ Find Constraints */
      select
        r_owner, constraint_name, r_constraint_name, constraint_type, search_condition
      from
        all_constraints
      where
        table_name = tab.nam and owner = tab.own) loop

        if r.constraint_type = 'P' then
          for c in (
            select column_name, table_name, position
              from all_cons_columns
             where constraint_name = r.constraint_name) loop

            ret.pks(c.column_name) := c.position;
          end loop;

          select distinct /* distinct in case a table has two foreign keys to table */
            owner, table_name bulk collect into ret.children
          from
            all_constraints
          where
            r_constraint_name = r.constraint_name and
            owner             = tab.own;

        elsif r.constraint_type = 'R' then -- foreign key

          select owner, table_name into v_table_owner, v_table_name 
            from all_constraints 
           where constraint_name = r.r_constraint_name and owner = r.r_owner;

          ret.parents.extend;
          ret.parents(ret.parents.count).own := v_table_owner;
          ret.parents(ret.parents.count).nam := v_table_name;
        end if;

      end loop;/*}*/

    return ret;

  end describe;/*}*/

end;
/
Github repository oracle_scriptlets, path: /desc_table/body.plsql

desc_table - spec.plsql

create or replace package desc_table 

/* 
   Package desc_table (spec.plsql and body.plsql)

   Copyright (C) René Nyffenegger

   This source code is provided 'as-is', without any express or implied
   warranty. In no event will the author be held liable for any damages
   arising from the use of this software.

   Permission is granted to anyone to use this software for any purpose,
   including commercial applications, and to alter it and redistribute it
   freely, subject to the following restrictions:

   1. The origin of this source code must not be misrepresented; you must not
      claim that you wrote the original source code. If you use this source code
      in a product, an acknowledgment in the product documentation would be
      appreciated but is not required.

   2. Altered source versions must be plainly marked as such, and must not be
      misrepresented as being the original source code.

   3. This notice may not be removed or altered from any source distribution.

   René Nyffenegger rene.nyffenegger@adp-gmbh.ch

*/


  authid current_user
as

  table_does_not_exist exception;
  pragma exception_init(table_does_not_exist, -20010);

--TODO: well, long is deprecated, isn't it?
  type check_t        is table of long;

  type col_t          is record (name varchar2(30), nullable boolean, datatype varchar2(106), checks check_t);
  type cols_t         is table   of col_t;

  type col_comment_t  is record (pos number, comment user_tab_comments.comments%type);
  type col_comments_t is table   of col_comment_t;

  type table_t        is record (own varchar2(30), nam varchar2(30));
  type tables_t       is table   of table_t;

  type char_to_number is table   of number(2) index by varchar2(30);

  type description    is record (tab           table_t,
                                 tab_type      user_tab_comments.table_type%type, -- 'TABLE', 'VIEW' ..?
                                 tab_comment   user_tab_comments.comments%type,
                                 cols          cols_t,
                                 col_comments  col_comments_t,
                                 pks           char_to_number, -- Position of primary keys
                                 parents       tables_t,
                                 children      tables_t);

  -- table_name: 61 chars maximum: 30 chars schema (optional), 1 char dot (optional), 30 chars username 
  function describe(table_name in varchar2) return description;

  function describe(tab        in table_t ) return description;

end desc_table;
/
Github repository oracle_scriptlets, path: /desc_table/spec.plsql

file_to_table - test_01.sql

--
--    If invoked with two apetales (@@): path is relative to
--    directory where file_to_table.sql resides.
--    Could be %SQLPATH%
--
--    Compare test_02.sql
--
begin

  for r in ( 
      @@file_to_table.sql ..\file_to_table\test_01.sql
  ) loop
                                      
    dbms_output.put_line(r.linetext);
                                      
  end loop;
end;
/
Github repository oracle_scriptlets, path: /file_to_table/test_01.sql

file_to_table - test_02.sql

--
--    If invoked with one apetales (@): path is relative to
--    current directory.
--
--    Compare test_02.sql
begin
                                      
  for r in ( 

      @file_to_table.sql test_02.sql

  ) loop
                                      
    dbms_output.put_line(r.linetext);
                                      
  end loop;
end;
/
Github repository oracle_scriptlets, path: /file_to_table/test_02.sql

file_to_table - tmp_file_to_table.sql

create global temporary table tmp_file_to_table (
  linenumber    number(7),
  linetext      varchar2(4000)
)
on commit delete rows;

comment on table tmp_file_to_table is 'This table is used in conjunction with the %SQLPATH%/file_to_table.sql and %SQLPATH%/file_to_table.bat files.';
Github repository oracle_scriptlets, path: /file_to_table/tmp_file_to_table.sql

ipc - demo_use_granted_roles.sql

connect / as sysdba

create user ipc_user identified by ipc_user;

grant
  create procedure,
  create session,
  select_catalog_role
to
  ipc_user;

-- Don't directly grant:
--
-- grant select  on v_$process to ipc_user;
-- grant select  on v_$session to ipc_user;


connect ipc_user/ipc_user


-- User ipc_user may select from v$process
select count(*) from v$process;


create or replace function tq84_proc_memory return varchar2 as
   v_result varchar2(200);
begin

    select
     'Used: '     || round(pga_used_mem    /1024/1024)||', '||
     'Alloc: '    || round(pga_alloc_mem   /1024/1024)||', '||
     'Freeable: ' || round(pga_freeable_mem/1024/1024)||', '||
     'PGA Max: '  || round(pga_max_mem     /1024/1024)
    into  
      v_result
    from
      v$process
    where
      addr = (select paddr from v$session where sid = 
      sys_context('USERENV','SID'));

    return v_result;

end tq84_proc_memory;
/

-- function tq84_proc_memory does not compile:

show errors
-- LINE/COL ERROR
-- -------- -----------------------------------------------------------------
-- 5/5      PL/SQL: SQL Statement ignored
-- 15/33    PL/SQL: ORA-00942: table or view does not exist

-- It would compile, if grants on v$* were directly given:
--    grant select on v_$process to ipc_user /
--    grant select on v_$session to ipc_user.

connect / as sysdba

grant execute on dbms_job  to ipc_user;
grant execute on dbms_pipe to ipc_user;
grant create job to ipc_user;

connect ipc_user/ipc_user

@IPC.pks
@IPC.pkb

create or replace function tq84_proc_memory return varchar2 as

  v_proc varchar2(32000);

begin

  v_proc := q'!
   declare
     x varchar2(200);
   begin
    select
     'Used: '     || round(pga_used_mem    /1048576)||', '||
     'Alloc: '    || round(pga_alloc_mem   /1048576)||', '||
     'Freeable: ' || round(pga_freeable_mem/1048576)||', '||
     'PGA Max: '  || round(pga_max_mem     /1048576)
    into  
      x
    from
      v$process
    where
     addr = (select paddr from v$session where sid = !' || 
             sys_context('USERENV','SID') || q'!);
    :result := x;
  end;!';

    return ipc.exec_plsql_in_other_session(v_proc);

end tq84_proc_memory;
/

show errors

select tq84_proc_memory from dual;

select ipc.exec_plsql_in_other_session('begin :result := user; end;') from dual;

connect / as sysdba
drop user ipc_user cascade;
Github repository oracle_scriptlets, path: /ipc/demo_use_granted_roles.sql

ipc - IPC.pkb

create or replace package body ipc as


    function exec_plsql_in_other_session(plsql in varchar2, maxwait_seconds in number := 1) return varchar2 is
    
        v_pipe_name    varchar2(37) := 'pipe-' || sys_guid;
        v_status       number;

        v_proc         varchar2(32000);
        v_result       varchar2(32000);

        pragma autonomous_transaction;

    begin


        v_status := dbms_pipe.create_pipe(v_pipe_name);

        v_proc := 'declare c number; dummy number; status number; res varchar2(4000);' ||
                  'begin c:= dbms_sql.open_cursor;' ||
                        'dbms_sql.parse(c, q''@' || plsql                        || '@'', dbms_sql.native);' ||
                        'dbms_sql.bind_variable(c, ''result'', lpad('' '', 32000));' ||
                        'dummy := dbms_sql.execute(c);' ||
                        'dbms_sql.variable_value(c, ''result'', res);' ||
                        'dbms_sql.close_cursor(c);' ||
                        'dbms_pipe.pack_message(res);' ||
                        'status := dbms_pipe.send_message(''' || v_pipe_name || ''');' ||
                  'exception when others then' ||
                  '  dbms_pipe.pack_message(sqlerrm); ' ||
                  '  status := dbms_pipe.send_message(''' || v_pipe_name || ''');' ||
                  '  raise_application_error(-20800, sqlerrm);' ||
                  'end;';

        dbms_scheduler.create_job (
          job_name        => 'tools_process_memory',
          job_type        => 'PLSQL_BLOCK',
          job_action      =>  v_proc,
          start_date      =>  null,
          repeat_interval =>  null,
          enabled         =>  true
        );

        v_status := dbms_pipe.receive_message(v_pipe_name, maxwait_seconds);

        dbms_pipe.unpack_message(v_result);

        v_status := dbms_pipe.remove_pipe(v_pipe_name);

        commit;

        return v_result;


    exception when others then

        v_status := dbms_pipe.remove_pipe(v_pipe_name);
        rollback;
        return 'IPC.exec_plsql_in_other_session: ' || sqlerrm;

    end exec_plsql_in_other_session;

end ipc;
/
Github repository oracle_scriptlets, path: /ipc/IPC.pkb

ipc - IPC.pks

create or replace package ipc as

    -- $Id: ipc.sps 16460 2014-11-19 09:27:54Z tq84 $

    function exec_plsql_in_other_session(plsql in varchar2, maxwait_seconds in number := 1) return varchar2;

end ipc;
/
Github repository oracle_scriptlets, path: /ipc/IPC.pks

mailer - body.plsql

create or replace package body mailer as

  c_seperator constant varchar2(19) := 'tq84$tq84$tq84$tq84';

  procedure auth_login( -- {
               smtp      in out utl_smtp.connection,
               username  in     varchar2,
               password  in     varchar2) is
  begin

    utl_smtp.command(smtp, 'AUTH LOGIN');
    utl_smtp.command(smtp, utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(username))));
    utl_smtp.command(smtp, utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(password)))); 

  end auth_login; -- }

  procedure header ( -- {
               smtp            in out utl_smtp.connection,
               mail_addr_from  in     varchar2,
               mail_addr_to    in     varchar2,
               subject         in     varchar2)
  is
  begin

    utl_smtp.write_data(smtp, 'Date: ' || to_char(sysdate, 'dd-mon-yyyy hh24:mi:ss') || utl_tcp.crlf);
    utl_smtp.write_data(smtp, 'To: ' || mail_addr_to || utl_tcp.crlf);
    utl_smtp.write_data(smtp, 'From: ' || mail_addr_from || utl_tcp.crlf);
    utl_smtp.write_data(smtp, 'Subject: ' || subject || utl_tcp.crlf);
    utl_smtp.write_data(smtp, 'reply-to: ' || mail_addr_from || UTL_TCP.crlf);
    utl_smtp.write_data(smtp, 'MIME-Version: 1.0' || utl_tcp.crlf);
    utl_smtp.write_data(smtp, 'Content-Type: multipart/mixed; boundary="' || c_seperator || '"' || utl_tcp.crlf || utl_tcp.crlf);

  end header; -- }

  procedure html(smtp in out  utl_smtp.connection, -- {
                 html in      varchar2) is
  begin

    utl_smtp.write_data(smtp, '--' || c_seperator || utl_tcp.crlf);
    utl_smtp.write_data(smtp, 'Content-Type: text/html' || utl_tcp.crlf || utl_tcp.crlf);

    utl_smtp.write_data(smtp, html);

    utl_smtp.write_data(smtp, utl_tcp.crlf || utl_tcp.crlf);

    return;

  end html; -- }

  procedure attachment( -- {
    smtp     in out utl_smtp.connection,
    filename in     varchar2, 
    content  in blob) is

    c_step   constant pls_integer  := 12000; -- Multiple of 3, not higher than 24573

  begin

    utl_smtp.write_data(smtp, '--' || c_seperator || utl_tcp.crlf);
    utl_smtp.write_data(smtp, 'Content-Type: application/octet-stream; name="' || filename || '"' || utl_tcp.crlf);
    utl_smtp.write_data(smtp, 'Content-Transfer-Encoding: base64' || UTL_TCP.crlf);
    utl_smtp.write_data(smtp, 'Content-Disposition: attachment; filename="' || filename || '"' || utl_tcp.crlf || utl_tcp.crlf);
  
    for i in 0 .. trunc((dbms_lob.getlength(content) - 1 )/c_step) loop
      utl_smtp.write_data(smtp, utl_raw.cast_to_varchar2(utl_encode.base64_encode(DBMS_LOB.substr(content, c_step, i * c_step + 1))));
    end loop;
  
    utl_smtp.write_data(smtp, utl_tcp.crlf || utl_tcp.crlf);


  end attachment; -- }

  procedure end_mail( -- {
    smtp     in out utl_smtp.connection
  ) is
  begin

    utl_smtp.write_data(smtp, '--' || c_seperator || '--' || utl_tcp.crlf);
    utl_smtp.close_data(smtp);
  
    utl_smtp.quit(smtp);

  end end_mail; -- }

end mailer;
/
Github repository oracle_scriptlets, path: /mailer/body.plsql

mailer - spec.plsql

create or replace package mailer is
  
  procedure auth_login(
               smtp      in out utl_smtp.connection,
               username  in     varchar2,
               password  in     varchar2);

  procedure header (
               smtp            in out utl_smtp.connection,
               mail_addr_from  in     varchar2,
               mail_addr_to    in     varchar2,
               subject         in     varchar2);

  procedure html(smtp in out  utl_smtp.connection,
                 html in      varchar2);

  procedure attachment(
    smtp     in out utl_smtp.connection,
    filename in     varchar2, 
    content  in blob);

  procedure end_mail(
    smtp     in out utl_smtp.connection);

end mailer;
/
Github repository oracle_scriptlets, path: /mailer/spec.plsql

mailer - test.plsql

declare

  mailserver  varchar2(100) := '&1';
  port        number        :=  &2 ;
  from_addr   varchar2(100) := '&3';
  to_addr     varchar2(100) := '&4';
  auth_pw     varchar2(100) := '&5';
  from_name   varchar2(100) := '&6';

  smtp_conn   utl_smtp.connection;

  zip         blob;

  function create_zip return blob is -- {

    zip blob;

    file1 blob := utl_raw.cast_to_raw('Hello world!'                                    );
    file2 blob := utl_raw.cast_to_raw('foo bar baz'                                     );
    file3 blob := utl_raw.cast_to_raw('one two three'                                   );
    file4 blob := utl_raw.cast_to_raw('file four' || chr(13) || chr(10) || 'second line');

    large_file blob;

    i number := 1;

  begin

    dbms_lob.createTemporary(zip       , true);
    dbms_lob.createTemporary(large_file, true);

    while i < 10000 loop

      dbms_lob.append(large_file, utl_raw.cast_to_raw(to_char(to_date(i, 'j'),'jsp') || chr(13) || chr(10)));
      i := i+1;
    end loop;

    -- ../zipper
    zipper.addFile(zip, 'hi-world.txt'              , file1     );
    zipper.addFile(zip, 'file_2.txt'                , file2     );
    zipper.addFile(zip, 'subdir1/file_3.txt'        , file3     );
    zipper.addFile(zip, 'subdir1/subdir2/file_4.txt', file4     );
    zipper.addFile(zip, 'subdir1/large/file.txt'    , large_file);

    zipper.finish (zip);
    dbms_lob.freeTemporary(large_file);

    return zip;

  end create_zip; -- }

begin

  smtp_conn := utl_smtp.open_connection(mailserver, port);

  utl_smtp.ehlo(smtp_conn, mailserver );

  mailer.auth_login(smtp_conn, from_addr, auth_pw);
  
  utl_smtp.mail(smtp_conn, from_addr  );
  utl_smtp.rcpt(smtp_conn, to_addr    );

  utl_smtp.open_data(smtp_conn);

  mailer.header( -- {
    smtp_conn,
    mail_addr_from  => from_addr,
    mail_addr_to    => to_addr,
    subject         =>'/// Test mail with attachment ///'
  ); -- }
  
  mailer.html(smtp_conn, q'{<html><head><title>Test with Attachment</title>
   <style type='text/css'>
     * { font-family: Garamond; }
     body {background-color: #f7f0ff;}
   </style>
 </head>
 <body>

 <h1>Hi</h1>

 Attached, you find the zip file.


</body>
</html>
  }');

  zip := create_zip();
  mailer.attachment(smtp_conn, 'The.zip', zip);

  mailer.end_mail(smtp_conn);

  dbms_lob.freeTemporary(zip);


end;
/
Github repository oracle_scriptlets, path: /mailer/test.plsql

operation_log - operation_log.pkb

create or replace package body operation_log as

  type num_t is table of number;
  parent_ids num_t := num_t();

  procedure log_insert( -- {
    p_txt          varchar2,
    p_is_exception varchar2 :='N',
    p_back_trace   varchar2 := null,
    p_clob         clob     := null
  ) is

    pragma autonomous_transaction;

    v_back_trace   varchar2(4000);
    v_caller call_stack.who_am_i_r := call_stack.who_am_i(2);

    v_parent_id number;

  begin

    if parent_ids.count > 0 then
       v_parent_id := parent_ids(parent_ids.count);
    end if;

    insert into operation_log_table values (operation_log_seq.nextval, sysdate, p_txt,
      v_caller.type_,
      substr(v_caller.name_, 1, 30), -- TODO 2016-11-22: This substr is necessarey because of »0X459AF82320        40  ANONYMOUS BLOCK«
      v_caller.pkg_name,
      v_caller.line,
      v_caller.owner,
      p_is_exception, v_parent_id, p_back_trace,
      p_clob
      );

    commit;

  end log_insert; -- }

  procedure log_(txt varchar2, is_exception boolean := false, clob_ clob := null) is -- {

    v_is_exception varchar2(1) := 'N';
    v_back_trace   varchar2(4000);
  begin

    if is_exception then
       v_is_exception := 'Y';

       v_back_trace := dbms_utility.format_error_backtrace;
    end if;

    log_insert(txt, p_is_exception => v_is_exception, p_back_trace => v_back_trace, p_clob => clob_);

  end log_; -- }

  procedure indent(txt varchar2) is -- {
  begin

    log_insert(txt);

    parent_ids.extend;
    parent_ids(parent_ids.count) := operation_log_seq.currval;

  end indent; -- }

  procedure dedent(txt varchar2 := null) is -- {
  begin

    if parent_ids.count > 0 then
       parent_ids.trim;
    else
       log_insert('Warning: dedent called but parent_ids.count = 0');
    end if;

    if txt is not null then
       log_insert(txt);
    end if;

  end dedent; -- }

  procedure exc(txt varchar2 := null) is -- {
  begin

    if sqlcode = c_ex_num then
       dedent(txt);
    else
       log_(sqlerrm, is_exception => true);
       dedent(txt);
    end if;

    raise_application_error(c_ex_num, sqlerrm);

  end exc; -- }

  procedure print_id_recursively(p_id number, p_level number := 0, p_curly_braces boolean := false) is -- {
    v_first   boolean := true;
    v_tm      varchar2(21);
    v_txt     varchar2(4000);

    v_caller_type      operation_log_table.caller_type      %type;
    v_caller_name      operation_log_table.caller_name      %type;
    v_caller_pkg_name  operation_log_table.caller_pkg_name  %type;
    v_caller_line      operation_log_table.caller_line      %type;
    v_caller_owner     operation_log_table.caller_owner     %type;

    v_cnt_children          number;
    c_txt_width    constant number  := 120;
    c_caller_width constant number  := 150;
    v_clob                  varchar(8);

  begin

    select to_char(tm, 'yyyy-mm-dd hh24:mi:ss'), txt,  caller_type,  caller_name,  caller_pkg_name,  caller_line,  caller_owner,case when clob_ is not null then ' -clob- ' else ' ' end
      into       v_tm                         ,v_txt,v_caller_type,v_caller_name,v_caller_pkg_name,v_caller_line,v_caller_owner,v_clob
      from operation_log_table
     where id = p_id;

    select count(*) into v_cnt_children from operation_log_table where id_parent = p_id;

    dbms_output.put( substr(rpad( 
                                lpad(' ', p_level * 2) || 
                                   replace(
                                   replace(
                                   replace(v_txt, chr( 10), ' '),
                                                  chr(123), ' '), -- opening curly brace
                                                  chr(125), ' '), -- closing curly brace
                                c_caller_width), 
                                1, c_txt_width
                             )    || ' ' ||
                             &tq84_prefix.string_op.sprintf('%8s %s %-30s %-30s %4d %-30s',
                                 v_clob            ,
                                 v_tm              ,
                                 v_caller_name     ,
                                 v_caller_pkg_name ,
                                 v_caller_line     ,
                                 v_caller_owner 
                              ));

    if p_curly_braces and v_cnt_children > 0 then 
       dbms_output.put_line(' ' || chr(123));
    else
       dbms_output.put_line('');
    end if;


    for r in (select id from operation_log_table where id_parent = p_id        order by id) loop
        print_id_recursively(r.id, p_level + 1, p_curly_braces => p_curly_braces);
    end loop;

    if p_curly_braces then
       if v_cnt_children > 0  then
          dbms_output.put_line(lpad(' ', (p_level) * 2) || chr(125));
       end if;
    end if;

  end print_id_recursively; -- }

  procedure find_last_root_ids(p_count number := 20) is -- {
  begin

    for r in (

      select id, tm from (

        select id, tm, row_number() over (order by id desc) r
          from operation_log_table
         where id_parent is null
         order by id desc

      )
      where r <= p_count

    ) loop

      dbms_output.put_line(to_char(r.id, '9999999') || ': ' || to_char(r.tm, 'dd.mm.yyyy hh24:mi:ss'));

    end loop;

  end find_last_root_ids; -- }

end operation_log;
/
show errors
Github repository oracle_scriptlets, path: /operation_log/operation_log.pkb

operation_log - operation_log.pks

create or replace package operation_log as

  exception_ exception;
  pragma exception_init(exception_, -20001); 
        c_ex_num constant number := -20001;

  procedure log_(txt varchar2, is_exception boolean := false, clob_ clob := null);

  procedure indent(txt varchar2);
  procedure dedent(txt varchar2 := null);

  procedure exc(txt varchar2 := null);

  procedure print_id_recursively(p_id number, p_level number := 0, p_curly_braces boolean := false);

  procedure find_last_root_ids(p_count number := 20);

end operation_log;
/
Github repository oracle_scriptlets, path: /operation_log/operation_log.pks

operation_log - operation_log_table.sql

drop table operation_log_table purge;

create table operation_log_table (
  id               number,
  tm               date                 not null,
  txt              varchar2(4000)       not null,
--caller           varchar2(4000)       not null,
  caller_type      varchar2(  32)       not null,
  caller_name      varchar2(  30)       not null,
  caller_pkg_name  varchar2(  30)           null,
  caller_line      number  (   6)       not null,
  caller_owner     varchar2(  30)       not null,
  --
  is_exception     varchar2(   1)       not null check(is_exception in ('N', 'Y')),
  id_parent        number                   null,
  error_backtrace  varchar2(4000)           null,
  --
  clob_            clob                     null,
  --
  constraint       operation_log_table_pk  primary key (id),
  constraint operation_log_fk1 foreign key (id_parent) references operation_log_table
)
-- partition by range (tm)
--   interval (numtoyminterval(1, 'month')) (
--   partition operation_log_part_1 values less than (date '2016-12-01')
-- )
pctused 0
;

drop   sequence operation_log_seq;
create sequence operation_log_seq;
Github repository oracle_scriptlets, path: /operation_log/operation_log_table.sql

operation_log - spool_log.sql

define root_id=&2

@spool c:\temp\log.txt

exec operation_log.print_id_recursively(p_id => &root_id, p_curly_braces => true)

@spool_off
Github repository oracle_scriptlets, path: /operation_log/spool_log.sql

operation_log - _test - run.plsql

truncate table    operation_log_table;
drop     sequence operation_log_seq;
create   sequence operation_log_seq start with 1;
alter    package  operation_log compile;

drop package operation_log_test;
drop table operation_log_table_expected purge;
drop table operation_log_table_gotten   purge;

create table operation_log_table_expected ( -- {
   id                       number,
-- tm                       date,
   txt                      varchar2(4000),
   --
    caller_type             varchar2(32),
    caller_name             varchar2(30),
    caller_pkg_name         varchar2(30),
    caller_line             number  ( 6),
    caller_owner            varchar2(30),
    --
    is_exception            varchar2(1),
    id_parent               number,
    error_backtrace         varchar2(4000),
    clob_                   varchar2( 200)   -- Note, is a CLOB in the »original« table
) -- }
/

-- {  Expected data
--                                             (        ID   TXT                                         CALLER_TYPE        CALLER_NAME              CALLER_PKG_NAME      CALLER_LINE  CALLER_OWNER     I     ID_PARENT   ERROR_BACKTRACE                                              , CLOB_
--                                             (----------,  ---------------------                    ,  ----------------,  --------------------- ,  --------------------,-----------, -------------,  '-' , ----------,  ---------------                                                -----
insert into operation_log_table_expected values(         1, 'proc_a'                                  , 'PROCEDURE'      , 'PROC_A'               , 'OPERATION_LOG_TEST' ,          6, user         ,  'N' ,       null,  null                                                         , null);  
insert into operation_log_table_expected values(         2, 'Iterating i 1 .. 3'                      , 'PROCEDURE'      , 'PROC_A'               , 'OPERATION_LOG_TEST' ,          8, user         ,  'N' ,       null,  null                                                         , null);
insert into operation_log_table_expected values(         3, 'i: 1'                                    , 'PROCEDURE'      , 'PROC_A'               , 'OPERATION_LOG_TEST' ,         12, user         ,  'N' ,          2,  null                                                         , null);
insert into operation_log_table_expected values(         4, 'Iterating j 1 .. 1'                      , 'PROCEDURE'      , 'PROC_A'               , 'OPERATION_LOG_TEST' ,         14, user         ,  'N' ,          2,  null                                                         , null);
insert into operation_log_table_expected values(         5, 'j: 1'                                    , 'PROCEDURE'      , 'PROC_A'               , 'OPERATION_LOG_TEST' ,         17, user         ,  'N' ,          4,  null                                                         , null);
insert into operation_log_table_expected values(         6, 'finished'                                , 'PROCEDURE'      , 'PROC_A'               , 'OPERATION_LOG_TEST' ,         20, user         ,  'N' ,          2,  null                                                         , null);
insert into operation_log_table_expected values(         7, 'i: 2'                                    , 'PROCEDURE'      , 'PROC_A'               , 'OPERATION_LOG_TEST' ,         12, user         ,  'N' ,          2,  null                                                         , null);
insert into operation_log_table_expected values(         8, 'Iterating j 1 .. 2'                      , 'PROCEDURE'      , 'PROC_A'               , 'OPERATION_LOG_TEST' ,         14, user         ,  'N' ,          2,  null                                                         , null);
insert into operation_log_table_expected values(         9, 'j: 1'                                    , 'PROCEDURE'      , 'PROC_A'               , 'OPERATION_LOG_TEST' ,         17, user         ,  'N' ,          8,  null                                                         , null);
insert into operation_log_table_expected values(        10, 'j: 2'                                    , 'PROCEDURE'      , 'PROC_A'               , 'OPERATION_LOG_TEST' ,         17, user         ,  'N' ,          8,  null                                                         , null);
insert into operation_log_table_expected values(        11, 'finished'                                , 'PROCEDURE'      , 'PROC_A'               , 'OPERATION_LOG_TEST' ,         20, user         ,  'N' ,          2,  null                                                         , null);
insert into operation_log_table_expected values(        12, 'i: 3'                                    , 'PROCEDURE'      , 'PROC_A'               , 'OPERATION_LOG_TEST' ,         12, user         ,  'N' ,          2,  null                                                         , null);
insert into operation_log_table_expected values(        13, 'Iterating j 1 .. 3'                      , 'PROCEDURE'      , 'PROC_A'               , 'OPERATION_LOG_TEST' ,         14, user         ,  'N' ,          2,  null                                                         , null);
insert into operation_log_table_expected values(        14, 'j: 1'                                    , 'PROCEDURE'      , 'PROC_A'               , 'OPERATION_LOG_TEST' ,         17, user         ,  'N' ,         13,  null                                                         , null);
insert into operation_log_table_expected values(        15, 'j: 2'                                    , 'PROCEDURE'      , 'PROC_A'               , 'OPERATION_LOG_TEST' ,         17, user         ,  'N' ,         13,  null                                                         , null);
insert into operation_log_table_expected values(        16, 'j: 3'                                    , 'PROCEDURE'      , 'PROC_A'               , 'OPERATION_LOG_TEST' ,         17, user         ,  'N' ,         13,  null                                                         , null);
insert into operation_log_table_expected values(        17, 'finished'                                , 'PROCEDURE'      , 'PROC_A'               , 'OPERATION_LOG_TEST' ,         20, user         ,  'N' ,          2,  null                                                         , null);
insert into operation_log_table_expected values(        18, 'operation_log_test_p'                    , 'PROCEDURE'      , 'OPERATION_LOG_TEST_P' ,  null                ,          4, user         ,  'N' ,          2,  null                                                         , null);
insert into operation_log_table_expected values(        19, 'in op log proc'                          , 'PROCEDURE'      , 'OPERATION_LOG_TEST_P' ,  null                ,          6, user         ,  'N' ,         18,  null                                                         , null);
insert into operation_log_table_expected values(        20, 'proc_b'                                  , 'PROCEDURE'      , 'PROC_B'               , 'OPERATION_LOG_TEST' ,         43, user         ,  'N' ,          2,  null                                                         , null);
insert into operation_log_table_expected values(        21, 'testing a clob'                          , 'PROCEDURE'      , 'PROC_B'               , 'OPERATION_LOG_TEST' ,         45, user         ,  'N' ,         20,  null                                                         ,'This is the clob');
insert into operation_log_table_expected values(        22, 'proc_c'                                  , 'PROCEDURE'      , 'PROC_C'               , 'OPERATION_LOG_TEST' ,         61, user         ,  'N' ,         20,  null                                                         , null);
insert into operation_log_table_expected values(        23, 'Not going to throw'                      , 'PROCEDURE'      , 'PROC_C'               , 'OPERATION_LOG_TEST' ,         67, user         ,  'N' ,         22,  null                                                         , null);
insert into operation_log_table_expected values(        24, 'proc_c'                                  , 'PROCEDURE'      , 'PROC_C'               , 'OPERATION_LOG_TEST' ,         61, user         ,  'N' ,         20,  null                                                         , null);
insert into operation_log_table_expected values(        25, 'Going to throw'                          , 'PROCEDURE'      , 'PROC_C'               , 'OPERATION_LOG_TEST' ,         64, user         ,  'N' ,         24,  null                                                         , null);
insert into operation_log_table_expected values(        26, 'ORA-01476: divisor is equal to zero'     , 'PROCEDURE'      , 'EXC'                  , 'OPERATION_LOG'      ,         87, user         ,  'Y' ,         24, 'ORA-06512: at "RENE.OPERATION_LOG_TEST", line 65' || chr(10) , null);
insert into operation_log_table_expected values(        27, 'expected exception caught'               , 'PROCEDURE'      , 'PROC_A'               , 'OPERATION_LOG_TEST' ,         32, user         ,  'N' ,          2,  null                                                         , null);
 -- }

create or replace package operation_log_test as -- {

    procedure proc_a;
    procedure proc_b;
    procedure proc_c(throw_exc boolean);

end operation_log_test; -- }
/

create or replace procedure operation_log_test_p as -- {
begin

    operation_log.indent('operation_log_test_p');

    operation_log.log_('in op log proc');

    operation_log.dedent;

end operation_log_test_p; -- }
/

create or replace package body operation_log_test as -- {

    procedure proc_a is -- {
    begin

        operation_log.log_('proc_a');

        operation_log.indent('Iterating i 1 .. 3');

        for i in 1 .. 3 loop -- {

          operation_log.log_('i: ' || i);

          operation_log.indent('Iterating j 1 .. ' || i);

          for j in 1 .. i loop -- {
             operation_log.log_('j: ' || j);
          end loop; -- }

          operation_log.dedent('finished');

        end loop; -- }

        operation_log_test_p;

        proc_b;

        operation_log.dedent;

    exception
       when operation_log.exception_ then
         operation_log.log_('expected exception caught');
         operation_log.dedent; 

       when others then
         operation_log.exc;

    end proc_a; -- }

    procedure proc_b is -- {
    begin

      operation_log.indent('proc_b');

      operation_log.log_('testing a clob', clob_ => 'This is the clob');

      proc_c(false);
      proc_c( true);

      operation_log.dedent;

    exception when others then

       operation_log.exc;

    end proc_b; -- }

    procedure proc_c(throw_exc boolean) is -- {
    begin

      operation_log.indent('proc_c');

      if throw_exc then
         operation_log.log_('Going to throw');
         dbms_output.put_line('division by zero: ' || (42/0));
      else
         operation_log.log_('Not going to throw');
      end if;

      operation_log.dedent;

    exception when others then

       operation_log.exc;

    end proc_c; -- }

end operation_log_test; -- }
/
show errors

exec operation_log_test.proc_a

create table operation_log_table_gotten as select -- {
  id,
  txt,
  --
  caller_type,
  caller_name,
  caller_pkg_name,
  caller_line,
  caller_owner,
  --
  is_exception,
  id_parent,
  error_backtrace,
  cast(clob_ as varchar2(200)) clob_
from
  operation_log_table -- }
;

exec operation_log.print_id_recursively(2)

-- https://github.com/ReneNyffenegger/oracle_scriptlets/blob/master/sqlpath/diff_tables.sql
@diff_tables operation_log_table_gotten operation_log_table_expected


/*
select
  id,
  substr(txt, 1, 20),
  substr(caller, 1, 60),
  is_exception,
  id_parent, 
  substr(error_backtrace, 1, 30)
from
  operation_log_table;
*/

/*
with log_rec (txt, caller, is_exception, id, level_) as (
  select
    substr(txt   , 1, 60) txt,
    substr(caller, 1, 60) caller,
    is_exception,
    id,
    0  level_
  from
    operation_log_table
  where
    id_parent is null 
UNION ALL
  select
    lpad(' ', level_) || substr(operation_log_table.txt, 1, 60),
    substr(operation_log_table.caller, 1, 60),
    operation_log_table.is_exception,
    operation_log_table.id,
    level_ + 1
  from
    log_rec              join
    operation_log_table on log_rec.id = operation_log_table.id_parent
)
select
  substr(lpad(' ', level_*2) || txt, 1, 50),
  substr(caller, 1, 60),
  is_exception
from
  log_rec
order by id;
*/

-- drop package operation_log_test;
-- drop table operation_log_table_expected purge;
-- drop table operation_log_table_gotten   purge;
Github repository oracle_scriptlets, path: /operation_log/_test/run.plsql

plan2html - create_tables.sql

drop table plan_table purge;
@?/rdbms/admin/utlxplan.sql

drop   table plan2html_t purge;
create table plan2html_t (
  seq    number unique,
  html   varchar2(4000)
);

drop   sequence plan2html_seq;
create sequence plan2html_seq;
Github repository oracle_scriptlets, path: /plan2html/create_tables.sql

plan2html - plan2html.pkb

create or replace package body plan2html as

  nbsp constant varchar2(6) := chr(38) || 'nbsp;';

  procedure write_out(html varchar2) is -- {
  begin
      insert into plan2html_t values(plan2html_seq.nextval, html);
  end write_out; -- }

  procedure explained_stmt_to_table(stmt_id varchar2) is -- {

    c_show_projection constant boolean := false;


    procedure show_step(stmt_id varchar2, pid number, lvl number) is -- {

      object_id   varchar2(4000);

      v_rowspan number;
      padding_left  varchar2(4000);

      procedure td(text varchar2, attr varchar2:=null) is -- {
        attr_ varchar2(4000);
      begin

        if attr is not null then
           attr_ := ' ' || attr;
        end if;
        write_out('<td' || attr_ || '>' || text || '</td>');
      end td; -- }

    begin


      for step in (select * from plan_table where statement_id = stmt_id and nvl(parent_id, -999) = nvl(pid, -999) order by position) loop
        v_rowspan := 1;

        if c_show_projection then
           v_rowspan := v_rowspan + 1;
        end if;

        padding_left := 'padding-left:' || (lvl * 20) || 'px';

        if step.filter_predicates is not null then
           v_rowspan := v_rowspan + 1;
        end if;
        if step.access_predicates is not null then
           v_rowspan := v_rowspan + 1;
        end if;

        write_out('<tr>'); -- {

        if lvl != step.depth then
           raise_application_error(-20800, 'Wrong assumption lvl=' || lvl || ', depth=' || step.depth || '!');
        end if;

        td(step.id, 'rowspan=' || v_rowspan || ' style=''vertical-align:top; color:grey''');

        if step.object_name is not null then -- {
           object_id := ' <b>' || lower(step.object_owner || '.' || step.object_name) || '</b>';
        end if; -- }
           
        if step.object_node is not null then -- {
            object_id := object_id || '@' || lower(step.object_node);
        end if; -- }


        if step.object_alias is not null then -- {
           if object_id is not null then
              object_id := ' ' || object_id;
           end if;

           object_id := object_id || ' [' || lower(step.object_alias) || ']';

        end if; -- }

        td(lower(step.operation) || ' ' || lower(step.options) || object_id, 'colspan=2 style=''' || padding_left || '''');


        td(lower(step.object_type)); 
        td(      step.object_instance); 
        td(      step.cardinality, 'style=''text-align: right'''); 
        td(      step.cost || ' [' || step.cpu_cost || '+' || step.io_cost || ']'); 
        td(      step.bytes     , 'style=''text-align: right'''); 
        td(      step.temp_space, 'style=''text-align: right'''); 
        td(      step.time); 
        td(      step.qblock_name);  -- Name of the query block (either system-generated or defined by the user with the QB_NAME hint)
        td(      step.partition_start || ' - ' || step.partition_stop || ' [' || step.partition_id || ']'); 
        td(      step.distribution);
--      td('xml: '    || step.other_xml);
--      td('Other: '  || step.other_tag); 
        td(              step.optimizer); -- ALL_ROWS, ANALYZED ...
        td(step.search_columns);  -- Number of index columns with start and stop keys (that is: the number of columns with matching predicates)

        write_out('</tr>'); -- }

        if c_show_projection then -- {
           write_out('<tr>');
           td('');
           td('Proj: ' || step.projection, 'colspan=14');
           write_out('</tr>');
        end if; -- }

        if step.filter_predicates is not null then -- {
           write_out('<tr>');
           td('<span style=''color:grey''>' || replace(substr(step.filter_predicates, 1, 3950), '"', '') || '</span>', 'colspan=14 style=''' || padding_left || '''');
           write_out('</tr>');
        end if; -- }

        if step.access_predicates is not null then -- {
           write_out('<tr>');
           td('<span style=''color:grey''>' || replace(substr(step.access_predicates, 1, 3950), '"', '') || '</span>', 'colspan=14 style=''' || padding_left || '''');
           write_out('</tr>');
        end if; -- }

        show_step(stmt_id, step.id, lvl+1);

      end loop;

    end show_step; -- }

  begin


    write_out('<table border=0 style=''border:black solid 1px''>');
    write_out('<tr style=''background-color:#ecdcff''><td></td><td></td><td></td><td>Typ</td><td>Inst</td><td>Card</td><td>Cost</td><td>Bytes</td><td>Temp</td><td>Time</td><td>qblck</td><td>Part</td><td>Dist</td><td>Opt</td><td>S.C.</td></tr>');
    show_step(stmt_id, null, 0);
    write_out('</table>');

  end explained_stmt_to_table; -- }

end plan2html;
/
show errors
Github repository oracle_scriptlets, path: /plan2html/plan2html.pkb

plan2html - plan2html.pks

create or replace package plan2html as

  procedure write_out(html varchar2);
  procedure explained_stmt_to_table(stmt_id varchar2);

end plan2html;
/
Github repository oracle_scriptlets, path: /plan2html/plan2html.pks

plan2html - test.sql

@plan2html.pkb

delete           plan2html_t;
delete from plan_table where statement_id = 'TEST-01';
explain plan               set statement_id='TEST-01' for select * from all_objects where object_name like :1;
exec plan2html.explained_stmt_to_table     ('TEST-01');

$del   c:\temp\expl.html
@spool c:\temp\expl.html

select html from plan2html_t order by seq;
select '<code><pre>' from dual;
select * from table(dbms_xplan.display(statement_id => 'TEST-01'));
select '</pre></code>' from dual;

@spool_off

$\temp\expl.html
Github repository oracle_scriptlets, path: /plan2html/test.sql

plscope - body.plsql

create or replace package body plscope as

    -- Used if it is necessary to prevent circles, for example
    -- in find_call_path_recurse.
    type signatures_seen_t is table of number(1) index by signature_;

    counter number := 0;

    procedure dot_call(caller in varchar2, callee in varchar2) is/*{*/
    begin
        dbms_output.put_line(' "' || caller || '" -> "' || callee || '"');
    end dot_call;/*}*/

    procedure gexf_call(caller in varchar2, callee in varchar2) is/*{*/
    begin
        dbms_output.put_line(' <edge source="' || caller || '" target="' || callee || '"/>');
    end gexf_call;/*}*/

    procedure fill_callable(owner_ in varchar2, delete_existing in boolean) is/*{*/
    begin

        if delete_existing then
           delete plscope_callable;
        end if;

        insert into plscope_callable
              (signature, object_name, name, exclude)
        select signature, object_name, name,       0
          from all_identifiers
         where ( ( type in ('PROCEDURE', 'FUNCTION'                ) and usage = 'DEFINITION' )  or
                 ( type in ('CURSOR'   , 'PACKAGE', 'PACKAGE BODY' ) and usage = 'DECLARATION') 
               ) 
               and owner = owner_;

    end fill_callable;/*}*/

    procedure fill_call(owner_ in varchar2, delete_existing in boolean) is/*{*/
        callers signature_t_;
    begin

        if delete_existing then
           delete plscope_call;
        end if;

        fill_callable(owner_, delete_existing);

        for callable in (select signature from plscope_callable /* TODO: where owner = owner_ */) loop

            callers := who_calls(callable.signature);

            for i in 1 .. callers.count loop

                begin
                insert into plscope_call (caller, callee) values (callers(i), callable.signature);
                exception when others then
--              raise_application_error(-20801, sqlerrm || ': ' ||  callers(i) || ' ' || callable.signature);
                dbms_output.put_line           (sqlerrm || ': ' ||  callers(i) || ' ' || callable.signature);
                end;

            end loop;

        end loop;

    end fill_call;/*}*/

    procedure print_dot_graph is/*{*/
    begin

        dbms_output.put_line('digraph G {');

        for call in (

           select
             caller.object_name object_name_caller,
             caller.name name_caller,
             ' -> ',
             callee.object_name object_name_callee,
             callee.name name_callee
           from
                     plscope_call call
             join plscope_callable caller on call.caller = caller.signature
             join plscope_callable callee on call.callee = callee.signature
        ) loop

           dot_call(call.object_name_caller || '.' || call.name_caller, call.object_name_callee || '.' || call.name_callee);

        end loop;


        dbms_output.put_line('}');

    end print_dot_graph;/*}*/

    procedure print_upwards_graph(sig signature_, format in varchar2) is /*{*/
    begin
    --
    -- Use ../sqlpath/ps_upwards.sql to create a dot file and
    -- render it's content.
    --

        if lower(format) = 'dot' then

              dbms_output.put_line('digraph G ' || chr(123));
              dbms_output.put_line(' graph [overlap=false size="11.7,16.5"];');
              dbms_output.put_line(' node [shape=plaintext fontsize=11 fontname="Arial Narrow"];'); -- shape=record

        elsif lower(format) = 'gefx' then
        --
        -- Fileformat: see http://gexf.net/format/
        --

              dbms_output.put_line('<?xml version="1.0" encoding="UTF-8"?>');
              dbms_output.put_line('<gexf xmlns="http://www.gexf.net/1.2draft" version="1.2">');
              dbms_output.put_line('<edges>');

        end if;


        for r in (


                      with c (complete_name_caller, complete_name_callee, signature_caller, level_) as (
                      ------
                      -- Recursive query:
                      -- First "iteration" get the direct callers of the desired signature_ (parameter sig):
                      --
                                       select complete_name_caller,
                                              complete_name_callee,
                                              signature_caller,
                                              0 level_ -- First iteration, "level" is 0
                                        from plscope_call_v xx
                                       where xx.signature_callee = sig

                              UNION ALL
                      --
                      -- Itaration:
                      -- get the callers of all calls that had been identified
                      -- by the prior iteration:
                      --
                                       select yy.complete_name_caller,
                                              yy.complete_name_callee,
                                              yy.signature_caller,
                                              cc.level_ + 1 level_ -- Next iteration, increase level
                                        from c cc join plscope_call_v yy on
                                              yy.signature_callee = cc.signature_caller and
                                              yy.exclude_caller   = 0
                      )
                      --search depth first by c.object_name_caller set sorting
                      cycle signature_caller set is_cycle to 1 default 0
                      select distinct complete_name_caller, complete_name_callee, signature_caller /*, is_cycle */ from c
                      where
                        is_cycle = 0 /*and
                        level_ < 5*/


        ) loop

           if lower(format) = 'dot' then
                  dot_call(r.complete_name_caller, r.complete_name_callee);
           else
                  gexf_call(r.complete_name_caller, r.complete_name_callee);
           end if;

        end loop;


        if lower(format) = 'dot' then
              dbms_output.put_line(chr(125));
        elsif lower(format) = 'gefx' then
              dbms_output.put_line('</edges>');
              dbms_output.put_line('</gexf>');
        end if;

    end print_upwards_graph;/*}*/

    procedure print_downwards_graph(sig signature_, format in varchar2) is /*{*/
    begin
    --
    -- Use ../sqlpath/ps_downwards.sql to create a dot file and
    -- render it's content.
    --

        if lower(format) = 'dot' then

              dbms_output.put_line('digraph G ' || chr(123));
              dbms_output.put_line(' graph [overlap=false size="11.7,16.5"];');
              dbms_output.put_line(' node [shape=plaintext fontsize=11 fontname="Arial Narrow"];'); -- shape=record

        elsif lower(format) = 'gefx' then
        --
        -- Fileformat: see http://gexf.net/format/
        --

              dbms_output.put_line('<?xml version="1.0" encoding="UTF-8"?>');
              dbms_output.put_line('<gexf xmlns="http://www.gexf.net/1.2draft" version="1.2">');
              dbms_output.put_line('<edges>');

        end if;


        for r in (


                      with c (complete_name_caller, complete_name_callee, signature_callee, level_) as (
                      ------
                      -- Recursive query:
                      -- First "iteration" get the direct callees of the desired signature_ (parameter sig):
                      --
                                       select complete_name_caller,
                                              complete_name_callee,
                                              signature_callee,
                                              0 level_ -- First iteration, "level" is 0
                                        from plscope_call_v xx
                                       where xx.signature_caller = sig and
                                             xx.exclude_callee   =   0

                              UNION ALL
                      --
                      -- Iteration:
                      -- get the callees of all calls that had been identified
                      -- by the prior iteration:
                      --
                                       select yy.complete_name_caller,
                                              yy.complete_name_callee,
                                              yy.signature_callee,
                                              cc.level_ + 1 level_ -- Next iteration, increase level
                                        from c cc join plscope_call_v yy on
                                              yy.signature_caller = cc.signature_callee
                                        where yy.exclude_caller = 0 and
                                              yy.exclude_callee = 0
                      )
                      --search depth first by c.object_name_caller set sorting
                      cycle signature_callee set is_cycle to 1 default 0
                      select distinct complete_name_caller, complete_name_callee, signature_callee /*, is_cycle */ from c
                      where
                        is_cycle = 0 /*and
                        level_ < 5*/


        ) loop

           if lower(format) = 'dot' then
                  dot_call(r.complete_name_caller, r.complete_name_callee);
           else
                  gexf_call(r.complete_name_caller, r.complete_name_callee);
           end if;

        end loop;


        if lower(format) = 'dot' then
              dbms_output.put_line(chr(125));
        elsif lower(format) = 'gefx' then
              dbms_output.put_line('</edges>');
              dbms_output.put_line('</gexf>');
        end if;

    end print_downwards_graph;/*}*/

    function  find_call_path_recurse(sig_from signature_, sig_to signature_, sigs_seen in out nocopy signatures_seen_t) return boolean/*{*/
    is

      found_at_least_one boolean := false;

    begin

    counter := counter + 1;

    if counter > 1000 then
       return false;
    end if;

    -- Check if this function had already been called with the
    -- 'current' value of sig_from:
              if sigs_seen.exists(sig_from) then
              -- Yes, already been called, return so as not to
              -- recurse infinitely (or at least until there's a
              -- stack problem).
                 return false;
              end if;


    -- Mark the 'current' signature as seen, see check above:
              sigs_seen(sig_from) := 1;

              for call in (

                  select
                    complete_name_caller,
                    complete_name_callee,
                    signature_callee
                  from
                    plscope_call_v
                  where
                    signature_caller = sig_from

              ) loop


                 if call.signature_callee = sig_to then
                    dot_call(call.complete_name_caller, call.complete_name_callee);
                    found_at_least_one := true;
                 else

                    if find_call_path_recurse(call.signature_callee, sig_to, sigs_seen) then
                       dot_call(call.complete_name_caller, call.complete_name_callee);
                       found_at_least_one := true;
                    end if;

                 end if;

              end loop;

              return found_at_least_one;


    end find_call_path_recurse;/*}*/

    procedure find_call_path(sig_from signature_, sig_to signature_)/*{*/
    is
    -- Try to find a call path from a 'callable' to another 'callable',
    -- possibly via more than one hop.

              call_count number;

              sigs_seen signatures_seen_t;
              dummy boolean;
    begin


              dbms_output.put_line('digraph G {');
              dbms_output.put_line(' node [shape=plaintext fontsize=11 fontname="Arial Narrow"];');

              dummy := find_call_path_recurse(sig_from, sig_to, sigs_seen);

              dbms_output.put_line('}');


    end find_call_path;/*}*/

    procedure find_definition (/*{*/
       -- In:
       obj_ in varchar2, owner_ in varchar2, obj_typ_ in varchar2, usage_id_ in number,
       --- Out:
       sig out signature_/*, nam_ out varchar2*/
     )
    is

       wait_for_definition varchar2(30) := '?';
       wait_for_type varchar2(30) := '?';
       usage_id_l number;

    begin

       usage_id_l := usage_id_;

       while usage_id_l != 0 and (wait_for_definition != 'DEFINITION' or wait_for_type not in ('FUNCTION', 'PROCEDURE', 'CURSOR', 'PACKAGE', 'PACKAGE BODY')) loop

             select signature, usage /*, name*/, type , usage_context_id
               into sig , wait_for_definition/*, nam_*/, wait_for_type , usage_id_l
              from
                all_identifiers where usage_id    = usage_id_l and
                                      object_name = obj_       and
                                      owner       = owner_     and
                                      object_type = obj_typ_;

       end loop;

       exception when others then

        dbms_output.put_line('find_definition: obj: ' || obj_ || ' / ' || obj_typ_ || ', usage_id: ' || usage_id_ || ',' || usage_id_l);
        dbms_output.put_line('    ' || sqlerrm);

        sig := null;

    end find_definition ;/*}*/

    function  who_calls(sig_called signature_) return signature_t_ is/*{*/
        caller_sig signature_;
        ret signature_t_ := signature_t_();
    begin

        for caller in (
            select object_name, owner, object_type, usage_context_id from all_identifiers
             where signature = sig_called and
                   usage ='CALL'
        ) loop

           find_definition(
             -- In: 
                caller.object_name, 
                caller.owner,
                caller.object_type, 
                caller.usage_context_id, 
             -- Out:
                caller_sig/*, caller_nam*/);

           if caller_sig is not null then

              ret.extend;
              ret(ret.count) := caller_sig;

           else

              dbms_output.put_line('find_definition failed for ' || caller.object_name || ' ' || caller.object_type || ' ' || caller.usage_context_id || ' ' || sig_called);
   
           end if;

        end loop;

        return ret;

    end who_calls;/*}*/

    procedure gather_identifiers is/*{*/
    begin

       execute immediate q'!alter session set plscope_settings='IDENTIFIERS:ALL'!';

       for i in 1 .. 2 loop
       --
       -- For a reason I don't really understand, the loop needs to run twice,
       -- as otherwise not all identifiers are collected correctly.

           for o in (
              select object_type, object_name from user_objects
               where object_type in ('PACKAGE', 'TYPE', 'FUNCTION', 'PROCEDURE', 'TRIGGER') and
                     object_name not in ('PLSCOPE')
           ) loop
    
             begin
               execute immediate 'alter ' || o.object_type || ' ' || o.object_name || ' compile';
             exception when others then
               dbms_output.new_line;
               dbms_output.put_line (sqlerrm);
               dbms_output.put_line (' ' || o.object_name || ' (' || o.object_type || ')');
             end;
    
           end loop;

       end loop;

    end gather_identifiers;/*}*/

end plscope;
/
Github repository oracle_scriptlets, path: /plscope/body.plsql

plscope - hierarchy.sql

--
--   Displays the hierarchical relationship of identifiers
--   in a package that has been compiled with PL/Scope enabled.
--
--      alter session set plscope_settings='IDENTIFIERS:ALL'
--
--      alter package ... compile;
--
----------------

with package_identifier_hier 
  (line, col, identifier, type, usage, usage_id, usage_context_id, object_name, object_type, owner, indent)
as (
  select line, 
         col, 
         name identifier, 
         type,
         usage,
         usage_id,
         usage_context_id,
         object_name,
         object_type,
         owner,
         0 indent
    from all_identifiers 
   where owner       = user         and 
         object_name = '&OBJECT_NAME' and 
         object_type = 'PACKAGE BODY' and
         usage_context_id    =  0
      UNION ALL  
  select iteration.line, 
         iteration.col, 
         iteration.name identifier, 
         iteration.type,
         iteration.usage,
         iteration.usage_id,
         iteration.usage_context_id,
         iteration.object_name,
         iteration.object_type,
         iteration.owner,
         predecessor.indent + 1 indent
    from all_identifiers         iteration   join
         package_identifier_hier predecessor on
         predecessor.owner            = iteration.owner       and
         predecessor.object_name      = iteration.object_name and
         predecessor.object_type      = iteration.object_type and
         predecessor.usage_id         = iteration.usage_context_id
  )
select    lpad (' ', 2 * indent) || 
              identifier || ' ' || 
              lower(type) || ' (' || lower(usage) || ')'
              identifier_hierarchy
  from package_identifier_hier
order by line, col;
Github repository oracle_scriptlets, path: /plscope/hierarchy.sql

plscope - spec.plsql

create or replace package plscope as

    subtype signature_ is varchar2(32);

    type signature_t_ is table of signature_;

    procedure fill_callable(owner_ in varchar2, delete_existing in boolean);

    procedure fill_call (owner_ in varchar2, delete_existing in boolean);

    procedure print_upwards_graph   (sig signature_, format in varchar2);
    procedure print_downwards_graph (sig signature_, format in varchar2);

    -- Try to find a call path from a 'callable' to another 'callable',
    -- possibly via more than one hops.
    procedure find_call_path(sig_from signature_, sig_to signature_);

    procedure print_dot_graph;

    function  who_calls(sig_called signature_) return signature_t_;

    procedure gather_identifiers;

end plscope;
/
Github repository oracle_scriptlets, path: /plscope/spec.plsql

plscope - tables.sql

--
--   Call 'plscope.gather_identifiers' after
--   installing these tables/views in order
--   to fill 'all_identifiers'.
--
--   Then call 'plscope.fill_call'.
--


declare

   procedure drop_if_exists(name in varchar2) is -- {

       type_ varchar2(30);
   begin

       select object_type into type_ from user_objects where object_name = upper(name);

       execute immediate 
           'drop ' || type_  || ' ' || name ||
            case when type_ = 'TABLE' then ' purge' end;

   exception when no_data_found then
  
       null;
       
   end drop_if_exists; -- }

begin

   drop_if_exists ('plscope_ref_v'   );
   drop_if_exists ('plscope_call_v'  );
   drop_if_exists ('plscope_call'    );
   drop_if_exists ('plscope_callable');

end;
/


create table plscope_callable (
  signature varchar2(32) not null primary key,
  object_name varchar2(30) not null,
  name varchar2(30) not null,
  complete_name varchar2(61) as (object_name || '.' || name) virtual,
  exclude       number(1) not null check (exclude in (0,1))
);

comment on column plscope_callable.exclude is 'Flag if calls from/to this callable should be excluded when plscope.downwards / plscope.upwards is executed';

create table plscope_call (
  caller not null references plscope_callable,
  callee not null references plscope_callable
);

create view plscope_call_v as
select
             caller.object_name   object_name_caller,
             caller.name          name_caller,
             caller.complete_name complete_name_caller,
             caller.exclude       exclude_caller,
             --
             callee.object_name   object_name_callee,
             callee.name          name_callee,
             callee.complete_name complete_name_callee,
             callee.exclude       exclude_callee,
             --
             caller.signature signature_caller,
             callee.signature signature_callee
from
                     plscope_call call
             join plscope_callable caller on call.caller = caller.signature
             join plscope_callable callee on call.callee = callee.signature;



create view plscope_ref_v as with direct as (
     select '->' ion from dual union all
     select '<-' ion from dual
)
select
     case when direct.ion = '->' then object_name_caller else object_name_callee end object_name_referenced,
     case when direct.ion = '->' then name_caller else name_callee end name_referenced,
     case when direct.ion = '->' then complete_name_caller else complete_name_callee end complete_name_referenced,
     --
     direct.ion direction,
     --
     case when direct.ion = '<-' then object_name_caller else object_name_callee end object_name_references,
     case when direct.ion = '<-' then name_caller else name_callee end name_references,
     case when direct.ion = '<-' then complete_name_caller else complete_name_callee end complete_name_references
from
     plscope_call_v cross join direct;
Github repository oracle_scriptlets, path: /plscope/tables.sql

plscope - tq84_all_identifiers.sql

--
--     Workaround for a bug.
--
--     See http://dba.stackexchange.com/questions/31683/is-there-a-bug-with-pl-scope-in-combination-with-associative-arrays
--
--     Query below extracted from all_identifiers, but
--     with outer join to sys.plscope_identifier$.
--

declare procedure drop_if_exists is -- {
       type_ varchar2(30);
   begin

       select object_type into type_ from user_objects where object_name = 'TQ84_ALL_IDENTIFIERS';

       execute immediate
           'drop ' || type_  || ' tq84_all_identifiers' ||
            case when type_ = 'TABLE' then ' purge' end;

   exception when no_data_found then

       null;

   end drop_if_exists;

begin

   drop_if_exists;

end;
/



create table tq84_all_identifiers (
  owner,
  name,
  signature,
  type,
  object_name,
  object_type,
  usage,
  usage_id,
  line,
  col,
  usage_context_id,
  --
  constraint tq84_all_identifiers_pk primary key (object_name, object_type, owner, usage_id)
)
organization index
as
--insert into tq84_all_identifiers
select u.name owner, i.symrep name, i.signature,
decode(i.type#, 1, 'VARIABLE', 2, 'ITERATOR', 3, 'DATE DATATYPE',
                4, 'PACKAGE',  5, 'PROCEDURE', 6, 'FUNCTION', 7, 'FORMAL IN',
                8, 'SUBTYPE',  9, 'CURSOR', 10, 'INDEX TABLE', 11, 'OBJECT',
               12, 'RECORD', 13, 'EXCEPTION', 14, 'BOOLEAN DATATYPE', 15, 'CONSTANT',
               16, 'LIBRARY', 17, 'ASSEMBLY', 18, 'DBLINK', 19, 'LABEL',
               20, 'TABLE', 21, 'NESTED TABLE', 22, 'VARRAY', 23, 'REFCURSOR',
               24, 'BLOB DATATYPE', 25, 'CLOB DATATYPE', 26, 'BFILE DATATYPE',
               27, 'FORMAL IN OUT', 28, 'FORMAL OUT', 29, 'OPAQUE',
               30, 'NUMBER DATATYPE', 31, 'CHARACTER DATATYPE',
               32, 'ASSOCIATIVE ARRAY', 33, 'TIME DATATYPE', 34, 'TIMESTAMP DATATYPE',
               35, 'INTERVAL DATATYPE', 36, 'UROWID', 37, 'SYNONYM', 38, 'TRIGGER',
                   'UNDEFINED') type,
o.name object_name,
decode(o.type#, 5, 'SYNONYM', 7, 'PROCEDURE', 8, 'FUNCTION', 9, 'PACKAGE',
                11, 'PACKAGE BODY', 12, 'TRIGGER', 13, 'TYPE', 14, 'TYPE BODY',
                22, 'LIBRARY', 33, 'SPEC OPERATOR', 87, 'ASSEMBLY',
                'UNDEFINED') object_type,
decode(a.action, 1, 'DECLARATION', 2, 'DEFINITION', 3, 'CALL', 4, 'REFERENCE',
                 5, 'ASSIGNMENT', 'UNDEFINED') usage,
  a.action# usage_id, a.line, a.col, a.context# usage_context_id
from
  sys."_CURRENT_EDITION_OBJ" o,
  sys.plscope_identifier$ i,
  sys.plscope_action$ a,
  sys.user$ u
where i.signature (+) = a.signature
  and o.obj# = a.obj#
  and o.owner# = u.user#
  and ( o.type# in ( 5, 7, 8, 9, 11, 12, 14, 22, 33, 87) OR
       ( o.type# = 13 AND o.subname is null));


commit;

create synonym all_identifiers for tq84_all_identifiers;
Github repository oracle_scriptlets, path: /plscope/tq84_all_identifiers.sql

plscope - test - pck_a.pkb

create package body pck_a as -- {

    function foo_bar_baz return varchar2 is -- {
      v_unused number;
      v_used   varchar2(20);
    begin
      v_used := pck_c.func_c_01;

      return c_foo||c_bar||c_baz||v_used;
    end foo_bar_baz; -- }

end pck_a; -- }
/
show errors
Github repository oracle_scriptlets, path: /plscope/test/pck_a.pkb

plscope - test - pck_a.pks

create package pck_a as -- {

    c_foo    constant varchar2(3)  := 'foo';
    c_bar    constant varchar2(3)  := 'bar';
    c_baz    constant varchar2(3)  := 'baz';

    c_unused constant varchar2(10) := 'Unused';

    function foo_bar_baz return varchar2;

end pck_a; -- }
/
Github repository oracle_scriptlets, path: /plscope/test/pck_a.pks

plscope - test - pck_b.pkb

create package body pck_b as -- {

    function fun_unused return varchar2 is -- {
    begin
      return 'unused';
    end fun_unused; -- }

    function fun_another_unused return varchar2 is -- {
    begin
      return 'another unused';
    end fun_another_unused; -- }

    function fun_2 return varchar2 is -- {
      rec used_rec_t;
    begin

       select id into rec.id
         from tab_01
        where id = 1;

      return 'fun_2';
    end fun_2; -- }

    function not_really_used return varchar2 is -- {

      type rec_t is record (
          id      number,
          unused  varchar2(100)
      );

      rec rec_t;

    begin

      select id into rec.id from tab_01 where rownum = 1;

      return fun_2 || pck_a.foo_bar_baz;
    end not_really_used; -- }

end pck_b; -- }
/
show errors
Github repository oracle_scriptlets, path: /plscope/test/pck_b.pkb

plscope - test - pck_b.pks

create package pck_b as -- {

    type used_rec_t is record (
         id    tab_01.id%type,
         text  tab_01.text%type
    );

    v_unused_b  date;

    function not_really_used return varchar2;

end pck_b; -- }
/
Github repository oracle_scriptlets, path: /plscope/test/pck_b.pks

plscope - test - pck_c.pkb

create package body pck_c as -- {

    function func_c_02 return varchar2 is begin -- {
      return 'FUNC_D';
    end func_c_02; -- }

    function func_c_01 return varchar2 is begin -- {

      for r in (select * from tab_01) loop

          if    r.text = pck_a.c_foo then
                return 'X';

          elsif r.text = pck_a.c_bar then
                return 'Y';

          elsif r.text = pck_a.c_baz then
                return func_c_02;

          end if;


      end loop;

      return null;

    end func_c_01; -- }

    function func_c_trg_01  return varchar2 is begin -- called by trg_01 {
        return 'TRG_01';
    end func_c_trg_01; -- }

end pck_c; -- }
/
Github repository oracle_scriptlets, path: /plscope/test/pck_c.pkb

plscope - test - pck_c.pks

create package pck_c as -- {

    function func_c_01      return varchar2;
    function func_c_02      return varchar2;
    function func_c_trg_01  return varchar2; -- called by trg_01

end pck_c; -- }
/
Github repository oracle_scriptlets, path: /plscope/test/pck_c.pks

plscope - test - run.sql

connect / as sysdba

declare

  procedure drop_user_if_exists is
      cnt number;
  begin

      select count(*) into cnt from dba_users where username = 'TQ84_PLSCOPE_TEST';

      if cnt > 0 then
         execute immediate 'drop user tq84_plscope_test cascade';
      end if;

  end drop_user_if_exists;

begin

  drop_user_if_exists;

end;
/


create user tq84_plscope_test 
   identified by tq84_plscope_test
   default   tablespace data
   temporary tablespace temp
   quota unlimited on data;

grant
  create procedure,
  create session,
  create synonym,
  create table,
  create trigger,
  create view
  to tq84_plscope_test;

grant all on sys.all_identifiers        to tq84_plscope_test;

-- Grants needed for tq84_all_identifiers (see ../tq84_plscope_test.sql)
grant all on sys."_CURRENT_EDITION_OBJ" to tq84_plscope_test;
grant all on sys.plscope_identifier$    to tq84_plscope_test;
grant all on sys.plscope_action$        to tq84_plscope_test;
grant all on sys.user$                  to tq84_plscope_test;



connect tq84_plscope_test/tq84_plscope_test;

@tab_01.sql

@pck_a.pks
@pck_b.pks
@pck_c.pks

@pck_a.pkb
@pck_b.pkb
@pck_c.pkb

@trg_01.plsql


-- Install PL-Scope:

@@../tables.sql

@@../spec.plsql
@@../body.plsql

-- Run PL-Scope

connect tq84_plscope_test/tq84_plscope_test
exec plscope.gather_identifiers
@@../tq84_all_identifiers
commit;

-- Prevent ORA-04068: existing state of packages has been discarded
connect tq84_plscope_test/tq84_plscope_test
exec plscope.fill_call(user, true);

-- Vim Tests
@@../vim/unused_constants.sql
@@../vim/unused_functions.sql
@@../vim/unused_variables.sql


$fc unused_constants.ef unused_constants.expected
$fc unused_functions.ef unused_functions.expected
$fc unused_variables.ef unused_variables.expected
Github repository oracle_scriptlets, path: /plscope/test/run.sql

plscope - test - tab_01.sql

create table tab_01 (
  id    number,
  text  varchar2(10)
);
Github repository oracle_scriptlets, path: /plscope/test/tab_01.sql

plscope - test - trg_01.plsql

create trigger trg_01
  before insert or update on tab_01
  for each row
begin
  :new.text := pck_c.func_c_trg_01;
end trg_01;
/
Github repository oracle_scriptlets, path: /plscope/test/trg_01.plsql

plscope - test - unused_constants.expected

pck_a.pks-7-5-C_UNUSED
Github repository oracle_scriptlets, path: /plscope/test/unused_constants.expected

plscope - test - unused_functions.expected

pck_b.pks-10-14-NOT_REALLY_USED
pck_b.pkb-3-14-FUN_UNUSED
pck_b.pkb-8-14-FUN_ANOTHER_UNUSED
pck_b.pkb-24-14-NOT_REALLY_USED
Github repository oracle_scriptlets, path: /plscope/test/unused_functions.expected

plscope - test - unused_variables.expected

pck_a.pkb-4-7-V_UNUSED
pck_b.pkb-28-11-UNUSED
pck_b.pks-8-5-V_UNUSED_B
pck_b.pks-5-10-TEXT
Github repository oracle_scriptlets, path: /plscope/test/unused_variables.expected

plscope - vim - unused_constants.sql

--
--    :set efm=%f-%l-%c-%m
--    :cf unused_constants.ef
--

@spool unused_constants.ef

select distinct
  lower(x.object_name) || 
    case x.object_type 
         when 'PACKAGE BODY' then '.pkb' 
         when 'PACKAGE'      then '.pks'
    end || '-' ||
  x.line                         || '-' ||
  x.col                          || '-' ||
  x.name   t
from (
   select signature from all_identifiers where usage in ('DECLARATION') and type in ('CONSTANT') and owner = user
   minus
   select signature from all_identifiers where usage in ('REFERENCE') and owner = user
) o, all_identifiers x 
where o.signature = x.signature
order by 
  1
;

@spool_off

Github repository oracle_scriptlets, path: /plscope/vim/unused_constants.sql

plscope - vim - unused_functions.sql

--
--    :set efm=%f-%l-%c-%m
--    :cf unused_functions.ef
--
@spool unused_functions.ef

select
    lower(object_name) || 
      case object_type 
           when 'PACKAGE BODY' then '.pkb' 
           when 'PACKAGE'      then '.pks'
           when 'TYPE BODY'    then '.tyb' 
           when 'TYPE'         then '.tys'
      end || '-' ||
    line                         || '-' ||
    col                          || '-' ||
    name   t
from (
  select distinct
    x.object_name,
    x.object_type,
    x.line,
    x.col,
    x.name
  from (
     select 
       distinct signature 
     from 
       all_identifiers 
     where 
       usage       in ('DEFINITION' ,   'DECLARATION'                   )     and 
       type        in ('FUNCTION', 'PROCEDURE' /*,'CURSOR' ,'VARIABLE'*/)     and 
       object_type in ('PACKAGE', 'PACKAGE BODY')                             and
       owner = user
     minus
     select 
       signature
     from 
       all_identifiers
     where 
--     (usage = 'DECLARATION' and object_type = 'PACKAGE') or -- << Only functions that are declared in package body
--                                                            --    Comment, if all unreferenced functions are desired.
       (usage not in ('DECLARATION', 'DEFINITION'))
  ) o, 
    all_identifiers x 
  where 
    o.signature = x.signature
)
  order by 
    object_name,
    object_type,
    line,
    col;

@spool_off
Github repository oracle_scriptlets, path: /plscope/vim/unused_functions.sql

plscope - vim - unused_variables.sql

--
--    :set efm=%f-%l-%c-%m
--    :cf unused_variables.ef
--

@spool unused_variables.ef

select
  lower(object_name) || 
    case object_type 
         when 'PACKAGE BODY' then '.pkb' 
         when 'PACKAGE'      then '.pks'
         when 'TYPE BODY'    then '.tyb' 
         when 'TYPE'         then '.tys'
    end || '-' ||
  x.line                         || '-' ||
  x.col                          || '-' ||
  x.name   t
from (
   select 
     signature from all_identifiers where usage in ( 'DEFINITION', 'DECLARATION') and type in (/*'CURSOR'*/ /*'CONSTANT'?*/ 'VARIABLE') and 
  -- object_type in ('PACKAGE BODY') and
     owner = user
   minus
   select signature from all_identifiers where usage not in ('DEFINITION', 'DECLARATION')
) o, 
  all_identifiers x 
where 
  o.signature = x.signature
order by 
  x.object_name,
  x.line desc;

@spool_off
Github repository oracle_scriptlets, path: /plscope/vim/unused_variables.sql

schema_to_neato - body.plsql

create or replace package body schema_to_neato as

  type descriptions is table of desc_table.description;

  procedure print(l in varchar2) is begin
    dbms_output.put_line(l);
  end print;

  procedure add_relations(descs in descriptions) is 
    description desc_table.description;

    procedure add_relation(parent in desc_table.table_t, child in desc_table.table_t) is begin
      print('  "' || child.own || '.' || child.nam || '" -> "' || parent.own || '.' || parent.nam || '" [arrowhead=crow]');
    end add_relation;
  begin
    
    -- iterating over all table descriptions:
    for desc_no in 1 .. descs.count loop
      description := descs(desc_no);

      for child_no in 1 .. description.children.count loop
        for tab_no_i in 1 .. descs.count loop

          if descs(tab_no_i).tab.nam = description.children(child_no).nam and
             descs(tab_no_i).tab.own = description.children(child_no).own then

            add_relation(descs(tab_no_i).tab, descs(desc_no).tab);
          end if;

        end loop;
      end loop;
    end loop;
  end add_relations;

  procedure create_neato(tables in tables_t) is 
    descs descriptions := descriptions();
  begin
    print('digraph ri {'                                      );
    print('  page = "15,10";'                                 ); -- A3
    print('  overlap=false;'                                  );
    print('  splines=true;'                                   );
    print('  node [fontsize=8 fontname=Verdana shape=record];');

    for idx_table in 1 .. tables.count loop
      descs.extend;
      descs(descs.count) := desc_table.describe(tables(idx_table));
    end loop;

    add_relations(descs);
    
    print('}');
  end create_neato;

end schema_to_neato;
/
Github repository oracle_scriptlets, path: /schema_to_neato/body.plsql

schema_to_neato - spec.plsql

create or replace package schema_to_neato
  authid current_user
as 
  -- Don't confuse with desc_table.tables_t
  type tables_t is table of varchar2(61);

  procedure create_neato(tables in tables_t);
end schema_to_neato;
/
Github repository oracle_scriptlets, path: /schema_to_neato/spec.plsql

schema_to_neato - test - drop_tables.sql

drop table erd_child_2_x_erd_other purge;
drop table erd_other               purge;
drop table erd_child_2             purge;
drop table erd_child_1             purge;
drop table erd_parent              purge;
Github repository oracle_scriptlets, path: /schema_to_neato/test/drop_tables.sql

schema_to_neato - test - install_tables.sql

create table erd_parent (
  id  number primary key,
  txt varchar2(10)
);

create table erd_child_1 (
  id  number primary key,
  id_p references erd_parent,
  txt varchar2(10)
);

create table erd_child_2 (
  id  number primary key,
  id_p references erd_parent,
  txt varchar2(10)
);

create table erd_other (
  id number primary key,
  txt varchar2(10)
);

create table erd_child_2_x_erd_other (
  id_child_2 references erd_child_2,
  id_other   references erd_other,
  txt        varchar2(10)
);
Github repository oracle_scriptlets, path: /schema_to_neato/test/install_tables.sql

schema_to_neato - test - neato_from_shell.sql

--
-- Start from Shell (currently: cmd.exe) with
--   
--    sqlplus rene/rene @neato_from_shell
--

set serveroutput on size 100000 format wrapped
set feedback off
set pagesize 0
set trimspool on
set termout off
spool c:\temp\neato_created.neato
set termout on

begin
  schema_to_neato.create_neato(
    schema_to_neato.tables_t(
        'ERD_PARENT', 
        'ERD_CHILD_1',
        'ERD_CHILD_2',
        'ERD_OTHER',
        'ERD_CHILD_2_X_ERD_OTHER'
      )
  );
end;
/

spool off


$neato -Tpng -oc:\temp\erd.png c:\temp\neato_created.neato
$c:\temp\erd.png

exit
Github repository oracle_scriptlets, path: /schema_to_neato/test/neato_from_shell.sql

source_code - body.plsql

create or replace package body source_code as

  function name_from_line(p_name varchar2, p_type varchar2, p_line number, p_owner varchar2 := user) return type_and_name is
  -- original code by GARBUYA 2010 ©.
     v_obj_type        varchar2(30);
     v_curr_line       varchar2(4000);
     in_comment        boolean := false;
     it_is_literal     boolean := false;
     v_pos1            number  := 0;
     v_pos2            number  := 0;
     v_tmp_1           varchar2(4000);
     v_tmp_2           varchar2(4000);
     v_bgn_cnt         number := 0;
     v_end_cnt         number := 0;
     v_blk_cnt         number := 0;
     v_str_len         number := 0;

     v_unknown         type_and_name;
--   v_type_and_name   type_and_name;

     type num_table_t  is table of number;

     v_blk_bgn_len_tbl num_table_t := num_table_t();

     type str_table_t  is table of varchar2(256);

     v_blk_bgn_tbl     str_table_t := str_table_t (' IF '   , ' LOOP '   , ' CASE ', ' BEGIN ');

     type type_and_name_t is table of type_and_name;

     v_name_stack             type_and_name_t := type_and_name_t();

     type str_varr_t   is varray(2) of char(1);
     v_literal_arr     str_varr_t := str_varr_t ('''', '"');
   begin

   v_unknown.type_ := '?';
   v_unknown.name_ := '?';

   for v_idx in v_blk_bgn_tbl.first .. v_blk_bgn_tbl.last loop
      v_blk_bgn_len_tbl.extend(1);
      v_blk_bgn_len_tbl (v_blk_bgn_len_tbl.last) := length(v_blk_bgn_tbl(v_idx));
   end loop;

   for src in (
     select  -- {
        ' ' || replace(
                  translate(upper(text),
                           ';(' || chr(10),
                           '   '
                  ),
                  '''''',
                  ' '
               ) || ' ' text
      from
        all_source
      where
        owner = p_owner and
        name  = p_name  and
        type  = p_type  and
        line  < p_line
      order  by
        line -- }
   )
   loop -- {

     v_curr_line := src.text;

     if in_comment then -- {

        declare
          v_pos_end_comment number;
        begin

          v_pos_end_comment :=  instr (v_curr_line, '*/');

          if v_pos_end_comment > 0 then
             v_curr_line := substr (v_curr_line, v_pos_end_comment + 2);
             v_curr_line := substr (v_curr_line, v_pos1 + 2);
             in_comment := false;
          else
             v_curr_line := ' ';
          end if;
        end;

     end if; -- }

     if v_curr_line != ' ' then -- {

        declare

          v_pos_start_comment   number;
          v_pos_end_comment     number;
          v_text_before_comment varchar2(2048);
          v_text_after_comment  varchar2(2048);

        begin

          v_pos_start_comment := instr(v_curr_line, '/*');

          while v_pos_start_comment > 0 loop -- {

             v_text_before_comment := substr (v_curr_line, 1, v_pos_start_comment - 1);
             v_pos_end_comment := instr  (v_curr_line, '*/');

             if v_pos_end_comment > 0 then
                v_text_after_comment := substr (v_curr_line, v_pos_end_comment + 2);
                v_curr_line              := v_text_before_comment || v_text_after_comment;
             else
                v_curr_line    := v_text_before_comment;
                in_comment := true;
             end if;

             v_pos_start_comment := instr (v_curr_line, '/*');

          end loop; -- }

        end;

        if v_curr_line != ' ' then -- {
           v_pos1 := instr (v_curr_line, '--');

           if v_pos1 > 0 then -- {
              v_curr_line := substr (v_curr_line, 1, v_pos1 - 1);
           end if; -- }

           if v_curr_line != ' ' then -- {

              for v_idx in v_literal_arr.first .. v_literal_arr.last loop -- {

                 v_pos1 := instr (v_curr_line, v_literal_arr (v_idx) );

                 while v_pos1 > 0  loop

                    v_pos2 := instr (v_curr_line, v_literal_arr (v_idx), v_pos1 + 1);

                    if v_pos2 > 0 then

                       v_tmp_1 := substr (v_curr_line, 1, v_pos1 - 1);
                       v_tmp_2 := substr (v_curr_line, v_pos2 + 1);
                       v_curr_line := v_tmp_1 || v_tmp_2;

                    else

                       if it_is_literal then
                          v_curr_line := substr (v_curr_line, v_pos1 + 1);
                          it_is_literal := false;
                       else
                          v_curr_line := substr (v_curr_line, 1, v_pos1 - 1);
                          it_is_literal := true;
                       end if;

                    end if;

                    v_pos1 := instr (v_curr_line, v_literal_arr (v_idx) );

                 end loop;

              end loop; -- }

              if v_curr_line != ' ' then -- {

                 while instr (v_curr_line, '  ') > 0 loop
                    v_curr_line := replace(v_curr_line, '  ', ' ');
                 end loop;

                 v_curr_line := replace(v_curr_line, ' END IF '  , ' END ');
                 v_curr_line := replace(v_curr_line, ' END LOOP ', ' END ');

                 if v_curr_line != ' ' then -- {

                    v_curr_line := ' ' || v_curr_line;

                    v_pos1 := instr(v_curr_line, ' FUNCTION ') + INSTR(v_curr_line, ' PROCEDURE ');

                    if v_pos1 > 0 then -- {

                       v_obj_type := trim(substr(v_curr_line, v_pos1 + 1, 9));  -- get object type


                       v_curr_line := trim(substr(v_curr_line, v_pos1 + 10))||'  ';  -- cut object type
                       v_curr_line :=      substr(v_curr_line, 1,  instr(v_curr_line, ' ') - 1 );  -- get object name

--                     v_type_and_name.name_ := v_curr_line;
--                     v_type_and_name.type_ := v_obj_type ;


                       v_name_stack.extend;
--                     v_name_stack(v_name_stack.last) := v_type_and_name;
                       v_name_stack(v_name_stack.last ).name_  := v_curr_line;
                       v_name_stack(v_name_stack.last ).type_  := v_obj_type ;

                    end if; -- }

                    v_pos1  := 0;
                    v_pos2  := 0;
                    v_tmp_1 := v_curr_line;
                    v_tmp_2 := v_curr_line;

                    for v_idx in v_blk_bgn_tbl.first .. v_blk_bgn_tbl.last loop -- {

                       v_str_len := nvl(length(v_tmp_1),0);
                       v_tmp_1   := replace(v_tmp_1,v_blk_bgn_tbl(v_idx), null);
                       v_bgn_cnt := nvl(length(v_tmp_1), 0);
                       v_pos1    := v_pos1 + (v_str_len - v_bgn_cnt)/v_blk_bgn_len_tbl(v_idx);
                       v_str_len := nvl(length(v_tmp_2),0);
                       v_tmp_2   := replace(v_tmp_2,' END ', null);
                       v_end_cnt := nvl(length(v_tmp_2), 0);
                       v_pos2    := v_pos2 + (v_str_len - v_end_cnt)/5; --- 5 is the length(' end ') 

                    end loop; -- }

                    if v_pos1 > v_pos2 then -- {
                       v_blk_cnt := v_blk_cnt + 1; -- }
                    elsif v_pos1 < v_pos2 then -- {
                       v_blk_cnt := v_blk_cnt - 1;

                       if v_blk_cnt = 0 and v_name_stack.count > 0 then
                          v_name_stack.delete(v_name_stack.last);
                       end if;

                    end if; -- }

                 end if; -- }

              end if; -- }

           end if; -- }

        end if; -- }

     end if; -- }

   end loop; -- }

   if v_name_stack.last is null then -- {
   -- TODO: HOw can this happen?
      dbms_output.put_line('! source_code: v_name_stack.last is null');
      return v_unknown;
   end if; -- }

   return 
     case v_name_stack.last
        when 0 then  v_unknown
        else v_name_stack(v_name_stack.last)
    end;

  end name_from_line;

end source_code;
/

show errors
Github repository oracle_scriptlets, path: /source_code/body.plsql

source_code - source_code_test.plsql

create or replace package source_code_test as

  procedure p;

end source_code_test;
/

create or replace package body source_code_test as

  procedure p2 is

    procedure p3 is
    begin
      null;
    end p3;
  
  begin
    p3;
  end p2;

  /*
  procedure xyz is begin
  -- */
  procedure p1 is begin
    p2;
  end p1;

  function f1 return number is begin
     return 42;
  end f1;

  procedure p is
    n number;
  begin
    if 1 > 10 then
       p1;
    else
      n := f1;
    end if;
  end p;

end source_code_test;
/


declare

  v_line number;
  v_type varchar2(30);

  procedure test(p_type varchar2, p_name varchar2) is
    v_gotten source_code.type_and_name;
  begin
    v_gotten := source_code.name_from_line(p_name => 'SOURCE_CODE_TEST', p_type => v_type, p_line => v_line);

    if v_gotten.type_ != p_type or 
       v_gotten.name_ != p_name then
       raise_application_error(-20800, 'v_line: ' || v_line || ', gotten: ' || v_gotten.type_ || ' / ' || v_gotten.name_);
    end if;

    v_line := v_line + 1;
  end test;

begin

  v_type := 'PACKAGE BODY'; v_line := 1;

  test('?'        , '?'       );-- create or replace package body source_code_test as
  test('?'        , '?'       );-- 
  test('?'        , '?'       );--   procedure p2 is
  test('PROCEDURE', 'P2'      );-- 
  test('PROCEDURE', 'P2'      );--     procedure p3 is
  test('PROCEDURE', 'P3'      );--     begin
  test('PROCEDURE', 'P3'      );--       null;
  test('PROCEDURE', 'P3'      );--     end p3;
  test('PROCEDURE', 'P2'      );--   
  test('PROCEDURE', 'P2'      );--   begin
  test('PROCEDURE', 'P2'      );--     p3;
  test('PROCEDURE', 'P2'      );--   end p2;
  test('?'        , '?'       );-- 
  test('?'        , '?'       );--   /*
  test('?'        , '?'       );--   procedure xyz is begin
  test('?'        , '?'       );--   -- */
  test('?'        , '?'       );--   procedure p1 is begin
  test('PROCEDURE', 'P1'      );--     p2;
  test('PROCEDURE', 'P1'      );--   end p1;
  test('PROCEDURE', 'P1'      );-- 
  test('FUNCTION' , 'F1'      );--   function f1
  test('FUNCTION' , 'F1'      );--   return number
  test('FUNCTION' , 'F1'      );--   is begin return 42; end f1;
  test('FUNCTION' , 'F1'      );-- 
  test('FUNCTION' , 'F1'      );--   procedure p is
  test('PROCEDURE', 'P'       );--     n number;
  test('PROCEDURE', 'P'       );--   begin
  test('PROCEDURE', 'P'       );--     if 1 > 10 then
  test('PROCEDURE', 'P'       );--        p1;
  test('PROCEDURE', 'P'       );--     else
  test('PROCEDURE', 'P'       );--       n := f1;
  test('PROCEDURE', 'P'       );--     end if;
  test('PROCEDURE', 'P'       );--   end p;
  test('PROCEDURE', 'P'       );-- 
  test('PROCEDURE', 'P'       );-- end source_code_test;
  test('PROCEDURE', 'P'       );-- /
  test('PROCEDURE', 'P'       );
  test('PROCEDURE', 'P'       );
  
  

  v_type := 'PACKAGE'; v_line := 1;

  test('?'        , '?'       );
  test('?'        , '?'       );
  test('?'        , '?'       );

  test('PROCEDURE', 'P'       );
  test('PROCEDURE', 'P'       );
  test('PROCEDURE', 'P'       );
  test('PROCEDURE', 'P'       );

end;
/
Github repository oracle_scriptlets, path: /source_code/source_code_test.plsql

source_code - spec.plsql

create or replace package source_code as

   type type_and_name is record (
     type_  varchar2(99),
     name_  varchar2(30)
   );

   -- original code by GARBUYA 2010 ©.
   function name_from_line(p_name varchar2, p_type varchar2, p_line number, p_owner varchar2 := user) return type_and_name;

end source_code;
/
Github repository oracle_scriptlets, path: /source_code/spec.plsql

sql_snap - body.plsql

create or replace package body sql_snap as
--
--   Needs
--     grant select on sys.v_$sqlarea to <user>


  v$sql_table v$sql_table_t;

  procedure start_ is/*{*/
  --    called by ../sqlpath/sqlsnaps.sql 
  begin
      select v$sql_line_t (
--           sql_text,
             executions,
             elapsed_time,
             cpu_time,
             disk_reads,
             buffer_gets,
             address,
             hash_value
      )
      bulk collect into v$sql_table
      from sys.v_$sqlarea;

  end start_;/*}*/

  procedure end___ is/*{*/
  --    called by ../sqlpath/sqlsnape.sql 
  begin
    for line in (
        select 
          rpad(sql_text, 130) sql_text,
          executions,
          elapsed_time,
          cpu_time,
          disk_reads,
          buffer_gets
        from (
          select
            e.sql_text,
            e.executions             - nvl(s.executions  , 0)                            executions  ,
            to_char( (e.elapsed_time - nvl(s.elapsed_time, 0)) / 1000000, '9999990.00')  elapsed_time,
            to_char( (e.cpu_time     - nvl(s.cpu_time    , 0)) / 1000000, '9999990.00')  cpu_time    ,
            e.disk_reads             - nvl(s.disk_reads  , 0)                            disk_reads  ,
            e.buffer_gets            - nvl(s.buffer_gets , 0)                            buffer_gets 
          from
            sys.v_$sqlarea     e left join
            table(v$sql_table) s on e.address    = s.address and
                                    e.hash_value = s.hash_value
          where
            e.executions   - nvl(s.executions  , 0) > 0
          order by
            e.elapsed_time - nvl(s.elapsed_time, 0) desc
        ) 
        where rownum < 40
    ) loop

       dbms_output.put(        line.sql_text                  || '  ');
       dbms_output.put(to_char(line.executions  , '9999999' ) || '  ');
       dbms_output.put(        line.elapsed_time              || '  ');
       dbms_output.put(        line.cpu_time                  || '  ');
       dbms_output.put(to_char(line.disk_reads  , '9999999' ) || '  ');
       dbms_output.put(to_char(line.buffer_gets , '9999999' )        );
       dbms_output.new_line;

    end loop;

  end end___;/*}*/


end sql_snap;
/
Github repository oracle_scriptlets, path: /sql_snap/body.plsql

sql_snap - spec.plsql

create or replace package sql_snap as

  procedure start_;
  procedure end___;

end;
/
Github repository oracle_scriptlets, path: /sql_snap/spec.plsql

sql_snap - types.sql

drop type  v$sql_table_t;
drop type  v$sql_line_t;

create type v$sql_line_t is object (
--  sql_text     sys.v_$sqlarea.sql_text     %type,
    executions   number, -- sys.v_$sqlarea.executions   %type,
    elapsed_time number, -- sys.v_$sqlarea.elapsed_time %type,
    cpu_time     number, -- sys.v_$sqlarea.cpu_time     %type,
    disk_reads   number, -- sys.v_$sqlarea.disk_reads   %type,
    buffer_gets  number, -- sys.v_$sqlarea.buffer_gets  %type,
    address      raw(4), -- sys.v_$sqlarea.address      %type,
    hash_value   number  -- sys.v_$sqlarea.hash_value   %type
  )
/

create type v$sql_table_t is table of v$sql_line_t
/

Github repository oracle_scriptlets, path: /sql_snap/types.sql

svn_keyword - create_package_trg.sql

drop trigger create_package_trg;
create or replace trigger create_package_trg 
after create on schema

declare
  j number;
begin

   if ora_sysevent != 'CREATE' or ora_dict_obj_type not in ('PACKAGE', 'PACKAGE BODY', 'FUNCTION', 'PROCEDURE', 'TYPE', 'TYPE BODY') then
      return;
   end if;

  
-- Execute Insert Statement with dbms_job so that it runs in its own 
-- session and can «see» the new source text.

   dbms_job.submit(j, '
   begin
   insert into source_compilation(schema, name, type, compile_date, svn_revision, svn_date)
       select
         schema,
         name,
         type,
         sysdate,
         svn_revision,
         svn_date
       from
         svn_keywords_in_source 
       where
         type = ''' || ora_dict_obj_type || ''' and
         name = ''' || ora_dict_obj_name || ''';
    end;');

    dbms_output.put_line('j: ' || j);
      
END create_package_trg;
/
Github repository oracle_scriptlets, path: /svn_keyword/create_package_trg.sql

svn_keyword - install.sql

@source_compilation.sql
@svn_keywords_in_source.sql
@create_package_trg.sql

@test.pks

select * from svn_keywords_in_source;
select * from source_compilation;
Github repository oracle_scriptlets, path: /svn_keyword/install.sql

svn_keyword - source_compilation.sql

drop   table source_compilation;
create table source_compilation (
  schema       varchar2(30),
  name         varchar2(30),
  type         varchar2(19),
  compile_date date,
  svn_revision number,
  svn_date     date,
  --
  constraint source_compilation_cpk primary key (schema, name, type, compile_date)
) organization index
-- Make storage happy:
pctfree 0 compress
;

create public synonym source_compilation for source_compilation;
Github repository oracle_scriptlets, path: /svn_keyword/source_compilation.sql

svn_keyword - svn_keywords_in_source.sql

create or replace view svn_keywords_in_source as
select /*+ materialize */
      substr(o.owner      , 1, 10)    schema,
      substr(o.object_name, 1, 30)    name,
      o.object_type                   type,
      --
      to_number(replace(
      max(
        case when regexp_like(c.text,   '\$Revision: (\d+)')                                         then
               regexp_replace(c.text, '.*\$Revision: (\d+) .*'                          , '\1')
             when regexp_like(c.text,     '\$Id: \S* (\d+)')                                         then
               regexp_replace(c.text,   '.*\$Id: \S* (\d+).*'                           , '\1')
        end
      )
      ,chr(10),''))                                                                                                              svn_revision,
      --
      max(
        case when regexp_like(c.text,   '\$Date: (\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d)' )              then
      to_date( regexp_replace(c.text, '.*\$Date: (\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d) .*'     , '\1'), 'yyyy-mm-dd hh24:mi:ss')

             when regexp_like(c.text,   '\$Date: (\d\d\.\d\d\.\d\d \d\d:\d\d)'        )              then
      to_date( regexp_replace(c.text, '.*\$Date: (\d\d\.\d\d\.\d\d \d\d:\d\d) .*'            , '\1'), 'dd.mm.yy hh24:mi'    )

             when regexp_like(c.text,    '\$Id: \S* \d+ (\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d).*')      then
      to_date( regexp_replace(c.text,  '.*\$Id: \S* \d+ (\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d).*','\1'), 'yyyy-mm-dd hh24:mi:ss')
        end
      )                                                                                                                          svn_date
    from
      all_objects  o left join
      all_source   c on o.owner                   = c.owner and
                        o.object_type             = c.type  and
                        o.object_name             = c.name
    where
      o.object_type in (/*'TRIGGER', */'TYPE', 'TYPE BODY', 'PROCEDURE', 'FUNCTION', 'PACKAGE', 'PACKAGE BODY') and
      o.owner   not in ('SYS', 'SYSTEM', 'DBSNMP', 'OUTLN')
    group by
      substr(o.owner      , 1, 10),
      substr(o.object_name, 1, 30),
      o.object_type;
      

create public synonym svn_keywords_in_source for svn_keywords_in_source;
Github repository oracle_scriptlets, path: /svn_keyword/svn_keywords_in_source.sql

svn_keyword - test.pks

create or replace package tq84_test as

--  $Id: tq84_test.pks 15445 2014-05-16 08:12:50Z rene $

end tq84_test;
/
Github repository oracle_scriptlets, path: /svn_keyword/test.pks

trace_file - body.plsql

create or replace package body trace_file as

-- Needs
--
--     grant  
--           alter  session       ,
--           create session       ,
--           create procedure     ,
--           create sequence      ,
--           create any directory ,
--           create table         ,
--           create trigger       ,
--           drop   any directory ,
--           create public synonym
--     to <user>;
--     
--     grant select on v_$process   to <user>;
--     grant select on v_$session   to <user>;
--     grant select on v_$parameter to <user>;
--     grant select on dba_users    to <user>;
--     
--     grant execute on utl_file    to <user>;
--
-------------------------------------------------------

  trace_file_dir  varchar2(250);
  trace_file_name varchar2( 50);
  trace_file      utl_file.file_type;

  chars_read      number;
 
  procedure start_(sql_stmt in varchar2, remove_file in boolean := true) is begin/*{*/
    cur_line#  := 0;
    chars_read := 0;

    begin   -- try to create directory 'TRACE_DIR'.
    execute immediate 'create directory trace_dir as ''' || trace_file_dir || '''';
    exception when others then -- Check if directory already existed.
      if sqlcode != -955 then raise; end if;
    end;

    if remove_file then
    -- Try to remove a possibly already existing trace file.
       begin
       utl_file.fremove('TRACE_DIR', trace_file_name);
       exception when utl_file.invalid_operation then
       -- If no such file existed, utl_file will throw
       -- invalid_operation (and we need to do nothing):
          null;
       end;
    end if;

    execute immediate sql_stmt;
  end start_;/*}*/

  procedure stop__(sql_stmt in varchar2) is begin/*{*/
    execute immediate sql_stmt;

--  Print directory and name of trace file
--  dbms_output.put_line('Dir:  ' || trace_file_dir);
--  dbms_output.put_line('Name: ' || trace_file_name);

    trace_file := utl_file.fopen('TRACE_DIR', trace_file_name, 'R', max_line_len);
  end stop__;/*}*/

  function next_line(line out varchar2) return boolean is /*{*/
    -- size of newline, might be 1 on some systems
    size_nl constant number := 2;
  begin
    utl_file.get_line(trace_file, line, max_line_len);

    cur_line#  := cur_line#  + 1;
    chars_read := chars_read + nvl(length(line),0) + size_nl;

    return true;

  exception when no_data_found then 

    execute immediate 'drop directory trace_dir';
    return false;

  when others then 

    raise_application_error(-20000, 
      'Error at line: ' || cur_line#       || 
      ' for file: '     || trace_file_name ||
      ' directory: '    || trace_file_dir  ||
      ' chars read: '   || chars_read      ||
      ' message: '      || sqlerrm);

  end next_line;/*}*/

  procedure dump_block(file_no in number, block_no in number) is/*{*/
  begin
  --  http://www.adp-gmbh.ch/ora/misc/dump_block.html
    
      start_('alter system dump datafile ' || file_no || ' block ' || block_no);
      stop__('alter session set sql_trace=false');

  end dump_block;/*}*/

  procedure dump_block(row_id  in rowid) is/*{*/
  begin

      dump_block(
        file_no  => dbms_rowid.rowid_relative_fno(row_id),
        block_no => dbms_rowid.rowid_block_number(row_id)
      );

  end dump_block;/*}*/

  begin/*{*/

    select 
      u_dump .value  ,
      lower(db_name.value)  || '_ora_' ||
      proc   .spid   || 
      nvl2(proc.traceid,  '_' || proc.traceid, null) || '.trc'

    into trace_file_dir,
         trace_file_name

    from 
                 v$parameter u_dump 
      cross join v$parameter db_name
      cross join v$process   proc
            join v$session   sess
              on proc.addr = sess.paddr
    where 
     u_dump .name   = 'user_dump_dest' and 
     db_name.name   = 'db_name'        and
     sess   .audsid = sys_context('userenv','sessionid');
   /*}*/

end trace_file;
/
Github repository oracle_scriptlets, path: /trace_file/body.plsql

trace_file - spec.plsql

create or replace package trace_file

/* 
   Package trace_file (spec.plsql and body.plsql)

   Copyright (C) René Nyffenegger

   This source code is provided 'as-is', without any express or implied
   warranty. In no event will the author be held liable for any damages
   arising from the use of this software.

   Permission is granted to anyone to use this software for any purpose,
   including commercial applications, and to alter it and redistribute it
   freely, subject to the following restrictions:

   1. The origin of this source code must not be misrepresented; you must not
      claim that you wrote the original source code. If you use this source code
      in a product, an acknowledgment in the product documentation would be
      appreciated but is not required.

   2. Altered source versions must be plainly marked as such, and must not be
      misrepresented as being the original source code.

   3. This notice may not be removed or altered from any source distribution.

   René Nyffenegger rene.nyffenegger@adp-gmbh.ch

*/

  authid current_user
as

  max_line_len constant number := 32767;
  cur_line#             number         ; 

  procedure start_   (sql_stmt in varchar2, remove_file in boolean := true);
  procedure stop__   (sql_stmt in varchar2);

  function  next_line(line    out varchar2) return boolean;

  ----

  procedure dump_block(file_no in number, block_no in number);
  procedure dump_block(row_id  in rowid);

end trace_file;
/
Github repository oracle_scriptlets, path: /trace_file/spec.plsql

trace_file - todo.txt

http://hoopercharles.wordpress.com/2011/01/24/watching-consistent-gets-10200-trace-file-parser/

---
ALTER SESSION SET EVENTS '10046 trace name context forever, level 8';   
 
  http://www.hellodba.com/reader.php?ID=35&lang=en

   
Github repository oracle_scriptlets, path: /trace_file/todo.txt

trace_file - test - test_01.sql

exec trace_file.start_('alter session set sql_trace=true');

select sysdate from dual;

select count(*) from user_tables;

exec trace_file.stop__('alter session set sql_trace=false');

set serveroutput on size 1000000

declare
  line varchar2(32767);
begin

  while trace_file.next_line(line) loop
    dbms_output.put_line(to_char(trace_file.cur_line#, '9999') || ': ' || line);
  end loop;

end;
/
Github repository oracle_scriptlets, path: /trace_file/test/test_01.sql

trace_file - test - test_02.sql

--drop table trace_c;
--drop table trace_p;
--
--create table trace_p (
--  id  number primary key,
--  txt varchar2(10)
--);
--
--create table trace_c (
--  pid not null references trace_p,
--  txt varchar2(10)
--);

insert into trace_p values (1, '!!!');
insert into trace_p values (2, 'ZZZ');

insert into trace_c values (1, 'one');
insert into trace_c values (2, 'two');
insert into trace_c values (2, 'TWO');

--exec trace_file.start_('alter session set sql_trace=true');
  exec trace_file.start_(q'!alter session set events '10046 trace name context forever, level 12'!');
--exec trace_file.start_('dbms_support.start_trace(binds=>true, waits=>true)');

select max(created) from dba_objects;


--exec trace_file.stop__('alter session set sql_trace=false');
  exec trace_file.stop__(q'!alter session set events '10046 trace name context off'!');
--exec trace_file.stop__('dbms_support.stop_trace');

set serveroutput on size 1000000

declare
  line varchar2(32767);
begin

  while trace_file.next_line(line) loop
    dbms_output.put_line(to_char(trace_file.cur_line#, '9999') || ': ' || line);
  end loop;

end;
/

Github repository oracle_scriptlets, path: /trace_file/test/test_02.sql

trace_file - test - test_dump_block.sql

create table dump_block_test (
   c   number,
   txt varchar2(200)
);

declare
  row_id rowid;
  line   varchar2(32767);
begin
 
  for c in ascii('a') .. ascii('z') loop
      insert into dump_block_test values (c, lpad(chr(c), c, chr(c)));
  end loop;

  for c in ascii('A') .. ascii('Z') loop
      insert into dump_block_test values (c, lpad(chr(c), c, chr(c)));
  end loop;

  commit;

--Make sure datafile is written to file:
  execute immediate 'alter system checkpoint';

  select rowid into row_id
    from dump_block_test
   where c = ascii('Q');

  trace_file.dump_block(row_id);

  while trace_file.next_line(line) loop
    dbms_output.put_line(to_char(trace_file.cur_line#, '9999') || ': ' || line);
  end loop;

end;
/

--select * from dump_block_test;

drop table dump_block_test;
Github repository oracle_scriptlets, path: /trace_file/test/test_dump_block.sql

txt

Text formatting.
create or replace package tq84_txt as

    function rpd(txt varchar2, len_ number) return varchar2;
    function dt(d date) return varchar2;
    function num(nm number, pattern varchar2) return varchar2;

    function num(nm number, len_left_of_dot pls_integer, len_right_of_dot pls_integer := 0) return varchar2;

    function export(nm  number  ) return varchar2;
    function export(txt varchar2) return varchar2;

end tq84_txt;
/
Github repository oracle_scriptlets, path: /txt/tq84_txt.pks
create or replace package body tq84_txt as

   function rpd(txt varchar2, len_ number) return varchar2 is -- {
   begin
       if txt is null then
          return rpad(' ', len_);
       end if;
       return rpad(txt, len_);
   end rpd; -- }

   function num(nm number, pattern varchar2) return varchar2 is -- {
   begin

       if nm is null then
          return rpad(' ', length(pattern) + 1);
       end if;

       return to_char(nm, pattern);
   end num; -- }

   function num(nm number, len_left_of_dot pls_integer, len_right_of_dot pls_integer := 0) return varchar2 is -- {
      pattern varchar2(100);
   begin

     pattern := lpad('9', len_left_of_dot - 1, '9');
     pattern := pattern || '0';

     if len_right_of_dot > 0 then
        pattern := pattern || '.';
        pattern := pattern || lpad('0', len_right_of_dot, '0');
     end if;

     return num(nm, pattern);

   end num; -- }

   function dt(d date) return varchar2 is -- {
   begin
       return to_char(d, 'yyyy-mm-dd');
   end dt; -- }

   function export(nm number) return varchar2 is -- {
   begin
       if nm is null then
          return 'null';
       end if;
       return nm;
   end export; -- }

   function export(txt varchar2) return varchar2 is -- {
   begin
       if txt is null then
          return 'null';
       end if;
       return '''' || replace(txt, '''', '''''') || '''';
   end export; -- }

end tq84_txt;
/
Github repository oracle_scriptlets, path: /txt/tq84_txt.pkb

See also

Oracle Patterns
Files for SQLPATH

Index