/*REXX program determines if a (calendar) year is a SHORT or LONG year (52 or 53 weeks).*/
parse arg LO HI .                                             /*obtain optional args.   */
if LO=='' | LO=="," | LO=='*'  then LO= left( date('S'), 4)   /*Not given?  Use default.*/
if HI=='' | HI==","            then HI= LO                    /* "    "      "     "    */
if                    HI=='*'  then HI= left( date('S'), 4)   /*an asterisk ≡ current yr*/

       do j=LO  to  HI                           /*process single yr  or range of years.*/
       say '     year '  j  " is a "   right( word('short long', weeks(j)-51),5)   " year"
       end   /*j*/
exit 0                                           /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
pWeek: parse arg #;  return  (#    +    # % 4    -    # % 100    +    # % 400)     //   7
weeks: parse arg y;  if pWeek(y)==4  |  pWeek(y-1)==3  then return 53;           return 52


see "long years 2000-2099: "
for year = 2000 to 2100
    num1 = (year-1900)%7
    num2 = floor((year-1904)/4)
    num3 = (num1+num2+5)%7
    if num3 = 0 or (num1 = 6 and num3 = 1)
       see "" + year + " "
    ok
next


require 'date'

def long_year?(year = Date.today.year)
  Date.new(year, 12, 28).cweek == 53
end

(2020..2030).each{|year| puts "#{year} is long? #{ long_year?(year) }." }


extern crate time; // 0.2.16

use time::Date;

fn main() {
    (2000..=2099)
        .filter(|&year| is_long_year(year))
        .for_each(|year| println!("{}", year));
}

fn is_long_year(year: i32) -> bool {
    Date::try_from_ymd(year, 12, 28).map_or(false, |date| date.week() == 53)
}


import java.time.temporal.TemporalAdjusters.firstInMonth
import java.time.temporal.{ChronoField, IsoFields}
import java.time.{DayOfWeek, LocalDate, Month}

import scala.util.{Failure, Try}

private object LongYear extends App {
  private val (currentCentury, maxWeekNumber) = (LocalDate.now().getYear / 100, ChronoField.ALIGNED_WEEK_OF_YEAR.range().getMaximum)
  private val centuries = currentCentury * 100 until (currentCentury + 1) * 100
  private val results = List(
    centuries.filter(isThursdayFirstOrLast),
    centuries.filter(year => maxIsoWeeks(year) == maxWeekNumber),
    centuries.filter(mostThursdaysInYear)
  )

  // Solution 1, the first or respectively last day of the year is a Thursday.
  private def isThursdayFirstOrLast(_year: Int): Boolean = {

    LocalDate.of(_year, Month.DECEMBER, 31).get(ChronoField.DAY_OF_WEEK) == DayOfWeek.THURSDAY.getValue ||
    LocalDate.of(_year, Month.JANUARY, 1).get(ChronoField.DAY_OF_WEEK) == DayOfWeek.THURSDAY.getValue
  }

  // Solution 2, if last week that contains at least four days of the month of December.
  private def maxIsoWeeks(_year: Int) = {
    // The last week that contains at least four days of the month of December.
    LocalDate.of(_year, Month.DECEMBER, 28).get(IsoFields.WEEK_OF_WEEK_BASED_YEAR)
  }

  // Solution 3, if there are 52 Thursdays in a year
  private def mostThursdaysInYear(_year: Int) = {
    val datum = LocalDate.of(_year, Month.JANUARY, 1).`with`(firstInMonth(DayOfWeek.THURSDAY))

    datum.plusDays(52 * 7).getYear == _year
  }

  println(s"Years in this ${currentCentury + 1}st century having ISO week $maxWeekNumber :")

  Try { // Testing the solutions
    assert(results.tail.forall(_ == results.head), "Discrepancies in results.")
  } match {
    case Failure(ex) => Console.err.println(ex.getMessage)
    case _ =>
  }

  results.zipWithIndex.foreach(solution => println(s"Solution ${solution._2}: ${solution._1.mkString(" ")}"))

}


(define (dec31wd year)
    (remainder (apply + (map (lambda (d) (quotient year d)) '(1 4 -100 400))) 7))

(define (long? year) (or (= 4 (dec31wd year)) (= 3 (dec31wd (- year 1)))))

(display "Long years between 1800 and 2100:") (newline)
(display (filter long? (iota 300 1800)))


func is_long_year(year) {
    Date.parse("#{year}-12-28", "%Y-%m-%d").week == 53
}

say (  "Long years in the 20th century:\n", (1900..^2000).grep(is_long_year))
say ("\nLong years in the 21st century:\n", (2000..^2100).grep(is_long_year))
say ("\nLong years in the 22nd century:\n", (2100..^2200).grep(is_long_year))


               DEFINE('DEC31WD(Year)')       :(END_DEC31WD)
DEC31WD        DEC31WD = REMDR(Year + (Year / 4) - (Year / 100) + (Year / 400), 7) :(RETURN)
END_DEC31WD

               DEFINE('ISOLONG(Year)')       :(END_ISOLONG)
ISOLONG        EQ(DEC31WD(Year), 4)          :S(RETURN)
               EQ(DEC31WD(Year - 1), 3)      :S(RETURN)F(FRETURN)
END_ISOLONG

               DEFINE('ISODEMO(Start,End)')  :(END_ISODEMO)
ISODEMO        OUTPUT = 'ISO long years between ' Start ' and ' End ':'
               Year = Start
LOOP           OUTPUT = ISOLONG(Year) Year
               Year = Year + 1
               LE(YEAR, 2045)                :S(LOOP) F(RETURN)
END_ISODEMO

                ISODEMO(1995, 2045)
END


func isLongYear(_ year: Int) -> Bool {
  let year1 = year - 1
  let p = (year + (year / 4) - (year / 100) + (year / 400)) % 7
  let p1 = (year1 + (year1 / 4) - (year1 / 100) + (year1 / 400)) % 7

  return p == 4 || p1 == 3
}

for range in [1900...1999, 2000...2099, 2100...2199] {
  print("\(range): \(range.filter(isLongYear))")
}


## Reference: https://en.wikipedia.org/wiki/ISO_week_date#Weeks_per_year

proc p {year} {
    return [expr {($year + ($year/4) - ($year/100) + ($year/400)) % 7}]
}

proc is_long_year {year} {
    return [expr {[p $year] == 4 || [p [expr {$year - 1}]] == 3}]
}

proc print_long_years {from to} {
    for {set year $from; set count 0} {$year <= $to} {incr year} {
        if {[is_long_year $year]} {
            if {$count > 0} {
                puts -nonewline [expr {($count % 10 == 0) ? "\n" : " "}]
            }
            puts -nonewline $year
            incr count
        }
    }
}

puts "Long years between 1800 and 2100:"
print_long_years 1800 2100
puts ""


module "iso-long-years" {
  source = "./iso-long-years"
  start_year = 1995
  end_year = 2045
}

output "long-years" {
   value = module.iso-long-years.long-years
}


const isLongYear = (year: number): boolean => {
  const jan1: Date = new Date(year, 0, 1);
  const dec31: Date = new Date(year, 11, 31);
  return (4 == jan1.getDay() || 4 == dec31.getDay())
}

for (let y: number = 1995; y <= 2045; y++) {
  if (isLongYear(y)) {
    console.log(y)
  }
}


long_year() {
  cal 1 $1 | grep -q ' 3 *$' && return 0
  cal 12 $1 | grep -q ' 26 *$'
}


Option Explicit

Function IsLongYear(ByVal Year As Integer) As Boolean
  Select Case vbThursday
  Case VBA.DatePart("w", VBA.DateSerial(Year, 1, 1)), _
       VBA.DatePart("w", VBA.DateSerial(Year, 12, 31))
    IsLongYear = True
  End Select
End Function

Sub Main()
'test
Dim l As Long
  For l = 1990 To 2021
    Select Case l
    Case 1992, 1998, 2004, 2009, 2015, 2020
      Debug.Assert IsLongYear(l)
    Case Else
      Debug.Assert Not IsLongYear(l)
    End Select
  Next l
End Sub


import "/date" for Date

var centuries = ["20th", "21st", "22nd"]
var starts = [1900, 2000, 2100]
for (i in 0...centuries.count) {
    var longYears = []
    System.print("\nLong years in the %(centuries[i]) century:")
    for (j in starts[i]...starts[i]+100) {
        var t = Date.new(j, 12, 28)
        if (t.weekOfYear[1] == 53) {
            longYears.add(j)
        }
    }
    System.print(longYears)
}


\Long year
code Rem=2, CrLf=9, IntIn=10, IntOut=11, Text=12, Clear=40;
integer S, E, Y;

  function integer Weekday(Y);
  \Weekday of Y-12-31, 0 Sunday
  integer Y;
  return Rem((Y + Y / 4 - Y / 100 + Y / 400) / 7);

  function integer IsLongYear(Y);
  integer Y;
  return 4 = Weekday(Y) ! 3 = Weekday(Y - 1);

begin
Clear;
Text(0, "****     List of ISO long years     ****");
CrLf(0);
Text(0, "Start year: "); S:= IntIn(0);
Text(0, "End year: "); E:= IntIn(0);
CrLf(0);
for Y:= S, E do
  if IsLongYear(Y) then [IntOut(0, Y); Text(0, " ")];
CrLf(0);
end


fcn isLongYear(y){ Time.Date.weeksInYear(y)==53 }
foreach nm,y in (T(T("20th",1900), T("21st",2000), T("22nd",2100))){
   println("\nLong years in the %s century:\n%s".fmt(nm,
      [y..y+99].filter(isLongYear).concat(" ")));
}


F sieve(limit)
   [Int] primes
   V c = [0B] * (limit + 1)
   V p = 3
   L
      V p2 = p * p
      I p2 > limit
         L.break
      L(i) (p2 .< limit).step(2 * p)
         c[i] = 1B
      L
         p += 2
         I !c[p]
            L.break

   L(i) (3 .< limit).step(2)
      I !(c[i])
         primes.append(i)
   R primes

F findPeriod(n)
   V r = 1
   L(i) 1 .< n
      r = (10 * r) % n
   V rr = r
   V period = 0
   L
      r = (10 * r) % n
      period++
      I r == rr
         L.break
   R period

V primes = sieve(64000)
[Int] longPrimes
L(prime) primes
   I findPeriod(prime) == prime - 1
      longPrimes.append(prime)
V numbers = [500, 1000, 2000, 4000, 8000, 16000, 32000, 64000]
V count = 0
V index = 0
V totals = [0] * numbers.len
L(longPrime) longPrimes
   I longPrime > numbers[index]
      totals[index] = count
      index++
   count++
totals.last = count
print(‘The long primes up to 500 are:’)
print(String(longPrimes[0 .< totals[0]]).replace(‘,’, ‘’))
print("\nThe number of long primes up to:")
L(total) totals
   print(‘  #5 is #.’.format(numbers[L.index], total))


on sieveOfEratosthenes(limit)
    script o
        property numberList : {missing value}
    end script

    repeat with n from 2 to limit
        set end of o's numberList to n
    end repeat
    repeat with n from 2 to (limit ^ 0.5 div 1)
        if (item n of o's numberList is n) then
            repeat with multiple from (n * n) to limit by n
                set item multiple of o's numberList to missing value
            end repeat
        end if
    end repeat

    return o's numberList's numbers
end sieveOfEratosthenes

on factors(n)
    set output to {}

    if (n < 0) then set n to -n
    set sqrt to n ^ 0.5
    set limit to sqrt div 1
    if (limit = sqrt) then
        set end of output to limit
        set limit to limit - 1
    end if
    repeat with i from limit to 1 by -1
        if (n mod i is 0) then
            set beginning of output to i
            set end of output to n div i
        end if
    end repeat

    return output
end factors

on isLongPrime(n)
    if (n < 3) then return false
    script o
        property f : factors(n - 1)
    end script

    set counter to 0
    repeat with fi in o's f
        set fi to fi's contents
        set e to 1
        set base to 10
        repeat until (fi = 0)
            if (fi mod 2 = 1) then set e to e * base mod n
            set base to base * base mod n
            set fi to fi div 2
        end repeat
        if (e = 1) then
            set counter to counter + 1
            if (counter > 1) then exit repeat
        end if
    end repeat

    return (counter = 1)
end isLongPrime

-- Task code:
on longPrimesTask()
    script o
        -- The isLongPrime() handler above returns the correct result for any number
        -- passed to it, but feeeding it only primes in the first place speeds things up.
        property primes : sieveOfEratosthenes(64000)
        property longs : {}
    end script

    set output to {}
    set counter to 0
    set mileposts to {500, 1000, 2000, 4000, 8000, 16000, 32000, 64000}
    set m to 1
    set nextMilepost to beginning of mileposts
    set astid to AppleScript's text item delimiters
    repeat with p in o's primes
        set p to p's contents
        if (isLongPrime(p)) then
            -- p being odd, it's never exactly one of the even mileposts.
            if (p < 500) then
                set end of o's longs to p
            else if (p > nextMilepost) then
                if (nextMilepost = 500) then
                    set AppleScript's text item delimiters to space
                    set end of output to "Long primes up to 500:"
                    set end of output to o's longs as text
                end if
                set end of output to "Number of long primes up to " & nextMilepost & ":  " & counter
                set m to m + 1
                set nextMilepost to item m of mileposts
            end if
            set counter to counter + 1
        end if
    end repeat
    set end of output to "Number of long primes up to " & nextMilepost & ":  " & counter
    set AppleScript's text item delimiters to linefeed
    set output to output as text
    set AppleScript's text item delimiters to astid

    return output
end longPrimesTask

longPrimesTask()


#include <stdio.h>
#include <stdlib.h>

#define TRUE 1
#define FALSE 0

typedef int bool;

void sieve(int limit, int primes[], int *count) {
    bool *c = calloc(limit + 1, sizeof(bool)); /* composite = TRUE */
    /* no need to process even numbers */
    int i, p = 3, p2, n = 0;
    p2 = p * p;
    while (p2 <= limit) {
        for (i = p2; i <= limit; i += 2 * p)
            c[i] = TRUE;
        do {
            p += 2;
        } while (c[p]);
        p2 = p * p;
    }
    for (i = 3; i <= limit; i += 2) {
        if (!c[i]) primes[n++] = i;
    }
    *count = n;
    free(c);
}

/* finds the period of the reciprocal of n */
int findPeriod(int n) {
    int i, r = 1, rr, period = 0;
    for (i = 1; i <= n + 1; ++i) {
        r = (10 * r) % n;
    }
    rr = r;
    do {
        r = (10 * r) % n;
        period++;
    } while (r != rr);
    return period;
}

int main() {
    int i, prime, count = 0, index = 0, primeCount, longCount = 0, numberCount;
    int *primes, *longPrimes, *totals;
    int numbers[] = {500, 1000, 2000, 4000, 8000, 16000, 32000, 64000};

    primes = calloc(6500, sizeof(int));
    numberCount = sizeof(numbers) / sizeof(int);
    totals = calloc(numberCount, sizeof(int));
    sieve(64000, primes, &primeCount);
    longPrimes = calloc(primeCount, sizeof(int));
    /* Surely longCount < primeCount */
    for (i = 0; i < primeCount; ++i) {
        prime = primes[i];
        if (findPeriod(prime) == prime - 1) {
            longPrimes[longCount++] = prime;
        }
    }
    for (i = 0; i < longCount; ++i, ++count) {
        if (longPrimes[i] > numbers[index]) {
            totals[index++] = count;
        }
    }
    totals[numberCount - 1] = count;
    printf("The long primes up to %d are:\n", numbers[0]);
    printf("[");
    for (i = 0; i < totals[0]; ++i) {
        printf("%d ", longPrimes[i]);
    }
    printf("\b]\n");

    printf("\nThe number of long primes up to:\n");
    for (i = 0; i < 8; ++i) {
        printf("  %5d is %d\n", numbers[i], totals[i]);
    }
    free(totals);
    free(longPrimes);
    free(primes);
    return 0;
}


using System;
using System.Collections.Generic;
using System.Linq;

public static class LongPrimes
{
    public static void Main() {
        var primes = SomePrimeGenerator.Primes(64000).Skip(1).Where(p => Period(p) == p - 1).Append(99999);
        Console.WriteLine(string.Join(" ", primes.TakeWhile(p => p <= 500)));
        int count = 0, limit = 500;
        foreach (int prime in primes) {
            if (prime > limit) {
                Console.WriteLine($"There are {count} long primes below {limit}");
                limit *= 2;
            }
            count++;
        }

        int Period(int n) {
            int r = 1, rr;
            for (int i = 0; i <= n; i++) r = 10 * r % n;
            rr = r;
            for (int period = 1;; period++) {
                r = (10 * r) % n;
                if (r == rr) return period;
            }
        }
    }

}

static class SomePrimeGenerator {

    public static IEnumerable<int> Primes(int lim) {
        bool [] flags = new bool[lim + 1]; int j = 2;
        for (int d = 3, sq = 4; sq <= lim; j++, sq += d += 2)
            if (!flags[j]) {
                yield return j; for (int k = sq; k <= lim; k += j)
                    flags[k] = true;
            }
        for (; j<= lim; j++) if (!flags[j]) yield return j;
    }
}


#include <iomanip>
#include <iostream>
#include <list>
using namespace std;

void sieve(int limit, list<int> &primes)
{
  bool *c = new bool[limit + 1];
  for (int i = 0; i <= limit; i++)
    c[i] = false;
  // No need to process even numbers
  int p = 3, n = 0;
  int p2 = p * p;
  while (p2 <= limit)
  {
    for (int i = p2; i <= limit; i += 2 * p)
      c[i] = true;
    do
      p += 2;
    while (c[p]);
    p2 = p * p;
  }
  for (int i = 3; i <= limit; i += 2)
    if (!c[i])
      primes.push_back(i);
  delete [] c;
}

// Finds the period of the reciprocal of n
int findPeriod(int n)
{
  int r = 1, rr, period = 0;
  for (int i = 1; i <= n + 1; ++i)
    r = (10 * r) % n;
  rr = r;
  do
  {
    r = (10 * r) % n;
    period++;
  }
  while (r != rr);
  return period;
}

int main()
{
  int count = 0, index = 0;
  int numbers[] = {500, 1000, 2000, 4000, 8000, 16000, 32000, 64000};
  list<int> primes;
  list<int> longPrimes;
  int numberCount = sizeof(numbers) / sizeof(int);
  int *totals = new int[numberCount];
  cout << "Please wait." << endl << endl;
  sieve(64000, primes);
  for (list<int>::iterator iterPrime = primes.begin();
    iterPrime != primes.end();
    iterPrime++)
  {
    if (findPeriod(*iterPrime) == *iterPrime - 1)
      longPrimes.push_back(*iterPrime);
  }

  for (list<int>::iterator iterLongPrime = longPrimes.begin();
    iterLongPrime != longPrimes.end();
    iterLongPrime++)
  {
    if (*iterLongPrime > numbers[index])
      totals[index++] = count;
        ++count;
  }
  totals[numberCount - 1] = count;
  cout << "The long primes up to " << totals[0] << " are:" << endl;
  cout << "[";
  int i = 0;
  for (list<int>::iterator iterLongPrime = longPrimes.begin();
    iterLongPrime != longPrimes.end() && i < totals[0];
    iterLongPrime++, i++)
  {
    cout << *iterLongPrime << " ";
  }
  cout << "\b]" << endl;
  cout << endl << "The number of long primes up to:" << endl;
  for (int i = 0; i < 8; ++i)
    cout << "  " << setw(5) << numbers[i] << " is " << totals[i] << endl;
  delete [] totals;
}


; Primality test using the Sieve of Eratosthenes with a couple minor optimizations
(defun primep (n)
   (cond ((and (<= n 3) (> n 1)) t)
         ((some #'zerop (mapcar (lambda (d) (mod n d)) '(2 3))) nil)
         (t (loop for i = 5 then (+ i 6)
                while (<= (* i i) n)
                 when (some #'zerop (mapcar (lambda (d) (mod n (+ i d))) '(0 2))) return nil
              finally (return t)))))

; Translation of the long-prime algorithm from the Raku solution
(defun long-prime-p (n)
  (cond
    ((< n 3) nil)
    ((not (primep n)) nil)
    (t (let* ((rr (loop repeat (1+ n)
                           for r = 1 then (mod (* 10 r) n)
                       finally (return r)))

              (period (loop for p = 0 then (1+ p)
                            for r = (mod (* 10 rr) n) then (mod (* 10 r) n)
                          while (and (< p n) (/= r rr))
                        finally (return (1+ p)))))

         (= period (1- n))))))

(format t "~{~a~^, ~}" (loop for n from 1 to 500 if (long-prime-p n) collect n))


require "big"

def prime?(n)                     # P3 Prime Generator primality test
  return n | 1 == 3 if n < 5      # n: 2,3|true; 0,1,4|false
  return false if n.gcd(6) != 1   # this filters out 2/3 of all integers
  pc = typeof(n).new(5)           # first P3 prime candidates sequence value
  until pc*pc > n
    return false if n % pc == 0 || n % (pc + 2) == 0  # if n is composite
    pc += 6                       # 1st prime candidate for next residues group
  end
  true
end

# The smallest divisor d of p-1 such that 10^d = 1 (mod p),
# is the length of the period of the decimal expansion of 1/p.
def long_prime?(p)
  return false unless prime? p
  (2...p).each do |d|
    return d == (p - 1) if (p - 1) % d == 0 && (10.to_big_i ** d) % p == 1
  end
  false
end

start = Time.monotonic  # time of starting
puts "Long primes ≤ 500:"
(2..500).each { |pc| print "#{pc} " if long_prime? pc }
puts
[500, 1000, 2000, 4000, 8000, 16000, 32000, 64000].each do |n|
  puts "Number of long primes ≤ #{n}: #{(7..n).count { |pc| long_prime? pc }}"
end
puts "\nTime: #{(Time.monotonic - start).total_seconds} secs"


// Return true if prime n is a long prime. Nigel Galloway: September 25th., 2018
let fN n g = let rec fN i g e l = match e with | 0UL                -> i
                                               | _ when e%2UL = 1UL -> fN ((i*g)%l) ((g*g)%l) (e/2UL) l
                                               | _                  -> fN i ((g*g)%l) (e/2UL) l
             fN 1UL 10UL (uint64 g) (uint64 n)
let isLongPrime n=Seq.length (factors (n-1) |> Seq.filter(fun g->(fN n g)=1UL))=1


USING: formatting fry io kernel math math.functions math.primes
math.primes.factors memoize prettyprint sequences ;
IN: rosetta-code.long-primes

: period-length ( p -- len )
    [ 1 - divisors ] [ '[ 10 swap _ ^mod 1 = ] ] bi find nip ;

MEMO: long-prime? ( p -- ? ) [ period-length ] [ 1 - ] bi = ;

: .lp<=500 ( -- )
    500 primes-upto [ long-prime? ] filter
    "Long primes <= 500:" print [ pprint bl ] each nl ;

: .#lp<=n ( n -- )
    dup primes-upto [ long-prime? t = ] count swap
    "%-4d long primes <= %d\n" printf ;

: long-primes-demo ( -- )
    .lp<=500 nl
    { 500 1,000 2,000 4,000 8,000 16,000 32,000 64,000 }
    [ .#lp<=n ] each ;

MAIN: long-primes-demo


: prime? ( n -- ? ) here + [email protected] 0= ;
: notprime! ( n -- ) here + 1 swap c! ;

: sieve ( n -- )
  here over erase
  0 notprime!
  1 notprime!
  2
  begin
    2dup dup * >
  while
    dup prime? if
      2dup dup * do
        i notprime!
      dup +loop
    then
    1+
  repeat
  2drop ;

: modpow { c b a -- a^b mod c }
  c 1 = if 0 exit then
  1
  a c mod to a
  begin
    b 0>
  while
    b 1 and 1 = if
      a * c mod
    then
    a a * c mod to a
    b 2/ to b
  repeat ;

: divide_out ( n1 n2 -- n )
  begin
    2dup mod 0=
  while
    tuck / swap
  repeat drop ;

: long_prime? ( n -- ? )
  dup prime? invert if drop false exit then
  10 over mod 0= if drop false exit then
  dup 1-
  2 >r
  begin
    over [email protected] dup * >
  while
    [email protected] prime? if
      dup [email protected] mod 0= if
        over dup 1- [email protected] / 10 modpow 1 = if
          2drop rdrop false exit
        then
        [email protected] divide_out
      then
    then
    r> 1+ >r
  repeat
  rdrop
  dup 1 = if 2drop true exit then
  over 1- swap / 10 modpow 1 <> ;

: next_long_prime ( n -- n )
  begin 2 + dup long_prime? until ;

500    constant limit1
512000 constant limit2

: main
  limit2 1+ sieve
  limit2 limit1 3
  0 >r
  ." Long primes up to " over 1 .r ." :" cr
  begin
    2 pick over >
  while
    next_long_prime
    dup limit1 < if dup . then
    dup 2 pick > if
      over limit1 = if cr then
      ." Number of long primes up to " over 6 .r ." : " [email protected] 5 .r cr
      swap 2* swap
    then
    r> 1+ >r
  repeat
  2drop drop rdrop ;

main
bye


' version 01-02-2019
' compile with: fbc -s console

Dim Shared As UByte prime()

Sub find_primes(n As UInteger)

    ReDim prime(n)
    Dim As UInteger i, k

    ' need only to consider odd primes, 2 has no repetion
    For i = 3 To n Step 2
        If prime(i) = 0 Then
            For k = i * i To n Step i + i
                prime(k) = 1
            Next
        End If
    Next

End Sub

Function find_period(p As UInteger) As UInteger
    ' finds period for every positive number
    Dim As UInteger period, r = 1

    Do
        r = (r * 10) Mod p
        period += 1
        If r <= 1 Then Return period
    Loop

End Function

' ------=< MAIN >=------

#Define max 64000
Dim As UInteger p = 3, n1 = 3, n2 = 500, i, n50, count

find_primes(max)
Print "Long primes upto 500 are ";

For i = n1 To n2 Step 2
    If prime(i) = 0 Then
        If i -1 = find_period(i) Then
            If n50 <= 50 Then
                Print Str(i); " ";
            End If
            count += 1
        End If
    End If
Next

Print : Print

Do
    Print "There are "; Str(count); " long primes upto "; Str(n2)

    n1 = n2 +1
    n2 += n2
    If n1 > max Then Exit Do

    For i = n1 To n2 Step 2
        If prime(i) = 0 Then
            If i -1 = find_period(i) Then
                count += 1
            End If
        End If
    Next
Loop

' empty keyboard buffer
While Inkey <> "" : Wend
Print : Print "hit any key to end program"
Sleep
End


package main

import "fmt"

func sieve(limit int) []int {
    var primes []int
    c := make([]bool, limit + 1) // composite = true
    // no need to process even numbers
    p := 3
    p2 := p * p
    for p2 <= limit {
        for i := p2; i <= limit; i += 2 * p {
            c[i] = true
        }
        for ok := true; ok; ok = c[p] {
            p += 2
        }
        p2 = p * p
    }
    for i := 3; i <= limit; i += 2 {
        if !c[i] {
            primes = append(primes, i)
        }
    }
    return primes
}

// finds the period of the reciprocal of n
func findPeriod(n int) int {
    r := 1
    for i := 1; i <= n + 1; i++ {
        r = (10 * r) % n
    }
    rr := r
    period := 0
    for ok := true; ok; ok = r != rr {
        r = (10 * r) % n
        period++
    }
    return period
}

func main() {
    primes := sieve(64000)
    var longPrimes []int
    for _, prime := range primes {
        if findPeriod(prime) == prime - 1 {
            longPrimes = append(longPrimes, prime)
        }
    }
    numbers := []int{500, 1000, 2000, 4000, 8000, 16000, 32000, 64000}
    index := 0
    count := 0
    totals := make([]int, len(numbers))
    for _, longPrime := range longPrimes {
        if longPrime > numbers[index] {
            totals[index] = count
            index++
        }
        count++
    }
    totals[len(numbers)-1] = count
    fmt.Println("The long primes up to", numbers[0], "are: ")
    fmt.Println(longPrimes[:totals[0]])

    fmt.Println("\nThe number of long primes up to: ")
    for i, total := range totals {
        fmt.Printf("  %5d is %d\n", numbers[i], total)
    }
}


import Data.List (elemIndex)

longPrimesUpTo :: Int -> [Int]
longPrimesUpTo n =
  filter isLongPrime $
    takeWhile (< n) primes
  where
    sieve (p : xs) = p : sieve [x | x <- xs, x `mod` p /= 0]
    primes = sieve [2 ..]
    isLongPrime n = found
      where
        cycles = take n (iterate ((`mod` n) . (10 *)) 1)
        index = elemIndex (head cycles) $ tail cycles
        found = case index of
          (Just i) -> n - i == 2
          _ -> False

display :: Int -> IO ()
display n =
  if n <= 64000
    then do
      putStrLn
        ( show n <> " is "
            <> show (length $ longPrimesUpTo n)
        )
      display (n * 2)
    else pure ()

main :: IO ()
main = do
  let fiveHundred = longPrimesUpTo 500
  putStrLn
    ( "The long primes up to 35 are:\n"
        <> show fiveHundred
        <> "\n"
    )
  putStrLn ("500 is " <> show (length fiveHundred))
  display 1000


import java.util.LinkedList;
import java.util.List;

public class LongPrimes
{
    private static void sieve(int limit, List<Integer> primes)
    {
        boolean[] c = new boolean[limit];
        for (int i = 0; i < limit; i++)
            c[i] = false;
        // No need to process even numbers
        int p = 3, n = 0;
        int p2 = p * p;
        while (p2 <= limit)
        {
            for (int i = p2; i <= limit; i += 2 * p)
                c[i] = true;
            do
                p += 2;
            while (c[p]);
            p2 = p * p;
        }
        for (int i = 3; i <= limit; i += 2)
            if (!c[i])
                primes.add(i);
    }

    // Finds the period of the reciprocal of n
    private static int findPeriod(int n)
    {
        int r = 1, period = 0;
        for (int i = 1; i < n; i++)
            r = (10 * r) % n;
        int rr = r;
        do
        {
            r = (10 * r) % n;
            ++period;
        }
        while (r != rr);
        return period;
    }

    public static void main(String[] args)
    {
        int[] numbers = new int[]{500, 1000, 2000, 4000, 8000, 16000, 32000, 64000};
        int[] totals = new int[numbers.length];
        List<Integer> primes = new LinkedList<Integer>();
        List<Integer> longPrimes = new LinkedList<Integer>();
        sieve(64000, primes);
        for (int prime : primes)
            if (findPeriod(prime) == prime - 1)
                longPrimes.add(prime);
        int count = 0, index = 0;
        for (int longPrime : longPrimes)
        {
            if (longPrime > numbers[index])
                totals[index++] = count;
            ++count;
        }
        totals[numbers.length - 1] = count;
        System.out.println("The long primes up to " + numbers[0] + " are:");
        System.out.println(longPrimes.subList(0, totals[0]));
        System.out.println();
        System.out.println("The number of long primes up to:");
        for (int i = 0; i <= 7; i++)
            System.out.printf("  %5d is %d\n", numbers[i], totals[i]);
    }
}


def count(s): reduce s as $x (0; .+1);

# Is the input integer a prime?
# "previous" should be a sorted array of consecutive primes
# from 2 on that includes the greatest prime less than (.|sqrt)
def is_prime(previous):
  . as $in
  | (($in + 1) | sqrt) as $sqrt
  | first(previous[]
          | if . > $sqrt then 1
            elif 0 == ($in % .) then 0
            else empty
            end) // 1
  | . == 1;

# This assumes . is an array of consecutive primes beginning with [2,3]
def next_prime:
  . as $previous
  | (2 +  .[-1] )
  | until(is_prime($previous); . + 2) ;

# Emit primes from 2 up
def primes:
  # The helper function has arity 0 for TCO
  # It expects its input to be an array of previously found primes, in order:
  def next:
     . as $previous
     | ($previous|next_prime) as $next
     | $next, (($previous + [$next]) | next) ;
  2, 3, ([2,3] | next);


using Primes

function divisors(n)
    f = [one(n)]
    for (p,e) in factor(n)
        f = reduce(vcat, [f*p^j for j in 1:e], init=f)
    end
    return length(f) == 1 ? [one(n), n] : sort!(f)
end

function islongprime(p)
    for i in divisors(p-1)
        if powermod(10, i, p) == 1
            return i + 1 == p
        end
    end
    false
end

println("Long primes ≤ 500: ")
for i in 2:500
    if islongprime(i)
        i == 229 ? println(i) : print(i, "  ")
    end
end
print("\n\n")

for i in [500, 1000, 2000, 4000, 8000, 16000, 32000, 64000]
    println("Number of long primes ≤ $i: $(sum(map(x->islongprime(x), 1:i)))")
end


// Version 1.2.60

fun sieve(limit: Int): List<Int> {
    val primes = mutableListOf<Int>()
    val c = BooleanArray(limit + 1)  // composite = true
    // no need to process even numbers
    var p = 3
    var p2 = p * p
    while (p2 <= limit) {
        for (i in p2..limit step 2 * p) c[i] = true
        do {
            p += 2
        } while (c[p])
        p2 = p * p
    }
    for (i in 3..limit step 2) {
        if (!c[i]) primes.add(i)
    }
    return primes
}

// finds the period of the reciprocal of n
fun findPeriod(n: Int): Int {
    var r = 1
    for (i in 1..n + 1) r = (10 * r) % n
    val rr = r
    var period = 0
    do {
        r = (10 * r) % n
        period++
    } while (r != rr)
    return period
}

fun main(args: Array<String>) {
    val primes = sieve(64000)
    val longPrimes = mutableListOf<Int>()
    for (prime in primes) {
        if (findPeriod(prime) == prime - 1) {
            longPrimes.add(prime)
        }
    }
    val numbers = listOf(500, 1000, 2000, 4000, 8000, 16000, 32000, 64000)
    var index = 0
    var count = 0
    val totals = IntArray(numbers.size)
    for (longPrime in longPrimes) {
        if (longPrime > numbers[index]) {
            totals[index++] = count
        }
        count++
    }
    totals[numbers.lastIndex] = count
    println("The long primes up to " + numbers[0] + " are:")
    println(longPrimes.take(totals[0]))

    println("\nThe number of long primes up to:")
    for ((i, total) in totals.withIndex()) {
        System.out.printf("  %5d is %d\n", numbers[i], total)
    }
}


Module LongPrimes {
      Sieve=lambda (limit)->{
            Flush
            Buffer clear c as byte*limit+1
            \\ no need to process even numbers
            p=3
            do
                  p2=p^2
                  if p2>limit then exit
                  i=p2
                  while i<=limit
                        Return c, i:=1
                        i+=2*p
                  end While
                  do
                  p+=2
                  Until not eval(c,p)
            always
            for i = 3 to limit step 2
              if  eval(c,i) else data i
            next i
       }
      findPeriod=lambda (n) -> {
            r = 1
            for i = 1 to n+1 {r = (10 * r) mod n}
            rr = r : period = 0
            do
                    r = (10 * r) mod n
                    period++
                    if r == rr then exit
            always
            =period
      }
      Call sieve(64000)  ' leave stack with primes
      stops=(500,1000,2000,4000,8000,16000,32000,64000)
      acc=0
      stp=0
      limit=array(stops, stp)
      p=number  ' pop one
      Print "Long primes up to 500:"
      document lp500$
      for i=1 to 500
            if i=p then
                  if findPeriod(i)=i-1 then acc++ :lp500$=str$(i)
                  p=number
            end if
            if empty then exit for
      next i
      lp500$="]"
      insert 1,1 lp500$="["
      Print lp500$
      Print
      i=500
      Print "The number of long primes up to:"
      print i," is ";acc
      stp++
      m=each(stops,1,-2)
      while m
            for i=array(m)+1 to array(m,m^+1)
                  if i=p then
                        if findPeriod(i)=i-1 then acc++
                        p=number
                  end if
                  if empty then exit for
            next i
            print array(m,m^+1)," is ";acc
      end While
}
LongPrimes


with(NumberTheory):
with(ArrayTools):

isLong := proc(x::integer)
 if irem(10^(x - 1) - 1, x) = 0 then
  for local count from 1 to x - 2 do
   if irem(10^(count) - 1, x) = 0 then
    return false;
   end if;
  end do;
 else
  return false;
 end if;
  return true;
end proc:

longPrimes := Array([]):

for number from 1 to PrimeCounting(500) do
 if isLong(ithprime(number)) then Append(longPrimes, ithprime(number)): end if:
end:

longPrimes;
lpcount := ArrayNumElems(longPrimes):
numOfLongPrimes := Array([lpcount]):
for expon from 1 to 7 do
 for number from PrimeCounting(500 * 2^(expon - 1)) + 1 to PrimeCounting(500 * 2^expon) do
  if isLong(ithprime(number)) then lpcount += 1: end if:
 end:
 Append(numOfLongPrimes, lpcount):
end:

numOfLongPrimes;


lPrimes[n_] := Select[Range[2, n], Length[RealDigits[1/#][[1, 1]]] == # - 1 &];
lPrimes[500]
Length /@ lPrimes /@ ( 250*2^Range[8])


;;;	Using the fact that 10 has to be a primitive root mod p
;;;	for p to be a reptend/long prime.
;;;	p supposed prime and >= 7
(define (cycle-mod p)
	(let (n 10 tally 1)
		(while (!= n 1)
			(++ tally)
			(setq n (% (* n 10) p))
			tally)))
;
;;;	Primality test
(define (prime? n)
	(= (length (factor n)) 1))
;
;;;	Reptend test (p >= 7)
(define (reptend? p)
	(if (prime? p)
		(= (- p (cycle-mod p)) 1)
		false))
;
;;;	Find reptends in interval 7 .. n
(define (find-reptends n)
	(filter reptend? (sequence 7 n)))
;
;;;	Task
(println (find-reptends 500))
(println (map (fn(n) (println n " --> " (length (find-reptends n)))) '(500 1000 2000 4000 8000 16000 32000 64000)))


import strformat

func sieve(limit: int): seq[int] =

  var composite = newSeq[bool](limit + 1)
  var p = 3
  var p2 = p * p
  while p2 < limit:
    if not composite[p]:
      for n in countup(p2, limit, 2 * p):
        composite[n] = true
    inc p, 2
    p2 = p * p

  for n in countup(3, limit, 2):
    if not composite[n]:
      result.add n

func period(n: int): int =
  ## Find the period of the reciprocal of "n".
  var r = 1
  for i in 1..(n + 1):
    r = 10 * r mod n
  let r1 = r
  while true:
    r = 10 * r mod n
    inc result
    if r == r1: break

let primes = sieve(64000)
var longPrimes: seq[int]
for prime in primes:
  if prime.period() == prime - 1:
    longPrimes.add prime

const Numbers = [500, 1000, 2000, 4000, 8000, 16000, 32000, 64000]
var index, count = 0
var totals = newSeq[int](Numbers.len)
for longPrime in longPrimes:
  if longPrime > Numbers[index]:
    totals[index] = count
    inc index
  inc count
totals[^1] = count

echo &"The long primes up to {Numbers[0]} are:"
for i in 0..<totals[0]:
  stdout.write ' ', longPrimes[i]
stdout.write '\n'

echo "\nThe number of long primes up to:"
for i, total in totals:
  echo &"  {Numbers[i]:>5} is {total}"


use ntheory qw/divisors powmod is_prime/;

sub is_long_prime {
    my($p) = @_;
    return 0 unless is_prime($p);
    for my $d (divisors($p-1)) {
        return $d+1 == $p if powmod(10, $d, $p) == 1;
    }
    0;
}

print "Long primes ≤ 500:\n";
print join(' ', grep {is_long_prime($_) } 1 .. 500), "\n\n";

for my $n (500, 1000, 2000, 4000, 8000, 16000, 32000, 64000) {
    printf "Number of long primes ≤ $n: %d\n",  scalar grep { is_long_prime($_) } 1 .. $n;
}


function is_long_prime(integer n)
    integer r = 1, rr, period = 0
    for i=1 to n+1 do
        r = mod(10*r,n)
    end for
    rr = r
    while true do
        r = mod(10*r,n)
        period += 1
        if period>=n then return false end if
        if r=rr then exit end if
    end while
    return period=n-1
end function


go =>
  println(findall(P, (member(P,primes(500)),long_prime(P)))),
  nl,
  println("Number of long primes up to limit are:"),
  foreach(Limit in [500,1_000,2_000,4_000,8_000,16_000,32_000,64_000])
     printf(" <= %5d: %4d\n", Limit, count_all( (member(P,primes(Limit)), long_prime(P)) ))
  end,
  nl.

long_prime(P) =>
  get_rep_len(P) == (P-1).

%
% Get the length of the repeating cycle for 1/n
%
get_rep_len(I) = Len =>
    FoundRemainders = {0 : _K in 1..I+1},
    Value = 1,
    Position = 1,
    while (FoundRemainders[Value+1] == 0, Value != 0)
        FoundRemainders[Value+1] := Position,
        Value := (Value*10) mod I,
        Position := Position+1
    end,
    Len = Position-FoundRemainders[Value+1].


% See https://en.wikipedia.org/wiki/Full_reptend_prime
long_prime(Prime):-
    is_prime(Prime),
    M is 10 mod Prime,
    M > 1,
    primitive_root(10, Prime).

% See https://en.wikipedia.org/wiki/Primitive_root_modulo_n#Finding_primitive_roots
primitive_root(Base, Prime):-
    Phi is Prime - 1,
    primitive_root(Phi, 2, Base, Prime).

primitive_root(1, _, _, _):-!.
primitive_root(N, P, Base, Prime):-
    is_prime(P),
    0 is N mod P,
    !,
    X is (Prime - 1) // P,
    R is powm(Base, X, Prime),
    R \= 1,
    divide_out(N, P, M),
    Q is P + 1,
    primitive_root(M, Q, Base, Prime).
primitive_root(N, P, Base, Prime):-
    Q is P + 1,
    Q * Q < Prime,
    !,
    primitive_root(N, Q, Base, Prime).
primitive_root(N, _, Base, Prime):-
    X is (Prime - 1) // N,
    R is powm(Base, X, Prime),
    R \= 1.

divide_out(N, P, M):-
    divmod(N, P, Q, 0),
    !,
    divide_out(Q, P, M).
divide_out(N, _, N).

print_long_primes([], _):-
    !,
    nl.
print_long_primes([Prime|_], Limit):-
    Prime > Limit,
    !,
    nl.
print_long_primes([Prime|Primes], Limit):-
    writef('%w ', [Prime]),
    print_long_primes(Primes, Limit).

count_long_primes(_, L, Limit, _):-
    L > Limit,
    !.
count_long_primes([], Limit, _, Count):-
    writef('Number of long primes up to %w: %w\n', [Limit, Count]),
    !.
count_long_primes([Prime|Primes], L, Limit, Count):-
    Prime > L,
    !,
    writef('Number of long primes up to %w: %w\n', [L, Count]),
    Count1 is Count + 1,
    L1 is L * 2,
    count_long_primes(Primes, L1, Limit, Count1).
count_long_primes([_|Primes], L, Limit, Count):-
    Count1 is Count + 1,
    count_long_primes(Primes, L, Limit, Count1).

main(Limit):-
    find_prime_numbers(Limit),
    findall(Prime, long_prime(Prime), Primes),
    writef('Long primes up to 500:\n'),
    print_long_primes(Primes, 500),
    count_long_primes(Primes, 500, Limit, 0).

main:-
    main(256000).


#MAX=64000
If OpenConsole()=0 : End 1 : EndIf

Dim p.b(#MAX) : FillMemory(@p(),#MAX,#True,#PB_Byte)
For n=2 To Int(Sqr(#MAX))+1 : If p(n) : m=n*n : While m<=#MAX : p(m)=#False : m+n : Wend : EndIf : Next

Procedure.i periodic(v.i)
  r=1 : Repeat : r=(r*10)%v : c+1 : If r<=1 : ProcedureReturn c : EndIf : ForEver
EndProcedure

n=500
PrintN(LSet("_",15,"_")+"Long primes upto "+Str(n)+LSet("_",15,"_"))
For i=3 To 500 Step 2
  If p(i) And (i-1)=periodic(i)
    Print(RSet(Str(i),5)) : c+1 : If c%10=0 : PrintN("") : EndIf
  EndIf
Next

PrintN(~"\n")
PrintN("The number of long primes up to:")
PrintN(RSet(Str(n),8)+" is "+Str(c)) : n+n
For i=501 To #MAX+1 Step 2
  If p(i) And (i-1)=periodic(i) : c+1 : EndIf
  If i>n : PrintN(RSet(Str(n),8)+" is "+Str(c)) : n+n : EndIf
Next
Input()


def sieve(limit):
    primes = []
    c = [False] * (limit + 1) # composite = true
    # no need to process even numbers
    p = 3
    while True:
        p2 = p * p
        if p2 > limit: break
        for i in range(p2, limit, 2 * p): c[i] = True
        while True:
            p += 2
            if not c[p]: break

    for i in range(3, limit, 2):
        if not c[i]: primes.append(i)
    return primes

# finds the period of the reciprocal of n
def findPeriod(n):
    r = 1
    for i in range(1, n): r = (10 * r) % n
    rr = r
    period = 0
    while True:
        r = (10 * r) % n
        period += 1
        if r == rr: break
    return period

primes = sieve(64000)
longPrimes = []
for prime in primes:
    if findPeriod(prime) == prime - 1:
        longPrimes.append(prime)
numbers = [500, 1000, 2000, 4000, 8000, 16000, 32000, 64000]
count = 0
index = 0
totals = [0] * len(numbers)
for longPrime in longPrimes:
    if longPrime > numbers[index]:
        totals[index] = count
        index += 1
    count += 1
totals[-1] = count
print('The long primes up to 500 are:')
print(str(longPrimes[:totals[0]]).replace(',', ''))
print('\nThe number of long primes up to:')
for (i, total) in enumerate(totals):
    print('  %5d is %d' % (numbers[i], total))


  [ over size 0 swap 2swap
    bsearchwith < drop ]      is search      ( [ --> n )

  [ 1 over 1 - times
      [ 10 * over mod ]
    tuck
    0 temp put
    [ 10 * over mod
      1 temp tally
      rot 2dup != while
      unrot again ]
    2drop drop
    temp take ]               is period      ( n --> n )

  [ dup isprime not iff
      [ drop false ] done
    dup period 1+ = ]         is islongprime ( n --> b )

  64000 eratosthenes

  []
  64000 times
    [ i^ islongprime if [ i^ join ] ]
  behead drop
  dup dup 500 search split drop echo cr cr

  ' [ 500 1000 2000 4000 8000 16000 32000 64000 ]
  witheach
    [ dup echo say " --> "
      dip dup search echo cr ]
  drop


#lang racket
(require math/number-theory)

(define (find-period n)
  (let ((rr (for/fold ((r 1))
                      ((i (in-range 1 (+ n 2))))
              (modulo (* 10 r) n))))
    (let period-loop ((r rr) (p 1))
      (let ((r′ (modulo (* 10 r) n)))
        (if (= r′ rr) p (period-loop r′ (add1 p)))))))

(define (long-prime? n)
  (and (prime? n) (= (find-period n) (sub1 n))))

(define memoised-long-prime? (let ((h# (make-hash))) (λ (n) (hash-ref! h# n (λ () (long-prime? n))))))

(module+ main
  ;; strictly, won't test 500 itself... but does it look prime to you?
  (filter memoised-long-prime? (range 7 500 2))
  (for-each
   (λ (n) (displayln (cons n (for/sum ((i (in-range 7 n 2))) (if (memoised-long-prime? i) 1 0)))))
   '(500 1000 2000 4000 8000 16000 32000 64000)))

(module+ test
  (require rackunit)
  (check-equal? (map find-period '(7 11 977)) '(6 2 976)))


use Math::Primesieve;
my $sieve = Math::Primesieve.new;

sub is-long (Int $p) {
    my $r = 1;
    my $rr = $r = (10 * $r) % $p for ^$p;
    my $period;
    loop {
        $r = (10 * $r) % $p;
        ++$period;
        last if $period >= $p or $r == $rr;
    }
    $period == $p - 1 and $p > 2;
}

my @primes = $sieve.primes(500);
my @long-primes = @primes.grep: {.&is-long};

put "Long primes ≤ 500:\n", @long-primes;

@long-primes = ();

for 500, 1000, 2000, 4000, 8000, 16000, 32000, 64000 -> $upto {
    state $from = 0;
    my @extend = $sieve.primes($from, $upto);
    @long-primes.append: @extend.hyper(:8degree).grep: {.&is-long};
    say "\nNumber of long primes ≤ $upto: ", +@long-primes;
    $from = $upto;
}


F longest_common_substring(s1, s2)
   V ir = 0
   V jr = -1
   L(i1) 0 .< s1.len
      V? i2 = s2.find(s1[i1])
      L i2 != N
         V (j1, j2) = (i1, i2)
         L j1 < s1.len & j2 < s2.len & s2[j2] == s1[j1]
            I j1 - i1 >= jr - ir
               (ir, jr) = (i1, j1)
            j1++
            j2++
         i2 = s2.find(s1[i1], i2 + 1)
   R s1[ir..jr]

print(longest_common_substring(‘thisisatest’, ‘testing123testing’))


F lcs(a, b)
   V lengths = [[0] * (b.len+1)] * (a.len+1)
   L(x) a
      V i = L.index
      L(y) b
         V j = L.index
         I x == y
            lengths[i + 1][j + 1] = lengths[i][j] + 1
         E
            lengths[i + 1][j + 1] = max(lengths[i + 1][j], lengths[i][j + 1])

   V result = ‘’
   V j = b.len
   L(i) 1..a.len
      I lengths[i][j] != lengths[i - 1][j]
         result ‘’= a[i - 1]
   R result

print(lcs(‘1234’, ‘1224533324’))
print(lcs(‘thisisatest’, ‘testing123testing’))


/*REXX pgm calculates/displays base ten  long primes  (AKA golden primes, proper primes,*/
/*───────────────────── maximal period primes, long period primes, full reptend primes).*/
parse arg a                                      /*obtain optional argument from the CL.*/
if a='' | a=","  then a= '500 -500 -1000 -2000 -4000 -8000 -16000' ,  /*Not specified?  */
                         '-32000 -64000 -128000 -512000 -1024000'     /*Then use default*/
    do k=1  for words(a);     H=word(a, k)       /*step through the list of high limits.*/
    neg= H<1                                     /*used as an indicator to display count*/
    H= abs(H)                                    /*obtain the absolute value of  H.     */
    $=                                           /*the list of  long primes   (so far). */
       do j=7  to H  by 2                        /*start with 7,  just use odd integers.*/
       if .len(j) + 1 \== j  then iterate        /*Period length wrong?   Then skip it. */
       $=$ j                                     /*add the   long prime   to the $ list.*/
       end   /*j*/
    say
    if neg  then do;  say 'number of long primes ≤ '    H     " is: "     words($);    end
            else do;  say   'list of long primes ≤ '    H":";         say strip($);    end
    end      /*k*/
exit                                             /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
.len: procedure; parse arg x;  r=1;   do x;                   r= 10*r // x;     end  /*x*/
                              rr=r;   do p=1  until r==rr;    r= 10*r // x;     end  /*p*/
      return p


System: I7-6700HQ, 3.5 GHz, Linux Kernel 5.6.17
Run as: $ ruby longprimes.rb


BYTE Func Equals(CHAR ARRAY a,b)
  BYTE i

  IF a(0)#b(0) THEN
    RETURN (0)
  FI

  FOR i=1 TO a(0)
  DO
    IF a(i)#b(i) THEN
      RETURN (0)
    FI
  OD
RETURN (1)

PROC Lcs(CHAR ARRAY a,b,res)
  CHAR ARRAY t(100)
  BYTE i,j,len

  IF a(0)<b(0) THEN
    len=a(0)
  ELSE
    len=b(0)
  FI

  WHILE len>0
  DO
    FOR i=1 to a(0)-len+1
    DO
      SCopyS(res,a,i,i+len-1)
      FOR j=1 to b(0)-len+1
      DO
        SCopyS(t,b,j,j+len-1)
        IF Equals(res,t) THEN
          RETURN
        FI
      OD
    OD
    len==-1
  OD
  res(0)=0
RETURN

PROC Test(CHAR ARRAY a,b)
  CHAR ARRAY res(100)

  Lcs(a,b,res)
  PrintF("lcs(""%S"",""%S"")=""%S""%E",a,b,res)
RETURN

PROC Main()
  Test("thisisatest","testing123testing")
RETURN


with Ada.Text_Io;

procedure Longest_Common_Substring is

   function Common (Left, Right: String) return String is
      Com : array (Left'Range, Right'Range) of Natural := (others => (others => 0));
      Longest : Natural := 0;
      Last    : Natural := 0;
   begin
      for L in Left'Range loop
         for R in Right'Range loop
            if Left (L) = Right (R) then
               if L > Left'First and R > Right'First then
                  Com (L, R) := Com (L - 1, R - 1) + 1;
               else
                  Com (L, R) := 1;
               end if;
               if Com (L, R) > Longest then
                  Longest := Com (L, R);
                  Last    := L;
               end if;
            end if;
         end loop;
      end loop;
      return Left (Last - Longest + 1 .. Last);
   end Common;

begin
   Ada.Text_Io.Put_Line (Common ("thisisatest", "testing123testing"));
end Longest_Common_Substring;


with Ada.Text_IO;  use Ada.Text_IO;

procedure Test_LCS is
   function LCS (A, B : String) return String is
   begin
      if A'Length = 0 or else B'Length = 0 then
         return "";
      elsif A (A'Last) = B (B'Last) then
         return LCS (A (A'First..A'Last - 1), B (B'First..B'Last - 1)) & A (A'Last);
      else
         declare
            X : String renames LCS (A, B (B'First..B'Last - 1));
            Y : String renames LCS (A (A'First..A'Last - 1), B);
         begin
            if X'Length > Y'Length then
               return X;
            else
               return Y;
            end if;
         end;
      end if;
   end LCS;
begin
   Put_Line (LCS ("thisisatest", "testing123testing"));
end Test_LCS;


main:(
   PROC lcs = (STRING a, b)STRING:
   BEGIN
      IF UPB a = 0 OR UPB b = 0 THEN
         ""
      ELIF a [UPB a] = b [UPB b] THEN
         lcs (a [:UPB a - 1], b [:UPB b - 1]) + a [UPB a]
      ELSE
         STRING x = lcs (a, b [:UPB b - 1]);
         STRING y = lcs (a [:UPB a - 1], b);
         IF UPB x > UPB y THEN x ELSE y FI
      FI
   END # lcs #;
   print((lcs ("thisisatest", "testing123testing"), new line))
)


// main.rs
// References:
// https://en.wikipedia.org/wiki/Full_reptend_prime
// https://en.wikipedia.org/wiki/Primitive_root_modulo_n#Finding_primitive_roots

mod bit_array;
mod prime_sieve;

use prime_sieve::PrimeSieve;

fn modpow(mut base: usize, mut exp: usize, n: usize) -> usize {
    if n == 1 {
        return 0;
    }
    let mut result = 1;
    base %= n;
    while exp > 0 {
        if (exp & 1) == 1 {
            result = (result * base) % n;
        }
        base = (base * base) % n;
        exp >>= 1;
    }
    result
}

fn is_long_prime(sieve: &PrimeSieve, prime: usize) -> bool {
    if !sieve.is_prime(prime) {
        return false;
    }
    if 10 % prime == 0 {
        return false;
    }
    let n = prime - 1;
    let mut m = n;
    let mut p = 2;
    while p * p <= n {
        if sieve.is_prime(p) && m % p == 0 {
            if modpow(10, n / p, prime) == 1 {
                return false;
            }
            while m % p == 0 {
                m /= p;
            }
        }
        p += 1;
    }
    if m == 1 {
        return true;
    }
    modpow(10, n / m, prime) != 1
}

fn long_primes(limit1: usize, limit2: usize) {
    let sieve = PrimeSieve::new(limit2);
    let mut count = 0;
    let mut limit = limit1;
    let mut prime = 3;
    while prime < limit2 {
        if is_long_prime(&sieve, prime) {
            if prime < limit1 {
                print!("{} ", prime);
            }
            if prime > limit {
                print!("\nNumber of long primes up to {}: {}", limit, count);
                limit *= 2;
            }
            count += 1;
        }
        prime += 2;
    }
    println!("\nNumber of long primes up to {}: {}", limit, count);
}

fn main() {
    long_primes(500, 8192000);
}


object LongPrimes extends App {
    def primeStream = LazyList.from(3, 2)
        .filter(p => (3 to math.sqrt(p).ceil.toInt by 2).forall(p % _ > 0))

    def longPeriod(p: Int): Boolean = {
        val mstart = 10 % p
        @annotation.tailrec
        def iter(mod: Int, period: Int): Int = {
            val mod1 = (10 * mod) % p
            if (mod1 == mstart) period
            else iter(mod1, period + 1)
        }
        iter(mstart, 1) == p - 1
    }

    val longPrimes = primeStream.filter(longPeriod(_))
    println("long primes up to 500:")
    println(longPrimes.takeWhile(_ <= 500).mkString(" "))
    println

    val limitList = Seq.tabulate(8)(math.pow(2, _).toInt * 500)
    for (limit <- limitList) {
        val count = longPrimes.takeWhile(_ <= limit).length
        println(f"there are $count%4d long primes up to $limit%5d")
    }
}


void
test_string(text &g, v, l)
{
    integer n;

    n = prefix(v, l);
    if (~g < n) {
        g = cut(l, 0, n);
    }
}

longest(text u, v)
{
    record r;
    text g, l, s;

    while (~u) {
        r[u] = 0;
        u = delete(u, 0);
    }
    while (~v) {
        if (rsk_lower(r, v, l)) {
            test_string(g, v, l);
        }
        if (rsk_upper(r, v, l)) {
            test_string(g, v, l);
        }
        v = delete(v, 0);
    }

    g;
}


BEGIN
    # returns the longest common substring of s and t #
    PROC longest common substring = ( STRING s, t )STRING:
         BEGIN
            STRING s1       = s[ @ 1 ]; # normalise bounds to 1 : ... #
            STRING s2       = t[ @ 1 ];
            STRING result  := "";
            INT result len := 0;
            FOR i TO UPB s1 DO
                FOR j TO UPB s2 DO
                    IF s1[ i ] = s2[ j ] THEN
                        INT k := 1;
                        WHILE INT ik = i + k;
                              INT jk = j + k;
                              IF ik > UPB s1 OR jk > UPB s2
                              THEN FALSE
                              ELSE s1[ ik ] = s2[ jk ]
                              FI
                        DO
                            k +:= 1
                        OD;
                        IF k > result len THEN
                            # found a longer substring #
                            result len := k;
                            result     := s1[ i : ( i + k ) - 1 ]
                        FI
                    FI
                OD
            OD;
            result
         END # longest common substring # ;

    # task test case #
    print( ( longest common substring( "thisisatest", "testing123testing" ), newline ) )
END


lcs←{
     ⎕IO←0
     betterof←{⊃(</+/¨⍺ ⍵)⌽⍺ ⍵}                     ⍝ better of 2 selections
     cmbn←{↑,⊃∘.,/(⊂⊂⍬),⍵}                          ⍝ combine lists
     rr←{∧/↑>/1 ¯1↓[1]¨⊂⍵}                          ⍝ rising rows
     hmrr←{∨/(rr ⍵)∧∧/⍵=⌈\⍵}                        ⍝ has monotonically rising rows
     rnbc←{{⍵/⍳⍴⍵}¨↓[0]×⍵}                          ⍝ row numbers by column
     valid←hmrr∘cmbn∘rnbc                           ⍝ any valid solutions?
     a w←(</⊃∘⍴¨⍺ ⍵)⌽⍺ ⍵                            ⍝ longest first
     matches←a∘.=w
     aps←{⍵[;⍒+⌿⍵]}∘{(⍵/2)⊤⍳2*⍵}                    ⍝ all possible subsequences
     swps←{⍵/⍨∧⌿~(~∨⌿⍺)⌿⍵}                          ⍝ subsequences with possible solns
     sstt←matches swps aps⊃⍴w                       ⍝ subsequences to try
     w/⍨{
         ⍺←0⍴⍨⊃⍴⍵                                   ⍝ initial selection
         (+/⍺)≥+/⍵[;0]:⍺                            ⍝ no scope to improve
         this←⍺ betterof{⍵×valid ⍵/matches}⍵[;0]    ⍝ try to improve
         1=1⊃⍴⍵:this                                ⍝ nothing left to try
         this ∇ 1↓[1]⍵                              ⍝ keep looking
     }sstt
 }


lcs: function [a,b][
    ls: new array.of: @[inc size a, inc size b] 0

    loop.with:'i a 'x [
        loop.with:'j b 'y [
            ls\[i+1]\[j+1]: (x=y)? -> ls\[i]\[j] + 1
                                   -> max @[ls\[i+1]\[j], ls\[i]\[j+1]]
        ]
    ]
    [result, x, y]: @[new "", size a, size b]

    while [and? [x > 0][y > 0]][
        if? ls\[x]\[y] = ls\[x-1]\[y] -> x: x-1
        else [
            if? ls\[x]\[y] = ls\[x]\[y-1] -> y: y-1
            else [
                result: a\[x-1] ++ result
                x: x-1
                y: y-1
            ]
        ]
    ]
    return result
]

print lcs "1234" "1224533324"
print lcs "thisisatest" "testing123testing"


func is_long_prime(p) {

    for d in (divisors(p-1)) {
        if (powmod(10, d, p) == 1) {
            return (d+1 == p)
        }
    }

    return false
}

say "Long primes ≤ 500:"
say primes(500).grep(is_long_prime).join(' ')

for n in ([500, 1000, 2000, 4000, 8000, 16000, 32000, 64000]) {
    say ("Number of long primes ≤ #{n}: ", primes(n).count_by(is_long_prime))
}


public struct Eratosthenes: Sequence, IteratorProtocol {
  private let n: Int
  private let limit: Int

  private var i = 2
  private var sieve: [Int]

  public init(upTo: Int) {
    if upTo <= 1 {
      self.n = 0
      self.limit = -1
      self.sieve = []
    } else {
      self.n = upTo
      self.limit = Int(Double(n).squareRoot())
      self.sieve = Array(0...n)
    }
  }

  public mutating func next() -> Int? {
    while i < n {
      defer { i += 1 }

      if sieve[i] != 0 {
        if i <= limit {
          for notPrime in stride(from: i * i, through: n, by: i) {
            sieve[notPrime] = 0
          }
        }

        return i
      }
    }

    return nil
  }
}

func findPeriod(n: Int) -> Int {
  let r = (1...n+1).reduce(1, {res, _ in (10 * res) % n })
  var rr = r
  var period = 0

  repeat {
    rr = (10 * rr) % n
    period += 1
  } while r != rr

  return period
}

let longPrimes = Eratosthenes(upTo: 64000).dropFirst().lazy.filter({ findPeriod(n: $0) == $0 - 1 })

print("Long primes less than 500: \(Array(longPrimes.prefix(while: { $0 <= 500 })))")

let counts =
  longPrimes.reduce(into: [500: 0, 1000: 0, 2000: 0, 4000: 0, 8000: 0, 16000: 0, 32000: 0, 64000: 0], {counts, n in
    for key in counts.keys where n < key {
      counts[key]! += 1
    }
  })

for key in counts.keys.sorted() {
  print("There are \(counts[key]!) long primes less than \(key)")
}


Imports System, System.Collections.Generic, System.Linq, System.Console

Module LongPrimes

    Function Period(ByVal n As Integer) As Integer
        Dim m As Integer, r As Integer = 1
        For i As Integer = 0 To n : r = 10 * r Mod n : Next
        m = r : Period = 1 : While True
            r = (10 * r) Mod n : If r = m Then Return Period
            Period += 1 : End While
    End Function

    Sub Main()
        Dim primes As IEnumerable(Of Integer) = SomePrimeGenerator.Primes(64000).Skip(1).Where(Function(p) Period(p) = p - 1).Append(99999)
        Dim count As Integer = 0, limit As Integer = 500
        WriteLine(String.Join(" ", primes.TakeWhile(Function(p) p <= limit)))
        For Each prime As Integer In primes
            If prime > limit Then
                WriteLine($"There are {count} long primes below {limit}")
                limit <<= 1 : End If : count += 1 : Next
    End Sub

End Module

Module SomePrimeGenerator

    Iterator Function Primes(lim As Integer) As IEnumerable(Of Integer)
        Dim flags As Boolean() = New Boolean(lim) {},
            j As Integer = 2, d As Integer = 3, sq As Integer = 4
        While sq <= lim
            If Not flags(j) Then
                Yield j : For k As Integer = sq To lim step j
                    flags(k) = True : Next
            End If : j += 1 : d += 2 : sq += d
        End While : While j <= lim
            If Not flags(j) Then Yield j
            j += 1 : End While
    End Function

End Module


on LCS(a, b)
    -- Identify the shorter string. The longest common substring won't be longer than it!
    set lengthA to a's length
    set lengthB to b's length
    if (lengthA < lengthB) then
        set {shorterString, shorterLength, longerString} to {a, lengthA, b}
    else
        set {shorterString, shorterLength, longerString} to {b, lengthB, a}
    end if

    set longestMatches to {}
    set longestMatchLength to 0
    -- Find the longest matching substring starting at each character in the shorter string.
    repeat with i from 1 to shorterLength
        repeat with j from shorterLength to i by -1
            set thisSubstring to text i thru j of shorterString
            if (longerString contains thisSubstring) then
                -- Match found. If it's longer than the previously found match, or a new string of the same length, remember it.
                set matchLength to j - i + 1
                if (matchLength > longestMatchLength) then
                    set longestMatches to {thisSubstring}
                    set longestMatchLength to matchLength
                else if ((matchLength = longestMatchLength) and (thisSubstring is not in longestMatches)) then
                    set end of longestMatches to thisSubstring
                end if
                -- Don't bother with the match's own substrings.
                exit repeat
            end if
        end repeat
    end repeat

    return longestMatches
end LCS


lcs: function [a,b][
    lengths: map 0..size a => [map 0..size b => 0]
    greatestLength: 0
    result: ""
    loop.with:'i a 'x [
        loop.with:'j b 'y [
            if x=y [
                if? or? i=0 j=0 ->
                    lengths\[i]\[j]: 0
                else ->
                    lengths\[i]\[j]: 1 + lengths\[i-1]\[j-1]

                if greatestLength < lengths\[i]\[j] [
                    greatestLength: lengths\[i]\[j]
                    result: slice a (i-greatestLength)+1 i
                ]
            ]
        ]
    ]
    return result
]

print lcs "thisisatest", "testing123testing"


lcs(a,b) { ; Longest Common Subsequence of strings, using Dynamic Programming
   Loop % StrLen(a)+2 {                          ; Initialize
      i := A_Index-1
      Loop % StrLen(b)+2
         j := A_Index-1, len%i%_%j% := 0
   }
   Loop Parse, a                                 ; scan a
   {
      i := A_Index, i1 := i+1, x := A_LoopField
      Loop Parse, b                              ; scan b
      {
         j := A_Index, j1 := j+1, y := A_LoopField
         len%i1%_%j1% := x=y ? len%i%_%j% + 1
         : (u:=len%i1%_%j%) > (v:=len%i%_%j1%) ? u : v
      }
   }
   x := StrLen(a)+1, y := StrLen(b)+1
   While x*y {                                   ; construct solution from lengths
     x1 := x-1, y1 := y-1
     If (len%x%_%y% = len%x1%_%y%)
         x := x1
     Else If  (len%x%_%y% = len%x%_%y1%)
         y := y1
     Else
         x := x1, y := y1, t := SubStr(a,x,1) t
   }
   Return t
}


import "/fmt" for Fmt
import "/math" for Int

// finds the period of the reciprocal of n
var findPeriod = Fn.new { |n|
    var r = 1
    for (i in 1..n+1) r = (10*r) % n
    var rr = r
    var period = 0
    var ok = true
    while (ok) {
        r = (10*r) % n
        period = period + 1
        ok = (r != rr)
    }
    return period
}

var primes = Int.primeSieve(64000).skip(1)
var longPrimes = []
for (prime in primes) {
    if (findPeriod.call(prime) == prime - 1) longPrimes.add(prime)
}
var numbers = [500, 1000, 2000, 4000, 8000, 16000, 32000, 64000]
var index = 0
var count = 0
var totals = List.filled(numbers.count, 0)
for (longPrime in longPrimes) {
    if (longPrime > numbers[index]) {
        totals[index] = count
        index = index + 1
    }
    count = count + 1
}
totals[-1] = count
System.print("The long primes up to %(numbers[0]) are: ")
System.print(longPrimes[0...totals[0]].join(" "))

System.print("\nThe number of long primes up to: ")
var i = 0
for (total in totals) {
    System.print("  %(Fmt.d(5, numbers[i])) is %(total)")
    i = i + 1
}


PROGRAM "longprimes"
VERSION "0.0002"

DECLARE FUNCTION Entry()
INTERNAL FUNCTION Sieve(limit&, primes&[], count%)
INTERNAL FUNCTION FindPeriod(n&)

FUNCTION Entry()
  DIM numbers&[7]
  numbers&[0] = 500
  numbers&[1] = 1000
  numbers&[2] = 2000
  numbers&[3] = 4000
  numbers&[4] = 8000
  numbers&[5] = 16000
  numbers&[6] = 32000
  numbers&[7] = 64000
  numberUpperBound% = UBOUND(numbers&[])
  DIM totals%[numberUpperBound%]
  DIM primes&[6499]
  PRINT "Please wait."
  PRINT
  Sieve(64000, @primes&[], @primeCount%)
  DIM longPrimes&[primeCount% - 1] ' Surely longCount% < primeCount%
  longCount% = 0
  FOR i% = 0 TO primeCount% - 1
    prime& = primes&[i%]
    IF FindPeriod(prime&) = prime& - 1 THEN
      longPrimes&[longCount%] = prime&
      INC longCount%
    END IF
  NEXT i%
  count% = 0
  index% = 0
  FOR i% = 0 TO longCount% - 1
    IF longPrimes&[i%] > numbers&[index%] THEN
      totals%[index%] = count%
      INC index%
    END IF
    INC count%
  NEXT i%
  totals%[numberUpperBound%] = count%
  PRINT "The long primes up to"; numbers&[0]; " are:"
  PRINT "[";
  FOR i% = 0 TO totals%[0] - 2
    PRINT STRING$(longPrimes&[i%]); " ";
  NEXT i%
  IF totals%[0] > 0 THEN
    PRINT STRING$(longPrimes&[totals%[0] - 1]);
  END IF
  PRINT "]"
  PRINT
  PRINT "The number of long primes up to:"
  FOR i% = 0 TO numberUpperBound%
    PRINT FORMAT$("  #####", numbers&[i%]); " is"; totals%[i%]
  NEXT i%
END FUNCTION

FUNCTION Sieve(limit&, primes&[], count%)
  DIM c@[limit&]
  FOR i& = 0 TO limit&
    c@[i&] = 0
  NEXT i&
  ' No need to process even numbers
  p% = 3
  n% = 0
  p2& = p% * p%
  DO WHILE p2& <= limit&
    FOR i& = p2& TO limit& STEP 2 * p%
      c@[i&] = 1
    NEXT i&
    DO
      p% = p% + 2
    LOOP UNTIL !c@[p%]
    p2& = p% * p%
  LOOP
  FOR i& = 3 TO limit& STEP 2
    IFZ c@[i&] THEN
      primes&[n%] = i&
      INC n%
    END IF
  NEXT i&
  count% = n%
END FUNCTION

' Finds the period of the reciprocal of n&
FUNCTION FindPeriod(n&)
  r& = 1
  period& = 0
  FOR i& = 1 TO n& + 1
    r& = (10 * r&) MOD n&
  NEXT i&
  rr& = r&
  DO
    r& = (10 * r&) MOD n&
    INC period&
  LOOP UNTIL r& = rr&
END FUNCTION period&

END PROGRAM


LCS(a, b){
	x := i := 1
	while StrLen(x)
		Loop % StrLen(a)
			IfInString, b, % x := SubStr(a, i:=StrLen(x)=1 ? i+1 : i, n:=StrLen(a)+1-A_Index)
				res := StrLen(res) > StrLen(x) ? res : x
	return res
}


FUNCTION Common_Sub$(haystack$, needle$)

    WHILE LEN(needle$)
        FOR x = LEN(needle$) DOWNTO 1
            IF INSTR(haystack$, LEFT$(needle$, x)) THEN RETURN LEFT$(needle$, x)
        NEXT
        needle$ = MID$(needle$, 2)
    WEND
    EXIT

ENDFUNC

PRINT Common_Sub$("thisisatest", "testing123testing")


FUNCTION lcs$ (a$, b$)
    IF LEN(a$) = 0 OR LEN(b$) = 0 THEN
	lcs$ = ""
    ELSEIF RIGHT$(a$, 1) = RIGHT$(b$, 1) THEN
	lcs$ = lcs$(LEFT$(a$, LEN(a$) - 1), LEFT$(b$, LEN(b$) - 1)) + RIGHT$(a$, 1)
    ELSE
	x$ = lcs$(a$, LEFT$(b$, LEN(b$) - 1))
	y$ = lcs$(LEFT$(a$, LEN(a$) - 1), b$)
	IF LEN(x$) > LEN(y$) THEN
		lcs$ = x$
	ELSE
		lcs$ = y$
	END IF
    END IF
END FUNCTION


function LCS(a, b)
	if length(a) = 0 or length(b) = 0 then return ""
	if right(a, 1) = right(b, 1) then
		LCS = LCS(left(a, length(a) - 1), left(b, length(b) - 1)) + right(a, 1)
	else
		x = LCS(a, left(b, length(b) - 1))
		y = LCS(left(a, length(a) - 1), b)
		if length(x) > length(y) then return x else return y
	end if
end function

print LCS("1234", "1224533324")
print LCS("thisisatest", "testing123testing")
end


var [const] BN=Import("zklBigNum");  // libGMP
primes,p := List.createLong(7_000), BN(3);  // one big alloc vs lots of allocs
while(p.nextPrime()<=64_000){ primes.append(p.toInt()) } // 6412 of them, skipped 2
primes.append(p.toInt());	// and one more so tail prime is >64_000

longPrimes:=primes.filter(fcn(p){ findPeriod(p)==p-1 }); // yawn
fcn findPeriod(n){
   r,period := 1,0;
   do(n){ r=(10*r)%n }
   rr:=r;
   while(True){   // reduce is more concise but 2.5 times slower
      r=(10*r)%n;
      period+=1;
      if(r==rr) break;
   }
   period
}


function LCS(a, b)
	if length(a) = 0 or length(b) = 0 then return ""
	while length(b)
		for j = length(b) to 1 step -1
			if instr(a, left(b, j)) then return left(b, j)
		next j
		b = mid$(b, 2)
	end while
end function

print LCS("thisisatest", "testing123testing")
end


#include <stdio.h>

void lcs(const char * const sa, const char * const sb, char ** const beg, char ** const end) {
    size_t apos, bpos;
    ptrdiff_t len;

    *beg = 0;
    *end = 0;
    len = 0;

    for (apos = 0; sa[apos] != 0; ++apos) {
        for (bpos = 0; sb[bpos] != 0; ++bpos) {
            if (sa[apos] == sb[bpos]) {
                len = 1;
                while (sa[apos + len] != 0 && sb[bpos + len] != 0 && sa[apos + len] == sb[bpos + len]) {
                    len++;
                }
            }

            if (len > *end - *beg) {
                *beg = sa + apos;
                *end = *beg + len;
                len = 0;
            }
        }
    }
}

int main() {
    char *s1 = "thisisatest";
    char *s2 = "testing123testing";
    char *beg, *end, *it;

    lcs(s1, s2, &beg, &end);

    for (it = beg; it != end; it++) {
        putchar(*it);
    }
    printf("\n");

    return 0;
}


      PRINT FNlcs("1234", "1224533324")
      PRINT FNlcs("thisisatest", "testing123testing")
      END

      DEF FNlcs(a$, b$)
      IF a$="" OR b$="" THEN = ""
      IF RIGHT$(a$) = RIGHT$(b$) THEN = FNlcs(LEFT$(a$), LEFT$(b$)) + RIGHT$(a$)
      LOCAL x$, y$
      x$ = FNlcs(a$, LEFT$(b$))
      y$ = FNlcs(LEFT$(a$), b$)
      IF LEN(y$) > LEN(x$) SWAP x$,y$
      = x$


LCS ← ¯1 ⊑ "" <⊸∾ ""¨∘⊢ ⊣⍟(>○≠){𝕩𝔽¨𝔽`𝕨∾¨""<⊸»𝕩}˝ (=⌜⥊¨⊣)⟜⌽


using System;

namespace LongestCommonSubstring
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(lcs("thisisatest", "testing123testing"));
            Console.ReadKey(true);
        }

        public static string lcs(string a, string b)
        {
            var lengths = new int[a.Length, b.Length];
            int greatestLength = 0;
            string output = "";
            for (int i = 0; i < a.Length; i++)
            {
                for (int j = 0; j < b.Length; j++)
                {
                    if (a[i] == b[j])
                    {
                        lengths[i, j] = i == 0 || j == 0 ? 1 : lengths[i - 1, j - 1] + 1;
                        if (lengths[i, j] > greatestLength)
                        {
                            greatestLength = lengths[i, j];
                            output = a.Substring(i - greatestLength + 1, greatestLength);
                        }
                    }
                    else
                    {
                        lengths[i, j] = 0;
                    }
                }
            }
            return output;
        }
    }
}


#include <string>
#include <algorithm>
#include <iostream>
#include <set>
#include <vector>

auto collectSubStrings( const std::string& s, int maxSubLength )
{
    int l = s.length();
    auto res = std::set<std::string>();
    for ( int start = 0; start < l; start++ )
    {
        int m = std::min( maxSubLength, l - start + 1 );
        for ( int length = 1; length < m; length++ )
        {
            res.insert( s.substr( start, length ) );
        }
    }
    return res;
}

std::string lcs( const std::string& s0, const std::string& s1 )
{
    // collect substring set
    auto maxSubLength = std::min( s0.length(), s1.length() );
    auto set0 = collectSubStrings( s0, maxSubLength );
    auto set1 = collectSubStrings( s1, maxSubLength );

    // get commons into a vector
    auto common = std::vector<std::string>();
    std::set_intersection( set0.begin(), set0.end(), set1.begin(), set1.end(),
        std::back_inserter( common ) );

    // get the longest one
    std::nth_element( common.begin(), common.begin(), common.end(),
        []( const std::string& s1, const std::string& s2 ) {
            return s1.length() > s2.length();
        } );
    return *common.begin();
}

int main( int argc, char* argv[] )
{
    auto s1 = std::string( "thisisatest" );
    auto s2 = std::string( "testing123testing" );
    std::cout << "The longest common substring of " << s1 << " and " << s2
              << " is:\n";
    std::cout << "\"" << lcs( s1, s2 ) << "\" !\n";
    return 0;
}


  ( LCS
  =   A a ta B b tb prefix
    .     !arg:([email protected](?A:%?a ?ta)[email protected](?B:%?b ?tb))
        & ( !a:!b&LCS$(!prefix !a.!ta.!tb)
          | LCS$(!prefix.!A.!tb)&LCS$(!prefix.!ta.!B)
          )
      | !prefix:? ([>!max:[?max):?lcs
      |
  )
& 0:?max
& :?lcs
& LCS$(.thisisatest.testing123testing)
& out$(max !max lcs !lcs);


(defun longest-common-substring (a b)
 "Return the longest substring common to a and b"
 ;; Found at https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Longest_common_substring#Common_Lisp
  (let ((L (make-array (list (length a) (length b)) :initial-element 0))
        (z 0)
        (result '()) )
    (dotimes (i (length a))
      (dotimes (j (length b))
        (when (char= (char a i) (char b j))
          (setf (aref L i j)
                (if (or (zerop i) (zerop j))
                    1
                    (1+ (aref L (1- i) (1- j))) ))
          (when (> (aref L i j) z)
            (setf z (aref L i j)
                  result '() ))
          (when (= (aref L i j) z)
            (pushnew (subseq a (1+ (- i z)) (1+ i))
                     result :test #'equal )))))
    result ))


import std.stdio;

string lcs(string a, string b) {
    int[][] lengths;
    lengths.length = a.length;
    for (int i=0; i<a.length; i++) {
        lengths[i].length = b.length;
    }

    int greatestLength;
    string output;
    for (int i=0; i<a.length; i++) {
        for (int j=0; j<b.length; j++) {
            if (a[i]==b[j]) {
                lengths[i][j] = i==0 || j==0 ? 1 : lengths[i-1][j-1] + 1;
                if (lengths[i][j] > greatestLength) {
                    greatestLength = lengths[i][j];
                    int start = i-greatestLength+1;
                    output = a[start..start+greatestLength];
                }
            } else {
                lengths[i][j] = 0;
            }
        }
    }
    return output;
}

void main() {
    writeln(lcs("testing123testing", "thisisatest"));
}


using System;

namespace LCS
{
    class Program
    {
        static void Main(string[] args)
        {
            string word1 = "thisisatest";
            string word2 = "testing123testing";

            Console.WriteLine(lcsBack(word1, word2));
            Console.ReadKey();
        }

        public static string lcsBack(string a, string b)
        {
            string aSub = a.Substring(0, (a.Length - 1 < 0) ? 0 : a.Length - 1);
            string bSub = b.Substring(0, (b.Length - 1 < 0) ? 0 : b.Length - 1);

            if (a.Length == 0 || b.Length == 0)
                return "";
            else if (a[a.Length - 1] == b[b.Length - 1])
                return lcsBack(aSub, bSub) + a[a.Length - 1];
            else
            {
                string x = lcsBack(a, bSub);
                string y = lcsBack(aSub, b);
                return (x.Length > y.Length) ? x : y;
            }
        }
    }
}


#include <stdint.h>
#include <string>
#include <memory>                       // for shared_ptr<>
#include <iostream>
#include <deque>
#include <unordered_map>
#include <algorithm>                    // for lower_bound()
#include <iterator>                     // for next() and prev()

using namespace std;

class LCS {
protected:
  // This linked list class is used to trace the LCS candidates
  class Pair {
  public:
    uint32_t index1;
    uint32_t index2;
    shared_ptr<Pair> next;

    Pair(uint32_t index1, uint32_t index2, shared_ptr<Pair> next = nullptr)
      : index1(index1), index2(index2), next(next) {
    }

    static shared_ptr<Pair> Reverse(const shared_ptr<Pair> pairs) {
      shared_ptr<Pair> head = nullptr;
      for (auto next = pairs; next != nullptr; next = next->next)
        head = make_shared<Pair>(next->index1, next->index2, head);
      return head;
    }
  };

  typedef deque<shared_ptr<Pair>> PAIRS;
  typedef deque<uint32_t> THRESHOLD;
  typedef deque<uint32_t> INDEXES;
  typedef unordered_map<char, INDEXES> CHAR_TO_INDEXES_MAP;
  typedef deque<INDEXES*> MATCHES;

  uint32_t FindLCS(MATCHES& indexesOf2MatchedByIndex1, shared_ptr<Pair>* pairs) {
    auto traceLCS = pairs != nullptr;
    PAIRS chains;
    THRESHOLD threshold;

    //
    //[Assert]After each index1 iteration threshold[index3] is the least index2
    // such that the LCS of s1[0:index1] and s2[0:index2] has length index3 + 1
    //
    uint32_t index1 = 0;
    for (const auto& it1 : indexesOf2MatchedByIndex1) {
      if (!it1->empty()) {
        auto dq2 = *it1;
        auto limit = threshold.end();
        for (auto it2 = dq2.rbegin(); it2 != dq2.rend(); it2++) {
          // Each of the index1, index2 pairs considered here correspond to a match
          auto index2 = *it2;

          //
          // Note: The reverse iterator it2 visits index2 values in descending order,
          // allowing thresholds to be updated in-place.  std::lower_bound() is used
          // to perform a binary search.
          //
          limit = lower_bound(threshold.begin(), limit, index2);
          auto index3 = distance(threshold.begin(), limit);

          //
          // Look ahead to the next index2 value to optimize space used in the Hunt
          // and Szymanski algorithm.  If the next index2 is also an improvement on
          // the value currently held in threshold[index3], a new Pair will only be
          // superseded on the next index2 iteration.
          //
          // Depending on match redundancy, the number of Pair constructions may be
          // divided by factors ranging from 2 up to 10 or more.
          //
          auto skipIndex2 = next(it2) != dq2.rend() &&
            (limit == threshold.begin() || *prev(limit) < *next(it2));
          if (skipIndex2) continue;

          if (limit == threshold.end()) {
            // Insert Case
            threshold.push_back(index2);
            // Refresh limit iterator:
            limit = prev(threshold.end());
            if (traceLCS) {
              auto prefix = index3 > 0 ? chains[index3 - 1] : nullptr;
              auto last = make_shared<Pair>(index1, index2, prefix);
              chains.push_back(last);
            }
          }
          else if (index2 < *limit) {
            // Update Case
            // Update limit value:
            *limit = index2;
            if (traceLCS) {
              auto prefix = index3 > 0 ? chains[index3 - 1] : nullptr;
              auto last = make_shared<Pair>(index1, index2, prefix);
              chains[index3] = last;
            }
          }
        }                                 // next index2
      }

      index1++;
    }                                     // next index1

    if (traceLCS) {
      // Return the LCS as a linked list of matched index pairs:
      auto last = chains.size() > 0 ? chains.back() : nullptr;
      // Reverse longest chain
      *pairs = Pair::Reverse(last);
    }

    auto length = threshold.size();
    return length;
  }

  //
  // Match() avoids m*n comparisons by using CHAR_TO_INDEXES_MAP to
  // achieve O(m+n) performance, where m and n are the input lengths.
  //
  // The lookup time can be assumed constant in the case of characters.
  // The symbol space is larger in the case of records; but the lookup
  // time will be O(log(m+n)), at most.
  //
  void Match(CHAR_TO_INDEXES_MAP& indexesOf2MatchedByChar, MATCHES& indexesOf2MatchedByIndex1,
    const string& s1, const string& s2) {
    uint32_t index = 0;
    for (const auto& it : s2)
      indexesOf2MatchedByChar[it].push_back(index++);

    for (const auto& it : s1) {
      auto& dq2 = indexesOf2MatchedByChar[it];
      indexesOf2MatchedByIndex1.push_back(&dq2);
    }
  }

  string Select(shared_ptr<Pair> pairs, uint32_t length,
    bool right, const string& s1, const string& s2) {
    string buffer;
    buffer.reserve(length);
    for (auto next = pairs; next != nullptr; next = next->next) {
      auto c = right ? s2[next->index2] : s1[next->index1];
      buffer.push_back(c);
    }
    return buffer;
  }

public:
  string Correspondence(const string& s1, const string& s2) {
    CHAR_TO_INDEXES_MAP indexesOf2MatchedByChar;
    MATCHES indexesOf2MatchedByIndex1;  // holds references into indexesOf2MatchedByChar
    Match(indexesOf2MatchedByChar, indexesOf2MatchedByIndex1, s1, s2);
    shared_ptr<Pair> pairs;             // obtain the LCS as index pairs
    auto length = FindLCS(indexesOf2MatchedByIndex1, &pairs);
    return Select(pairs, length, false, s1, s2);
  }
};


program Longest_Common_Substring;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

function lcs(x, y: string): string;
var
  n, m, Alength: Integer;
  t, common: string;
  j: Integer;
  k: Integer;
begin

  Result := '';
  Alength := x.Length;

  for j := 0 to Alength - 1 do
    for k := Alength - j downto 0 do
    begin
      common := x.Substring(j, k);
      if (y.IndexOf(common) > -1) and (common.Length > Result.Length) then
        Result := common;
    end;
end;

var
  a, b: string;

begin
  a := 'thisisatest';
  b := 'testing123testing';
  if ParamCount = 2 then
  begin
    if not ParamStr(1).IsEmpty then
      a := ParamStr(1);
    if not ParamStr(2).IsEmpty then
      b := ParamStr(2);
  end;

  Writeln('string A = ', a);
  Writeln('string B = ', b);
  Writeln('LCsubstr = ', lcs(a, b));
  readln;
end.


(defn longest [xs ys] (if (> (count xs) (count ys)) xs ys))

(def lcs
  (memoize
   (fn [[x & xs] [y & ys]]
     (cond
      (or (= x nil) (= y nil)) nil
      (= x y) (cons x (lcs xs ys))
      :else (longest (lcs (cons x xs) ys)
                     (lcs xs (cons y ys)))))))


lcs = (s1, s2) ->
  len1 = s1.length
  len2 = s2.length

  # Create a virtual matrix that is (len1 + 1) by (len2 + 1),
  # where m[i][j] is the longest common string using only
  # the first i chars of s1 and first j chars of s2.  The
  # matrix is virtual, because we only keep the last two rows
  # in memory.
  prior_row = ('' for i in [0..len2])

  for i in [0...len1]
    row = ['']
    for j in [0...len2]
      if s1[i] == s2[j]
        row.push prior_row[j] + s1[i]
      else
        subs1 = row[j]
        subs2 = prior_row[j+1]
        if subs1.length > subs2.length
          row.push subs1
        else
          row.push subs2
    prior_row = row

  row[len2]

s1 = "thisisatest"
s2 = "testing123testing"
console.log lcs(s1, s2)


func lComSubStr(w1, w2) {
    var (len, end) = (0, 0)
    var mat  = Array.Empty(w1.Length() + 1, () => Array.Empty(w2.Length() + 1, 0))
    var (i, j) = (0, 0)

    for sLett in w1 {
      for tLett in w2 {
        if tLett == sLett {
            let curLen = mat[i][j] + 1
            mat[i + 1][j + 1] = curLen
            if curLen > len {
                len = curLen
                end = i
            }
        }
        j += 1
      }
      j = 0
      i += 1
    }
    String(values: w1).Substring((end + 1) - len, len)
}

func comSubStr(w1, w2) {
  return String(lComSubStr(w1.Iterate().ToArray(), w2.Iterate().ToArray()))
}

comSubStr("thisisatest", "testing123testing") // "test"


defmodule LCS do
  def longest_common_substring(a,b) do
    alist = to_charlist(a) |> Enum.with_index
    blist = to_charlist(b) |> Enum.with_index
    lengths = for i <- 0..length(alist)-1, j <- 0..length(blist), into: %{}, do: {{i,j},0}
    Enum.reduce(alist, {lengths,0,""}, fn {x,i},acc ->
      Enum.reduce(blist, acc, fn {y,j},{map,gleng,lcs} ->
        if x==y do
          len = if i==0 or j==0, do: 1, else: map[{i-1,j-1}]+1
          map = %{map | {i,j} => len}
          if len > gleng, do: {map, len, String.slice(a, i - len + 1, len)},
                        else: {map, gleng, lcs}
        else
          {map, gleng, lcs}
        end
      end)
    end)
    |> elem(2)
  end
end

IO.puts LCS.longest_common_substring("thisisatest", "testing123testing")


USING: io sequences.extras ;

"thisisatest" "testing123testing" longest-subseq print


program main
implicit none
   call  compare('testing123testingthing', 'thisis',                 'thi')
   call  compare('testing',                'sting',                  'sting')
   call  compare('thisisatest_stinger',    'testing123testingthing', 'sting')
   call  compare('thisisatest_stinger',    'thisis',                 'thisis')
   call  compare('thisisatest',            'testing123testing',      'test')
   call  compare('thisisatest',            'thisisatest',            'thisisatest')
contains
subroutine compare(a,b,answer)
character(len=*),intent(in) :: a, b, answer
character(len=:),allocatable :: a2, match
character(len=*),parameter :: g='(*(g0))'
integer :: i
   a2=a ! should really make a2 the shortest and b the longest
   match=''
   do i=1,len(a2)-1
      call compare_sub(a2,b,match)
      if(len(a2).lt.len(match))exit
      a2=a2(:len(a2)-1)
   enddo
   write(*,g) merge('(PASSED)','(FAILED)',answer.eq.match), &
   & ' longest match found: "',match,'"; expected "',answer,'"', &
   & ' comparing "',a,'" and "',b,'"'
end subroutine
subroutine compare_sub(a,b,match)
character(len=*),intent(in) :: a, b
character(len=:),allocatable :: match
integer :: left, foundat, len_a
   len_a=len(a)
   do left=1,len_a
      foundat=index(b,a(left:))
      if(foundat.ne.0.and.len(match).lt.len_a-left+1)then
         if(len(a(left:)).gt.len(match))then
            match=a(left:)
            exit
         endif
      endif
   enddo
end subroutine compare_sub
end program main


(defun longest-common-subsequence (array1 array2)
  (let* ((l1 (length array1))
         (l2 (length array2))
         (results (make-array (list l1 l2) :initial-element nil)))
    (declare (dynamic-extent results))
    (labels ((lcs (start1 start2)
               ;; if either sequence is empty, return (() 0)
               (if (or (eql start1 l1) (eql start2 l2)) (list '() 0)
                 ;; otherwise, return any memoized value
                 (let ((result (aref results start1 start2)))
                   (if (not (null result)) result
                     ;; otherwise, compute and store a value
                     (setf (aref results start1 start2)
                           (if (eql (aref array1 start1) (aref array2 start2))
                             ;; if they start with the same element,
                             ;; move forward in both sequences
                             (destructuring-bind (seq len)
                                 (lcs (1+ start1) (1+ start2))
                               (list (cons (aref array1 start1) seq) (1+ len)))
                             ;; otherwise, move ahead in each separately,
                             ;; and return the better result.
                             (let ((a (lcs (1+ start1) start2))
                                   (b (lcs start1 (1+ start2))))
                               (if (> (second a) (second b))
                                 a
                                 b)))))))))
      (destructuring-bind (seq len) (lcs 0 0)
        (values (coerce seq (type-of array1)) len)))))


import std.stdio, std.array;

T[] lcs(T)(in T[] a, in T[] b) pure nothrow @safe {
    if (a.empty || b.empty) return null;
    if (a[0] == b[0])
        return a[0] ~ lcs(a[1 .. $], b[1 .. $]);
    const longest = (T[] x, T[] y) => x.length > y.length ? x : y;
    return longest(lcs(a, b[1 .. $]), lcs(a[1 .. $], b));
}

void main() {
    lcs("thisisatest", "testing123testing").writeln;
}


V revdate = ‘2021-11-14’

V elements =
   ‘hydrogen helium lithium beryllium boron carbon nitrogen oxygen fluorine ’""
   ‘neon sodium magnesium aluminum silicon phosphorous sulfur chlorine argon ’""
   ‘potassium calcium scandium titanium vanadium chromium manganese iron ’""
   ‘cobalt nickel copper zinc gallium germanium arsenic selenium bromine ’""
   ‘krypton rubidium strontium yttrium zirconium niobium molybdenum ’""
   ‘technetium ruthenium rhodium palladium silver cadmium indium tin ’""
   ‘antimony tellurium iodine xenon cesium barium lanthanum cerium ’""
   ‘praseodymium neodymium promethium samarium europium gadolinium terbium ’""
   ‘dysprosium holmium erbium thulium ytterbium lutetium hafnium tantalum ’""
   ‘tungsten rhenium osmium iridium platinum gold mercury thallium lead ’""
   ‘bismuth polonium astatine radon francium radium actinium thorium ’""
   ‘protactinium uranium neptunium plutonium americium curium berkelium ’""
   ‘californium einsteinium fermium mendelevium nobelium lawrencium ’""
   ‘rutherfordium dubnium seaborgium bohrium hassium meitnerium darmstadtium ’""
   ‘roentgenium copernicium nihonium flerovium moscovium livermorium ’""
   ‘tennessine oganesson’

V items = elements.split(‘ ’)

print(‘Last revision date: ’revdate)
print(‘Number of elements: ’items.len)
print(‘Last element      : ’items.last)


HelloString:
db "Hello World" ;no null terminator
GoodbyeString:
db "Goodbye World!",0

PrintString HelloString ;unimplemented macro.


Function LCS(a As String, b As String) As String
    If Len(a) = 0 Or Len(b) = 0 Then Return ""
    While Len(b)
        For j As Integer = Len(b) To 1 Step -1
            If Instr(a, Left(b, j)) Then Return Left(b, j)
        Next j
        b = Mid(b, 2)
    Wend
End Function

Print LCS("thisisatest", "testing123testing")
Sleep


package main

import "fmt"

func lcs(a, b string) (output string) {
    lengths := make([]int, len(a)*len(b))
    greatestLength := 0
    for i, x := range a {
        for j, y := range b {
            if x == y {
                if i == 0 || j == 0 {
                    lengths[i*len(b)+j] = 1
                } else {
                    lengths[i*len(b)+j] = lengths[(i-1)*len(b)+j-1] + 1
                }
                if lengths[i*len(b)+j] > greatestLength {
                    greatestLength = lengths[i*len(b)+j]
                    output = a[i-greatestLength+1 : i+1]
                }
            }
        }
    }
    return
}

func main() {
    fmt.Println(lcs("thisisatest", "testing123testing"))
}


import 'dart:math';

String lcsRecursion(String a, String b) {
  int aLen = a.length;
  int bLen = b.length;

  if (aLen == 0 || bLen == 0) {
    return "";
  } else if (a[aLen-1] == b[bLen-1]) {
    return lcsRecursion(a.substring(0,aLen-1),b.substring(0,bLen-1)) + a[aLen-1];
  } else {
    var x = lcsRecursion(a, b.substring(0,bLen-1));
    var y = lcsRecursion(a.substring(0,aLen-1), b);
    return (x.length > y.length) ? x : y;
  }
}

String lcsDynamic(String a, String b) {
  var lengths = new List<List<int>>.generate(a.length + 1,
      (_) => new List.filled(b.length+1, 0), growable: false);

  // row 0 and column 0 are initialized to 0 already
  for (int i = 0; i < a.length; i++) {
    for (int j = 0; j < b.length; j++) {
      if (a[i] == b[j]) {
        lengths[i+1][j+1] = lengths[i][j] + 1;
      } else {
        lengths[i+1][j+1] = max(lengths[i+1][j], lengths[i][j+1]);
      }
    }
  }

  // read the substring out from the matrix
  StringBuffer reversedLcsBuffer = new StringBuffer();
  for (int x = a.length, y = b.length; x != 0 && y != 0;) {
    if (lengths[x][y] == lengths[x-1][y]) {
      x--;
    } else if (lengths[x][y] == lengths[x][y-1]) {
      y--;
    } else {
      assert(a[x-1] == b[y-1]);
      reversedLcsBuffer.write(a[x-1]);
      x--;
      y--;
    }
  }

  // reverse String
  var reversedLCS = reversedLcsBuffer.toString();
  var lcsBuffer = new StringBuffer();
  for(var i = reversedLCS.length - 1; i>=0; i--) {
    lcsBuffer.write(reversedLCS[i]);
  }
  return lcsBuffer.toString();
}

void main() {
  print("lcsDynamic('1234', '1224533324') =  ${lcsDynamic('1234', '1224533324')}");
  print("lcsDynamic('thisisatest', 'testing123testing') = ${lcsDynamic('thisisatest', 'testing123testing')}");
  print("lcsDynamic('', 'x') = ${lcsDynamic('', 'x')}");
  print("lcsDynamic('x', 'x') = ${lcsDynamic('x', 'x')}");
  print('');
  print("lcsRecursion('1234', '1224533324') = ${lcsRecursion('1234', '1224533324')}");
  print("lcsRecursion('thisisatest', 'testing123testing') = ${lcsRecursion('thisisatest', 'testing123testing')}");
  print("lcsRecursion('', 'x') = ${lcsRecursion('', 'x')}");
  print("lcsRecursion('x', 'x') = ${lcsRecursion('x', 'x')}");
}


(define $common-seqs
  (lambda [$xs $ys]
    (match-all [xs ys] [(list char) (list char)]
      [[(loop $i [1 $n] <join _ <cons $c_i ...>> _)
        (loop $i [1 ,n] <join _ <cons ,c_i ...>> _)]
       (map (lambda [$i] c_i) (between 1 n))])))

(define $lcs (compose common-seqs rac))


defmodule LCS do
  def lcs(a, b) do
    lcs(to_charlist(a), to_charlist(b), []) |> to_string
  end

  defp lcs([h|at], [h|bt], res), do: lcs(at, bt, [h|res])
  defp lcs([_|at]=a, [_|bt]=b, res) do
    Enum.max_by([lcs(a, bt, res), lcs(at, b, res)], &length/1)
  end
  defp lcs(_, _, res), do: res |> Enum.reverse
end

IO.puts LCS.lcs("thisisatest", "testing123testing")
IO.puts LCS.lcs('1234','1224533324')


HelloString:
DC.B "Hello World" ;no null terminator
GoodbyeString:
DC.B "Goodbye World!",0
EVEN

PrintString HelloString ;unimplemented macro.


revDate: "2021-02-05"

elementString:
    "hydrogen helium lithium beryllium boron carbon nitrogen oxygen fluorine " ++
    "neon sodium magnesium aluminum silicon phosphorous sulfur chlorine argon " ++
    "potassium calcium scandium titanium vanadium chromium manganese iron "  ++
    "cobalt nickel copper zinc gallium germanium arsenic selenium bromine "  ++
    "krypton rubidium strontium yttrium zirconium niobium molybdenum "  ++
    "technetium ruthenium rhodium palladium silver cadmium indium tin "  ++
    "antimony tellurium iodine xenon cesium barium lanthanum cerium "  ++
    "praseodymium neodymium promethium samarium europium gadolinium terbium "  ++
    "dysprosium holmium erbium thulium ytterbium lutetium hafnium tantalum "  ++
    "tungsten rhenium osmium iridium platinum gold mercury thallium lead "  ++
    "bismuth polonium astatine radon francium radium actinium thorium "  ++
    "protactinium uranium neptunium plutonium americium curium berkelium "  ++
    "californium einsteinium fermium mendelevium nobelium lawrencium "  ++
    "rutherfordium dubnium seaborgium bohrium hassium meitnerium darmstadtium "  ++
    "roentgenium copernicium nihonium flerovium moscovium livermorium "  ++
    "tennessine oganesson"

elements: split.words elementString

print ["Last revision date:" revDate]
print ["Number of elements:" size elements]
print ["Last element in list:" last elements]


# syntax: GAWK -f LONG_LITERALS_WITH_CONTINUATIONS.AWK
BEGIN {
    ll_using_concatenation() ; ll_info()
    ll_using_continuation() ; ll_info()
    exit(0)
}
function ll_info(  arr,n,x) {
    n = split(str,arr," ")
    printf("version: %s\n",revised)
    printf("number of elements: %d\n",n)
    printf("last element: %s\n",arr[n])
    x = 30
    printf("first & last %d characters: %s & %s\n\n",x,substr(str,1,x),substr(str,length(str)-x))
}
function ll_remove_multiple_spaces(s) {
# all element names were wrapped in one or more spaces for readability and ease of future editing
# they are removed here
    gsub(/\n/," ",s) # AWK95 needs, GAWK & TAWK don't
    while (s ~ /  /) {
      gsub(/  +/," ",s)
    }
    sub(/^ /,"",s)
    sub(/ $/,"",s)
    return(s)
}
function ll_using_concatenation(  s) {
s=s" hydrogen     helium       lithium      beryllium     "
s=s" boron        carbon       nitrogen     oxygen        "
s=s" fluorine     neon         sodium       magnesium     "
s=s" aluminum     silicon      phosphorous  sulfur        "
s=s" chlorine     argon        potassium    calcium       "
s=s" scandium     titanium     vanadium     chromium      "
s=s" manganese    iron         cobalt       nickel        "
s=s" copper       zinc         gallium      germanium     "
s=s" arsenic      selenium     bromine      krypton       "
s=s" rubidium     strontium    yttrium      zirconium     "
s=s" niobium      molybdenum   technetium   ruthenium     "
s=s" rhodium      palladium    silver       cadmium       "
s=s" indium       tin          antimony     tellurium     "
s=s" iodine       xenon        cesium       barium        "
s=s" lanthanum    cerium       praseodymium neodymium     "
s=s" promethium   samarium     europium     gadolinium    "
s=s" terbium      dysprosium   holmium      erbium        "
s=s" thulium      ytterbium    lutetium     hafnium       "
s=s" tantalum     tungsten     rhenium      osmium        "
s=s" iridium      platinum     gold         mercury       "
s=s" thallium     lead         bismuth      polonium      "
s=s" astatine     radon        francium     radium        "
s=s" actinium     thorium      protactinium uranium       "
s=s" neptunium    plutonium    americium    curium        "
s=s" berkelium    californium  einsteinium  fermium       "
s=s" mendelevium  nobelium     lawrencium   rutherfordium "
s=s" dubnium      seaborgium   bohrium      hassium       "
s=s" meitnerium   darmstadtium roentgenium  copernicium   "
s=s" nihonium     flerovium    moscovium    livermorium   "
s=s" tennessine   oganesson                               "
    str = ll_remove_multiple_spaces(s)
    revised = "2020-06-30"
}
function ll_using_continuation(  s) {
# works with: AWK95, GAWK 3.1.4, GAWK 5, TAWK
s="\
 hydrogen     helium       lithium      beryllium     \
 boron        carbon       nitrogen     oxygen        \
 fluorine     neon         sodium       magnesium     \
 aluminum     silicon      phosphorous  sulfur        \
 chlorine     argon        potassium    calcium       \
 scandium     titanium     vanadium     chromium      \
 manganese    iron         cobalt       nickel        \
 copper       zinc         gallium      germanium     \
 arsenic      selenium     bromine      krypton       \
 rubidium     strontium    yttrium      zirconium     \
 niobium      molybdenum   technetium   ruthenium     \
 rhodium      palladium    silver       cadmium       \
 indium       tin          antimony     tellurium     \
 iodine       xenon        cesium       barium        \
 lanthanum    cerium       praseodymium neodymium     \
 promethium   samarium     europium     gadolinium    \
 terbium      dysprosium   holmium      erbium        \
 thulium      ytterbium    lutetium     hafnium       \
 tantalum     tungsten     rhenium      osmium        \
 iridium      platinum     gold         mercury       \
 thallium     lead         bismuth      polonium      \
 astatine     radon        francium     radium        \
 actinium     thorium      protactinium uranium       \
 neptunium    plutonium    americium    curium        \
 berkelium    californium  einsteinium  fermium       \
 mendelevium  nobelium     lawrencium   rutherfordium \
 dubnium      seaborgium   bohrium      hassium       \
 meitnerium   darmstadtium roentgenium  copernicium   \
 nihonium     flerovium    moscovium    livermorium   \
 tennessine   oganesson                               \
"
    str = ll_remove_multiple_spaces(s)
    revised = "30JUN2020"
}


import Data.Ord (comparing)
import Data.List (maximumBy, intersect)

subStrings :: [a] -> [[a]]
subStrings s =
  let intChars = length s
  in [ take n $ drop i s
     | i <- [0 .. intChars - 1]
     , n <- [1 .. intChars - i] ]

longestCommon :: Eq a => [a] -> [a] -> [a]
longestCommon a b =
  maximumBy (comparing length) (subStrings a `intersect` subStrings b)

main :: IO ()
main = putStrLn $ longestCommon "testing123testing" "thisisatest"