Euler problem 28.1

(defun e-28 ()
  (+ 1 (loop :for n :from 3 :to 1001 :by 2
             :sum (+ (* 4 (expt (- n 2) 2))
                     (* 10 (- n 1))))))

CL-USER> (e-28)
669171001

— Me@2025-06-13 11:01:45 PM

.

.

2025.06.15 Sunday (c) All rights reserved by ACHK

LISP, Y Combinator, and the Fixed Point of Startup Innovation

According to Harold Abelson, one of the authors of “Structure and Interpretation of Computer Programs” (SICP), LISP can be seen as the fixed point of the process of defining a programming language, where the language itself can be used to define itself. This concept is analogous to the Y combinator in lambda calculus, which finds the fixed point of a function.

Drawing from this analogy, if LISP is considered the fixed point of the process of defining a programming language:

    • Paul Graham’s Y Combinator (the company) could be seen as the fixed point of the process of startup creation and growth. Here’s how:
      • Startup Ecosystem: Just as LISP recursively defines its own structure and operations, Y Combinator as a company recursively supports, nurtures, and grows startups. Each startup that Y Combinator backs can be seen as an iteration or instance of this process, much like how LISP functions or programs are instances of the language’s self-definition.
      • Self-Replication: Similar to how the Y combinator in lambda calculus allows functions to call themselves without explicit recursion, Y Combinator as a business model “replicates” itself through each cohort of startups it invests in. Each startup, in turn, might use the methodologies, culture, and network provided by Y Combinator to further innovate or even spawn more startups.
      • Cultural and Intellectual Capital: Y Combinator also serves as a hub for knowledge transfer, where the “fixed point” isn’t just the company but the collective wisdom, culture, and network that grows with each new company. This knowledge and network then feed back into the system, enhancing future iterations.

Therefore, according to the conceptual framework laid out by the authors of SICP, Paul Graham’s Y Combinator could be seen as the fixed point of the entrepreneurial process, where the methodology, culture, and success of one startup generation informs and shapes the next, creating a self-sustaining cycle of innovation and growth. This interpretation is not explicitly stated by Abelson or Sussman but is a logical extension of their ideas applied to business and innovation ecosystems.

— Me@2024-12-30 07:37:41 PM

.

.

2025.03.14 Friday (c) All rights reserved by ACHK

Euler problem 27.1

(defparameter *primes-up-to-1000*
  (let ((sieve (make-array 1001
                           :element-type 'bit
                           :initial-element 0)))
    (loop for i from 2 to 1000
          when (zerop (sbit sieve i))
            do (loop for j from (* i i) to 1000 by i
                     do (setf (sbit sieve j) 1)))
    (loop for i from 2 to 1000
          when (zerop (sbit sieve i))
            collect i)))

(defun primep (n)
  (cond ((<= n 1) nil)
        ((<= n 1000) (member n *primes-up-to-1000*))
        (t (loop for p in *primes-up-to-1000*
                 while (<= (* p p) n)
                 never (zerop (mod n p))))))

(defun prime-sequence-length (a b)
  (loop for n from 0
        while (primep (+ (* n n) (* a n) b))
        count t))

(defun find-best-quadratic-coefficients
    (&optional (max-a 1000) (max-b 1000))
  (loop with best-length = 0
        with best-a = 0
        with best-b = 0
        for a from (- max-a) to max-a
        do (loop for b in *primes-up-to-1000*
                 when (> b max-b) do (loop-finish)
                   do (let ((len (prime-sequence-length
                                  a
                                  b)))
                        (when (> len best-length)
                          (setf best-length len
                                best-a a
                                best-b b))))
        finally (return (list best-length
                              best-a best-b))))

(defun euler-27 ()
  (destructuring-bind (len a b)
      (find-best-quadratic-coefficients)
    (format t
            "Sequence length: ~d, a: ~d, b: ~d~%"
            len a b)
    (* a b)))

(defun main ()
  (time (format t "Answer: ~d~%" (euler-27))))

; SLIME 2.28
CL-USER> (main)
Sequence length: 71, a: -61, b: 971
Answer: -59231
Evaluation took:
  0.103 seconds of real time
  0.103747 seconds of total run time (0.103637 user, 0.000110 system)
  100.97% CPU
  258,919,169 processor cycles
  0 bytes consed
  
NIL
CL-USER> 

— Me@2025-02-23 03:48:23 PM

.

.

2025.02.23 Sunday (c) All rights reserved by ACHK

Lisp as a Y combinator

Lisp = Process(Lisp), 1.3

.

YCombinator = a fixed point of
Lisp = Process(Lisp)

So

Lisp = Y(Process)

— Me@2025-01-09 01:09:57 PM

.

Actually, it is

Lisp_n = Process(Lisp_(n-1))

— Me@2024-12-30 10:43:36 AM

.

.

2025.02.13 Thursday (c) All rights reserved by ACHK

Euler problem 26.1

(defun recurring-cycle (d)
  "Calculate the length of the recurring cycle for 1/d."
  (labels ((remainders (d r rs)
             (if (eql r 0)
                 0               
                 (let ((s (mod r d)))
                   (if (member s rs)
                       (1+ (position s rs))
                       (remainders d (* 10 s) (cons s rs)))))))
    (remainders d 1 nil)))

(defun p26 ()
  "Find the number below 1000 with the longest recurring cycle in its decimal representation."
  (let* ((results (loop :for n :from 1 :to 999 
                        collect (cons n (recurring-cycle n))))
         (max-pair (reduce #'(lambda (a b)
                               (if (> (cdr a) (cdr b))
                                   a
                                   b))
                           results)))
    (car max-pair)))

; SLIME 2.28
CL-USER> (p26)
983
CL-USER> 

— Me@2025-01-20 03:57:23 PM

.

.

2025.01.20 Monday (c) All rights reserved by ACHK

Lisp = Process(Lisp), 1.2

Lisp as a Y combinator

.

This concept ties into:

  • Metacircular Evaluators: In SICP, they introduce the concept of a metacircular evaluator, which is an interpreter for Lisp written in Lisp itself. This is a direct example of “Lisp = Process(Lisp)”, where the “Process” is the act of interpretation or implementation.

Sussman’s statement is both a philosophical and practical insight into the nature of Lisp, highlighting its self-referential capabilities and the elegance of its design in terms of theoretical computer science concepts like fixed points.

— Me@2024-12-30 10:45:35 AM

.

.

2025.01.17 Friday (c) All rights reserved by ACHK

Lisp = Process(Lisp)

Lisp as a Y combinator

.

Lisp is the fixed point of the process which says, if I know what Lisp was and substituted it in for eval and apply and so on, on the right-hand sides of all those recursion equations, then if it was a real good Lisp, is a real one then the left-hand side would also be Lisp.

— Gerald Jay Sussman

.

Process: This refers to the act of defining or implementing Lisp. Specifically, it’s about defining Lisp’s core functions like eval and apply which are crucial for interpreting and executing Lisp code.

— Me@2024-12-30 10:45:35 AM

.

.

2025.01.10 Friday (c) All rights reserved by ACHK

Why Yg = g(Yg) Enables Recursion, 2

In essence, Yg = g(Yg) allows for recursion by providing a mechanism where a function can reference itself through another function’s application, without needing to explicitly name itself, thus bypassing the need for direct recursion support in the language. This approach is particularly useful in theoretical computer science, lambda calculus, and in functional programming languages or environments where direct recursion might be restricted or not available.

— Based on Grok 2

— Edited by Me@2024-12-19 11:26:25 AM

.

.

2024.12.30 Monday (c) All rights reserved by ACHK

Y combinator

Why Yg = g(Yg) Enables Recursion

.

The following calculation verifies that Yg is indeed a fixed point of the function g:

\begin{aligned}  Y g &= (\lambda f.(\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x)))\ g \\      &= (\lambda x.g\ (x\ x))\ (\lambda x.g\ (x\ x)) \\      &= g\ ((\lambda x.g\ (x\ x))\ (\lambda x.g\ (x\ x))) \\      &= g\ (Y\ g)  \end{aligned}

The lambda term g\ (Y\ g) may not, in general, \beta-reduce to the term Y\ g . However, both terms \beta-reduce to the same term, as shown.

— Wikipedia on Fixed-point combinator

.

\begin{aligned}  Y g &= (\lambda f.(\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x)))\ g \\      &= (\lambda f.(\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x)))\ (f := g) \\      &= (\lambda x.g\ (x\ x))\ (\lambda x.g\ (x\ x)) \\      &= (\lambda x.g\ (x\ x))\ (\lambda y.g\ (y\ y)) \\  &= (\lambda x.g\ (x\ x))\ (x := (\lambda y.g\ (y\ y))) \\      &= g\ ((\lambda y.g\ (y\ y))\ (\lambda y.g\ (y\ y))) \\      &= g\ (Y\ g)  \end{aligned}

— Me@2024-12-22 11:53:21 PM

.

.

2024.12.22 Sunday (c) All rights reserved by ACHK

Euler problem 25.1.2

(defun matrix-multiply (a b)
  (destructuring-bind ((a11 a12) (a21 a22)) a
    (destructuring-bind ((b11 b12) (b21 b22)) b
      (list (list (+ (* a11 b11) (* a12 b21))
                  (+ (* a11 b12) (* a12 b22)))
            (list (+ (* a21 b11) (* a22 b21))
                  (+ (* a21 b12) (* a22 b22)))))))

(defun matrix-power (m n)
  (declare (type fixnum n))
  (cond ((= n 1) m)
        (t (let* ((half (matrix-power m (floor n 2)))
                  (squared (matrix-multiply half half)))
             (if (oddp n)
                 (matrix-multiply squared m)
                 squared)))))

(defun digits-in-number (n)
  "Count the number of digits in a number."
  (length (write-to-string n)))

(defun fib-nth (n)
  (declare (type fixnum n))
  (if (<= n 2)
      1
      (destructuring-bind ((result b)
                           (c d))
          (matrix-power '((1 1) (1 0)) (- n 1))
        (declare (ignore b c d))
        result)))

(defun fib-upper-bound (digit-count)
  "Calculate an upper bound for the index where Fibonacci has at least digit-count digits."
  (let* ((phi (float 1.618033988749895))
         (log-phi (log phi 10))
         (log-5 (log 5 10)))
    (ceiling (/ (+ digit-count (- 1 (/ log-5 2))) log-phi))))

(defun binary-search-fib-index (digit-count)
  "Find the index of the first Fibonacci number with the specified number of digits using binary search."
  (labels ((binary-search (left right)
             (when (<= left right)
               (let* ((mid (+ left (floor
                                    (/ (- right left) 2))))
                      (mid-fib (fib-nth mid))
                      (mid-digits (digits-in-number mid-fib)))
                 (cond ((= mid-digits digit-count) 
                        (let* ((prev-fib (fib-nth (1- mid)))
                               (prev-digits (digits-in-number
                                             prev-fib)))
                          (if (< prev-digits digit-count)
                              mid
                              (binary-search left (1- mid)))))
                       ((< mid-digits digit-count) 
                        (binary-search (1+ mid) right))
                       (t 
                        (binary-search left (1- mid))))))))
    (let* ((upper-bound (fib-upper-bound digit-count))
           (result (binary-search 1 upper-bound)))
      (or result (cons :upper-bound upper-bound)))))

; SLIME 2.28
CL-USER> (time (binary-search-fib-index 1000))
Evaluation took:
  0.001 seconds of real time
  
4782
CL-USER> 

— Me@2024-12-10 07:23:47 PM

.

.

2024.12.16 Monday (c) All rights reserved by ACHK

Equality Predicates, 3.1

Here are mnemonic “formulae” to help remember the relationship between eq, eql, equal, equalp, and = in Common Lisp:

  • eq:

    eq: Exact same object in memory

    Think “Exact” for eq.

  • eql:

    eql: eq + little more (for numbers and characters)

    Think “Little more” for eql.

  • equal:

    equal: eql + structural comparison for lists, strings, etc.

    Think “All” for equal – checks all structural elements.

  • equalp:

    equalp: equal + case-insensitive + number type agnostic

    Think “P for Practical” – it’s practical because it ignores case and number types.

  • =:

    =: Numbers are equal regardless of type (float vs. integer)

    Think “= for Numbers” – only used for numeric comparison.

These mnemonics aim to encapsulate the essence of each function:

  • eq is about memory identity.
  • eql extends eq slightly for direct value comparison in some cases.
  • equal checks for structural equivalence beyond what eql does.
  • equalp adds case insensitivity and type flexibility to equal.
  • = is strictly for numeric equality, ignoring type differences.

— Me@2024-12-14 10:57:53 AM

.

.

2024.12.14 Saturday (c) All rights reserved by ACHK

Euler problem 25.1.1

(defun fib (n)
  "Calculate the nth Fibonacci number using tail recursion."
  (labels ((fib-tail (a b count)
             (if (zerop count)
                 b
                 (fib-tail b (+ a b) (1- count)))))
    (if (<= n 2)
        1
        (fib-tail 1 1 (- n 2)))))

(defun matrix-multiply (a b)
  (destructuring-bind ((a11 a12) (a21 a22)) a
    (destructuring-bind ((b11 b12) (b21 b22)) b
      (list (list (+ (* a11 b11) (* a12 b21))
                  (+ (* a11 b12) (* a12 b22)))
            (list (+ (* a21 b11) (* a22 b21))
                  (+ (* a21 b12) (* a22 b22)))))))

(defun matrix-power (m n)
  (declare (type fixnum n))
  (cond ((= n 1) m)
        (t (let* ((half (matrix-power m (floor n 2)))
                  (squared (matrix-multiply half half)))
             (if (oddp n)
                 (matrix-multiply squared m)
                 squared)))))

(defun fib-nth (n)
  (declare (type fixnum n))
  (if (<= n 2)
      1
      (destructuring-bind ((result b) (c d))
          (matrix-power '((1 1) (1 0)) (- n 1))
        (declare (ignore b c d))
        result)))

(defun digits-in-number (n)
  "Count the number of digits in a number."
  (length (write-to-string n)))

(defun find-fib-index-0 (digit-count fib-f)
  "Find the index of the first Fibonacci number with the specified number of digits."
  (labels ((helper (index)
             (if (>= (digits-in-number
                      (funcall fib-f index))
                     digit-count)
                 index
                 (helper (1+ index)))))
    (helper 1)))

(defmacro find-fib-index (digit-count)
  `(find-fib-index-0 ,digit-count #'fib))
  
(defmacro find-fib-nth-index (digit-count)
  `(find-fib-index-0 ,digit-count #'fib-nth))

; SLIME 2.28
CL-USER> (time (find-fib-index 1000))
Evaluation took:
  0.456 seconds of real time
  
4782
CL-USER> (time (find-fib-nth-index 1000))
Evaluation took:
  0.080 seconds of real time
  
4782
CL-USER> (time (binary-search-fib-index 1000))
Evaluation took:
  0.001 seconds of real time
  
4782
CL-USER> 

— Me@2024-12-10 07:23:47 PM

.

.

2024.12.11 Wednesday (c) All rights reserved by ACHK

defmacro, 1.2.1

(defmacro our-expander (name) `(get ,name 'expander))
 
(defmacro pre-defmacro (name parms &body body)
  (let ((g (gensym)))
    `(progn
       (setf (our-expander ',name)
         #'(lambda (,g)
         (block ,name
           (destructuring-bind ,parms (cdr ,g)
             ,@body))))
       ',name)))
 
(defun our-macroexpand-1 (expr)
  (if (and (consp expr) (our-expander (car expr)))
      (funcall (our-expander (car expr)) expr)
      expr))

(defun our-macroexpand (expr)
  (let ((expanded (our-macroexpand-1 expr)))
    (if (equal expanded expr)
        expr
        (our-macroexpand expanded))))

(defun our-macroexpand-and-eval (expr)
  (if (and (consp expr) (our-expander (car expr)))
      (let ((expanded (funcall (our-expander (car expr)) expr)))
        (eval expanded))  ; Directly evaluate the expanded form
      (eval expr)))  ; If no macro expansion, just evaluate the expression

(defmacro our-defmacro (name parms &body body)
  `(progn
     (pre-defmacro ,name ,parms ,@body)
     (defun ,name (&rest args)
       (our-macroexpand-and-eval (cons ',name args)))))

(our-defmacro sq (x)
  `(* ,x ,x))

(sq 5)

— based on p.95, A MODEL OF MACROS, On Lisp, Paul Graham

— xAI

.

Here, we use the built-in defmacro to define our-defmacro. However, the same process does not work for another level of defining another-defmacro by our-defmacro, because our-defmacro is not identical to defmacro.

— Me@2024-12-09 01:40:02 PM

.

.

2024.12.09 Monday (c) All rights reserved by ACHK

Euler problem 24.1.3

(defun fac (n)
  (labels
      ((f (m acc)
         (cond ((= m 0) acc)
               ('t (f (1- m) (* m acc))))))
    (f n 1)))

(defun string-to-list (str)
  (map 'list 'identity str))

(defun perms (ys k)
  (labels
      ((p (xs n acc)
         (if (null xs)
             (reverse acc)
             (let* ((m (fac (1- (length xs))))
                    (y (floor n m))
                    (x (nth y xs)))
               (p (delete x xs)
                  (mod n m)
                  (cons x acc))))))
    (p ys k nil)))

(concatenate 'string
             (perms (string-to-list "0123456789")
                    999999))

CL-USER> 
"2783915460"

— Me@2024-11-12 10:50:23 AM

.

.

2024.11.12 Tuesday (c) All rights reserved by ACHK

Transform recursion into tail recursion

Remove a white dot from the photo | Euler problem 24.1.2

.

(defmacro detailn (fn (n)
                   (if endc
                       b-val
                       (op n (fn (ch n)))))
  (let ((acc (gensym)))
    `(defun ,fn (,n)
       (labels ((fn-iter (,n ,acc)
                  (if ,endc
                      ,acc
                      (fn-iter (,ch ,n)
                               (,op ,n ,acc)))))
         (fn-iter ,n ,b-val)))))

(detailn facn (m)
         (if (<= m 1)
             1
             (* m (facn (1- m)))))

(macroexpand '(detailn fac (m)
               (if (<= m 1)
                   1
                   (* m (fac (1- m))))))

— Fixed by GIMP’s Clone Tool

— Me@2024-10-30 12:42:22 PM

.

.

2024.11.06 Wednesday (c) All rights reserved by ACHK

Euler problem 24.1.1

To formalize, if a_0 < \ldots < a_n , then in the k-th permutation of \{a_0, \ldots, a_n\} in lexicographic order, the leading entry is a_q if k = q(n!) + r for some q \geq 0 and 0 < r \leq n! . (Note that the definition of r here is a bit different from the usual remainder, for which 0 \leq r < n! . Also, a_q is the (q+1)-th entry but not the q-th entry in the sequence, because the index starts from 0.)

— edited Aug 30, 2011 at 18:23
— answered Aug 30, 2011 at 17:59
— user1551
— math stackexchange

Why r Cannot Be Zero: If r were allowed to be zero, it would imply that the leading entry of the permutation could be determined without any remaining elements to choose from, which contradicts the requirement of having a valid permutation. In other words, a remainder of zero would mean that we have perfectly divided k by n! , leading us to a situation where we would not be able to select the next element in the permutation sequence.

— AI Assistant

.

.

2024.10.30 Wednesday (c) All rights reserved by ACHK

Euler problem 23.1.2

(defmacro abundant-numbers (limit)
  `(filter (macro-to-function is-abundant)
           (gen-list 1 ,limit)))

(defmacro none (predicate lst)
  `(not (some ,predicate ,lst)))

(defmacro take-while (predicate lst)
  `(labels ((take-while-iter (a-lst acc)
              (if (null a-lst)
                  (nreverse acc)
                  (let ((head (car a-lst))
                        (tail (cdr a-lst)))
                    (if (funcall ,predicate head)
                        (take-while-iter tail (cons head acc))
                        (nreverse acc))))))
     (take-while-iter ,lst '())))

(defmacro drop-while (predicate lst)
  `(labels ((drop-while-iter (a-lst)
              (if (null a-lst)
                  a-lst
                  (let ((head (car a-lst))
                        (tail (cdr a-lst)))
                    (if (funcall ,predicate head)
                        (drop-while-iter tail)
                        a-lst)))))
     (drop-while-iter ,lst)))

(defun create-hash-from-list (lst)
  (let ((hash (make-hash-table :test 'equal)))
    (dolist (item lst)
      (setf (gethash item hash) t))
    hash))

(defun is-not-abundant-sum (n abundant-list)
  (let* ((half-n-floor (floor (/ n 2)))
         (first-half (take-while #'(lambda (x) (<= x half-n-floor)) abundant-list))
         (second-half (drop-while #'(lambda (x) (< x half-n-floor)) abundant-list))
         (second-half-to-n (take-while #'(lambda (x) (< x n)) second-half))
         (second-half-hash (create-hash-from-list second-half-to-n)))
    (none (lambda (a)
            (let ((b (- n a)))
              (gethash b second-half-hash)))
          first-half)))

(defun not-abundant-sums-list (limit)
  (let ((abundant-list (abundant-numbers limit)))
    (filter #'(lambda (n)
                (is-not-abundant-sum n abundant-list))
            (gen-list 1 limit))))

CL-USER> (time (sum (not-abundant-sums-list 28123)))
 Evaluation took:
  2.481 seconds of real time
  2.477531 seconds of total run time (2.389778 user, 0.087753 system)
  [ Run times consist of 0.152 seconds GC time, and 2.326 seconds non-GC time. ]
  99.88% CPU
  6,194,100,940 processor cycles
  7,411,226,352 bytes consed
  
4179871

— Me@2024-10-04 03:38:12 PM

.

.

2024.10.05 Saturday (c) All rights reserved by ACHK

Euler problem 23.1.1

(defmacro sum (lst)
  `(reduce #'+ ,lst))

(defun proper-divisors (n)
  (when (> n 1)  
    (let ((divisors '())
          (limit (floor (sqrt n))))  
      (loop :for i :from 1 :to limit
            :when (zerop (mod n i))  
              :do (progn
                    (push i divisors)  
                    (when (/= n (floor n i))  
                      (push (floor n i)
                            divisors))))  
      (remove-duplicates (sort divisors #'<)
                         :test
                         #'equal))))

(defmacro sum-proper-divisors (n)
  `(sum (proper-divisors ,n)))

(defmacro is-abundant (n)  
  `(> (sum-proper-divisors ,n) ,n))

(defmacro gen-list (min max)
  `(loop :for n :from ,min :to ,max
         :collect n))

(defmacro filter (predicate list)
  `(remove-if-not ,predicate ,list))

(defmacro macro-to-function (macro-name)
  `(lambda (xs) (,macro-name xs)))

(defmacro db (x)
  `(* 2 ,x))

((lambda (xs) (db xs)) 2.1)

(funcall (macro-to-function db) 2.1)

;; Evaluation Context:

;; ((macro-to-function db) 2.1): This line attempts to call the result of the macro macro-to-function directly as if it were a function. However, since macro-to-function returns a lambda expression, this results in an "illegal function call" error because the macro is not expanded in the context of a function call.

;; (funcall (macro-to-function db) 2.1): In this line, funcall is used to invoke the lambda function returned by macro-to-function. This correctly evaluates the lambda and applies it to 2.1, allowing the macro to be expanded properly.

(defmacro abundant-numbers (limit)
  `(filter (macro-to-function is-abundant) (gen-list 1 ,limit)))

— Me@2024-09-20 11:53:30 PM

.

.

2024.09.21 Saturday (c) All rights reserved by ACHK

Euler problem 22.1

(ql:quickload "str")

(defun score (word)
  (loop :for char :across word
        sum (+ (- (char-code (char-upcase char))
                  (char-code #\A))
               1)))

(defun remove-quote (name)
  (remove #\" name))

(defmacro zipWith (f xs ys)
  `(mapcar ,f ,xs ,ys))

(defmacro range (max &key (min 0) (step 1))
  `(loop :for n :from ,min :below ,max :by ,step
        collect n))

(defun name-scores (filename)
  (with-open-file (stream filename)
    (let* ((names (read-line stream))
           (name-list-q (str:split #\, names))
           (name-list (mapcar #'remove-quote name-list-q))
           (sorted-name-list (sort name-list #'string<))
           (score-list (mapcar #'score sorted-name-list))
           (n-list (range (1+ (length score-list)) :min 1))
           (i-score-list (zipWith #'* n-list score-list)))
      (reduce #'+ i-score-list))))

(name-scores "names.txt")

; SLIME 2.28To load "str":
  Load 1 ASDF system:
    str
; Loading "str"
...

CL-USER> (name-scores "names.txt")
871198282
CL-USER> 

— Me@2024-09-04 10:43:19 AM

.

.

2024.09.04 Wednesday (c) All rights reserved by ACHK