diff --git a/Flax/asset.scm b/Flax/asset.scm index 4abf1ee..f0f0624 100644 --- a/Flax/asset.scm +++ b/Flax/asset.scm @@ -1,5 +1,3 @@ -;; This is used to cp all resource to destination - (define-module (Flax asset) #:use-module (srfi srfi-1) #:use-module (srfi srfi-9) ;;record type @@ -39,9 +37,9 @@ (let ((src-file-name (string-append src-path "/" src-tree)) (dest-file-path (string-append prefix "/" src-tree))) (if (is-directory? src-file-name) - (mkdir dest-file-path) + (mkdir-p dest-file-path) (copy-file src-file-name dest-file-path))) - (begin (mkdir (string-append prefix "/" (car src-tree))) + (begin (mkdir-p (string-append prefix "/" (car src-tree))) (map file-tree-move (cdr src-tree) (repeat-element-of-list (length (cdr src-tree)) (string-append src-path "/" (car src-tree))) @@ -49,7 +47,7 @@ (string-append prefix "/" (car src-tree))))))) ;; (define (cp-file-tree src prefix) - (mkdir (get-absolute-path prefix)) + (mkdir-p (get-absolute-path prefix)) (file-tree-move (get-file-tree-list src) (dirname (get-absolute-path src)) (get-absolute-path prefix))) diff --git a/Flax/command/build.scm b/Flax/command/build.scm index 975a640..d58cff3 100644 --- a/Flax/command/build.scm +++ b/Flax/command/build.scm @@ -1,4 +1,3 @@ -;; TODO : unfinished file (define-module (Flax command build) #:use-module (Flax site) #:use-module (Flax utils) @@ -6,22 +5,20 @@ #:use-module (ice-9 r5rs) #:use-module (ice-9 match) - #:export (show-help + #:export (show-build-help build)) -;; not complete -(define (show-help) - (format #t "Useage:~%") - (format #t "1.~%")) +;; display the build command usage +(define (show-build-help) + (format #t "Useage: flax build ~%") + (format #t "If the is not provided, use \"config.scm\" instead. ~%")) -;; +;; the build command which is invoked by the ui (define* (build #:key (config-file "config.scm")) (if (file-exists? (get-absolute-path config-file)) (let ((obj (config-load config-file))) (if (is-site? obj) - (begin - (build-site obj) - (format #t "~%!!Done!!~%")) + (build-site obj) (format (current-error-port) "Didn't receive site object !~%Last config expression must be site ~%"))) (begin (format #t "Coundn't find config file !! ~%expect ~a but got nothing !~%" (basename config-file))))) diff --git a/Flax/page.scm b/Flax/page.scm index 36dc030..1a39bf7 100644 --- a/Flax/page.scm +++ b/Flax/page.scm @@ -1,10 +1,9 @@ -;; the page data type - (define-module (Flax page) #:use-module (Flax post) #:use-module (Flax html) #:use-module (Flax process) + #:use-module (ice-9 regex) #:use-module (ice-9 match) #:use-module (srfi srfi-9) #:use-module (srfi srfi-26) @@ -18,10 +17,14 @@ write-page create-writer page)) -;; + ;; define the record ;; ~file-name~ is a string -;; ~contents~ is a html code +;; ~contents~ is the page content +;; ~writer~ is the procedure to write the +;; content to disk and the procedure may do +;; some extra job like converting the content +;; to some formats (define-record-type (make-page file-name contents writer) is-page? @@ -49,11 +52,12 @@ (define* (page post prefix-directory #:optional (process-layer default-process-layer) #:key (writer (create-writer))) - (let ((file-name (get-post-file-name post))) + (let ((file-name (regexp-substitute #f (string-match ".[a-zA-Z]+$" (get-post-file-name post)) ;; use regexp to change the ext to "html" + 'pre ".html"))) (let ((page* (make-page file-name ((get-processor (assq-ref process-layer 'meta)) #:process-layer process-layer - ;; the process-object is an post-object + ;; the process-object is a post-object #:process-object post) writer))) (write-page page* prefix-directory)))) diff --git a/Flax/post.scm b/Flax/post.scm index 6b43e65..a70c727 100644 --- a/Flax/post.scm +++ b/Flax/post.scm @@ -18,7 +18,10 @@ set-post-sxml read-post - post-ref)) + post-ref + register-metadata-parser! + read-metadata-headers + parse-metadata)) ;; ~metadata~ is an alist @@ -30,10 +33,54 @@ (metadata get-post-metadata) (sxml get-post-sxml set-post-sxml)) -;; read one post and return post object -(define (read-post file-name) - (let-values (((meta-data content) ((get-reader-proc sxml-reader) file-name))) - (make-post (basename file-name) meta-data content))) +;; read one post and return post object +(define* (read-post file-name #:key (reader-list default-reader-list)) + (if (pair? reader-list) + (if (is-reader-available? (car reader-list) file-name) + (let-values (((meta-data content) (proc-of-reader (car reader-list) file-name))) + (make-post (basename file-name) meta-data content)) + (read-post file-name #:reader-list (cdr reader-list))) + (begin + (format (current-error-port) "Unmatched file : ~a ~%" file-name) + '()))) (define (post-ref post key) (assq-ref (get-post-metadata post) key)) + + +;; read meta data +(define %metadata-parsers + (make-hash-table)) + +(define (register-metadata-parser! name parser) + (hash-set! %metadata-parsers name parser)) + +(define (metadata-parser key) + (or (hash-ref %metadata-parsers key) identity)) + +(define (parse-metadata key value) + ((metadata-parser key) value)) + +(define (read-metadata-headers port) + (let loop ((metadata '())) + (let ((line (read-line port))) + (cond + ((eof-object? line) + (error "end of file while readig metadata: " (port-filename port))) + ((string=? line "---") + metadata) + (else + (match (map string-trim-both (string-split-at line #\:)) + (((= string->symbol key) value) + (loop (alist-cons key (parse-metadata key value) metadata))) + (_ error "invalid metadata format: " line))))))) + +(register-metadata-parser! + 'type + (lambda (str) + (string->symbol str))) + +(register-metadata-parser! + 'depth + (lambda (str) + (string->number str))) diff --git a/Flax/process.scm b/Flax/process.scm index fb85fb5..80ed2f5 100644 --- a/Flax/process.scm +++ b/Flax/process.scm @@ -9,14 +9,41 @@ get-processor set-processor - default-process-layer)) + default-process-layer + process-ref + processor-ref)) + +;; defien the record of (define-record-type (make-process key processor) is-process? (key get-process-key set-process-key) ;; you'd better set the key as symbol (processor get-processor set-processor)) ;; the processor is a procedure which process the sxml tree + +;; return the process from the process-layer otherwise +;; return '() +(define (process-ref process-layer key) + (assq-ref process-layer key)) + +;; return the processor of one process in process-layer +(define (processor-ref process-layer key) + (get-processor (process-ref process-layer key))) + + +;; read each post, genereate an alist of post path , not completed!!!!!!!!!!!!!! +(define (Hello) + (format #t "This is not done!!~%")) + +;; ---------------------------the default process layer------------------------------------------------ +;; this template require these keywords in post +;; img -- the preview image path, from the index file to that image, pure String +;; title -- the title of the post, pure String +;; author -- Your name, pure String +;; date -- the date the post posted, Pure String +;; tag -- The type of the post, Pure String +;; this will show later in the end of the file (define default-meta-process (make-process 'meta (lambda* (#:key process-layer process-object) @@ -64,7 +91,7 @@ ;; date if none output "today" -- date is a string ;; img if none don't display the image -- img is a src string ;; tag if none output "none" -- tag is a !!string list!! -;; content -- must have! otherwise you will get one post with out content +;; content -- must have! otherwise you will get one post without content (define default-process-layer `((meta . ,default-meta-process) (index . ,default-index-process) diff --git a/Flax/process/utils.scm b/Flax/process/utils.scm new file mode 100644 index 0000000..bd9254d --- /dev/null +++ b/Flax/process/utils.scm @@ -0,0 +1,36 @@ +(define-module (Flax process utils) + #:use-module (Flax post) + #:use-module (Flax utils) + + #:use-module (ice-9 regex) + #:use-module (ice-9 match) + + #:export (navigate)) + + +;; navigate between files, read the post, use action to process each +;; post, and then return a list, this action is defined by user and the +;; action is a function which accept a post . you can do what you want. +;; Don't use the flag keyword in any situation! +;; You can set the environment keyword if you need to. +(define* (navigate file-tree action #:key (flag #f) (environment (getcwd))) + (if (not (pair? file-tree)) + '() + (let ((environment* (if flag + (string-append environment "/" (car file-tree)) + environment)) + (file-tree* (if flag + (cdr file-tree) + file-tree))) + (append (if (pair? (car file-tree*)) + (navigate (car file-tree*) + action + #:flag #t + #:environment environment*) + (action (if (not (is-directory? (string-append environment* "/" (car file-tree*)))) + (read-post (string-append environment* "/" (car file-tree*))) + '()))) + (navigate (cdr file-tree*) + action + #:flag #f + #:environment environment*))))) diff --git a/Flax/reader.scm b/Flax/reader.scm index 2928655..90ad1c1 100644 --- a/Flax/reader.scm +++ b/Flax/reader.scm @@ -1,6 +1,6 @@ - (define-module (Flax reader) #:use-module (Flax utils) + #:use-module (Flax post) #:use-module (srfi srfi-1) ;;alist-delete procedure #:use-module (srfi srfi-9) @@ -10,6 +10,8 @@ #:use-module (ice-9 match) #:use-module (ice-9 regex) #:use-module (sxml simple) + + #:use-module (commonmark) #:export (make-reader is-reader? @@ -17,9 +19,12 @@ set-reader-matcher-as get-reader-proc is-reader-available? - + proc-of-reader + + sxml-reader + commonmark-reader make-file-extension-matcher - sxml-reader)) + default-reader-list)) ;; ~matcher~ is a function to judge whether the file is supported @@ -31,6 +36,7 @@ (matcher get-reader-matcher set-reader-matcher-as) (proc get-reader-proc)) +;; make file extension matcher ;; return the function which returns #t if the file is ;; end with ".~ext~" (define (make-file-extension-matcher ext) @@ -40,13 +46,19 @@ (regexp-match? (regexp-exec regexp file-name))))) + ;; return #t if the ~file-name~ is supported by ~reader~ (define (is-reader-available? reader file-name) ((get-reader-matcher reader) file-name)) +;; use reader's process to do things +(define (proc-of-reader reader file-name) + ((get-reader-proc reader) file-name)) + ;;;;;;;;;;; ;;;;;;;;;;; ;;;; define simple reader ;;; ;;;;;;;;;;; ;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; sxml-reader ;; take the file as the scheme code and then read it (define sxml-reader @@ -55,3 +67,13 @@ (let ((contents (load (get-absolute-path file-name)))) (values (alist-delete 'content contents eq?) ;; return the metadata list (assq-ref contents 'content)))))) ;; return the list + +(define commonmark-reader + (make-reader (make-file-extension-matcher "md") + (lambda (file-name) + (call-with-input-file file-name + (lambda (port) + (values (read-metadata-headers port) + (commonmark->sxml port))))))) + +(define default-reader-list (list sxml-reader commonmark-reader)) diff --git a/Flax/script/flax.scm b/Flax/script/flax.scm index df32a3b..d45e437 100755 --- a/Flax/script/flax.scm +++ b/Flax/script/flax.scm @@ -1,15 +1,10 @@ -#!/usr/bin/guile +#!/usr/bin/guile --no-auto-compile -*- scheme -*- !# ;; command option ;; --no-auto-compile - -;; NOTE: for test -(add-to-load-path - "/home/eilliot/Lasga/Repository/Local_Repository/Guile/Dev") - ;;Add modules here (use-modules (Flax ui)) diff --git a/Flax/site.scm b/Flax/site.scm index 13da726..5a0a4a0 100644 --- a/Flax/site.scm +++ b/Flax/site.scm @@ -1,23 +1,23 @@ (define-module (Flax site) - #:use-module (Flax reader) - #:use-module (Flax page) - #:use-module (Flax post) - #:use-module (Flax asset) - #:use-module (Flax process) - #:use-module (Flax utils) - - #:use-module (srfi srfi-9) - - #:export (make-site - is-site? - get-site-postdirectory - get-site-build-directory - get-site-readers - get-site-process-layer - set-site-process-layer - - build-site - site)) + #:use-module (Flax reader) + #:use-module (Flax page) + #:use-module (Flax post) + #:use-module (Flax asset) + #:use-module (Flax process) + #:use-module (Flax utils) + + #:use-module (srfi srfi-9) + + #:export (make-site + is-site? + get-site-postdirectory + get-site-build-directory + get-site-readers + get-site-process-layer + set-site-process-layer + + build-site + site)) ;; ~title~ is a string ;; ~domain~ is a string @@ -34,7 +34,7 @@ (posts-directory get-site-postdirectory) ;; the object directory where the builded page is sended to (build-directory get-site-build-directory) - ;; transfer the post file to the proper sxmltree which is needed by page + ;; transfer the post file to the post (readers get-site-readers)) @@ -45,7 +45,7 @@ (asset (make-asset "assets" "BlogSite")) ;; the process field contains an assoc list (process-layer default-process-layer) - (readers '(sxml-reader html-reader))) + (readers default-reader-list)) (make-site asset process-layer posts-directory @@ -53,43 +53,49 @@ readers)) ;; write the content to the disk -(define* (write-content posts-directory prefix-directory #:optional process-layer) - (let* ((file-tree-list (get-file-tree-list posts-directory))) - (if (pair? file-tree-list) - (begin - (set! file-tree-list (cdr file-tree-list)) - (while (not (eq? '() file-tree-list)) - (if (list? (car file-tree-list)) - ;; the element is directory which contains at least one file , the file may be a directory too! - (let ((prefix-directory* (string-append prefix-directory "/" (caar file-tree-list))) - (posts-directory* (string-append posts-directory "/" (caar file-tree-list)))) - (mkdir-p prefix-directory) - (write-content posts-directory* - prefix-directory* - process-layer)) - ;; the element is a file - (if (is-directory? (string-append posts-directory "/" (car file-tree-list))) - ;; no matter whether the directory contains file, create it - (mkdir-p (string-append prefix-directory "/" (car file-tree-list))) - (begin - (if (not (file-exists? prefix-directory)) - (mkdir-p prefix-directory)) - (page (read-post (string-append posts-directory "/" (car file-tree-list))) - prefix-directory - process-layer)))) - ;; update the list, and process the rest list elements - (set! file-tree-list (cdr file-tree-list)))) - (if (is-directory? file-tree-list) - ;; no matter whether the directory contains file, create it - (mkdir-p (string-append prefix-directory "/" file-tree-list)) - (begin - (if (file-exists? prefix-directory) - (if (not (is-directory? prefix-directory)) - (format (current-error-port) "When building pages. find there exists conflict files!! ~%Whose name is \"~a\".~%~%" prefix-directory)) - (mkdir-p prefix-directory)) - (page (read-post file-tree-list) - prefix-directory - process-layer)))))) +(define* (write-content posts-file-tree prefix-directory + #:key (flag #f) (environment (getcwd)) (reader-list default-reader-list) (process-layer default-process-layer)) + (if (string? posts-file-tree) + ;; initilaize the file tree, if flag is #t, onle executed once in this procedure!! + (if flag + (let* ((file-tree (get-file-tree-list posts-file-tree)) + (environment* (string-append environment "/" (car file-tree)))) + (write-content (cdr file-tree) prefix-directory + #:environment environment* + #:reader-list reader-list + #:process-layer process-layer)) + ;;if flag is #f, it is a single element from the file tree list + (if (is-directory? (string-append environment "/" posts-file-tree)) + ;; if the file is a directory, create it + (mkdir-p (string-append prefix-directory "/" posts-file-tree)) + ;; if not, write the page + (let ((post (read-post (string-append environment "/" posts-file-tree) + #:reader-list reader-list))) + (if (not (eq? post '())) + (page post prefix-directory process-layer) + (format (current-error-port) "Warning! Unrecognized file: ~a ~%" posts-file-tree))))) + ;; if it is a file list + (if (pair? posts-file-tree) + (let ((prefix-directory* (if flag + (string-append prefix-directory "/" (car posts-file-tree)) + prefix-directory)) + (environment* (if flag + (string-append environment "/" (car posts-file-tree)) + environment)) + (file-tree (if flag + (cdr posts-file-tree) + posts-file-tree))) + (write-content (car file-tree) prefix-directory* + #:flag (if (pair? (car file-tree)) + #t + #f) + #:environment environment* + #:reader-list reader-list + #:process-layer process-layer) + (write-content (cdr file-tree) prefix-directory* + #:environment environment* + #:reader-list reader-list + #:process-layer process-layer))))) ;; This procedure will not be deleted!! Just develop it! ;; get the site object and build the site @@ -97,21 +103,29 @@ (let ((posts-directory (get-site-postdirectory obj)) (build-directory (get-site-build-directory obj)) (assets-obj (get-site-asset obj)) - (process-layer (get-site-process-layer obj))) + (process-layer (get-site-process-layer obj)) + (reader-list (get-site-readers obj))) ;; cp the asset src file (if (pair? assets-obj) (while (not (eq? '() assets-obj)) - (if (file-exists? (get-asset-target (car assets-obj))) - (format (current-error-port) "Warning!! There already exists one \"~a\"!~%" (get-asset-target (car assets-obj))) - (begin - (cp-asset (car assets-obj)) - (format #t "Install source file successfully!~%"))) - (set! assets-obj (cdr assets-obj))) - (if (file-exists? (get-asset-target assets-obj)) - (format (current-error-port) "Warning!! There already exists one \"~a\"!~%" (get-asset-target assets-obj)) + (begin + (if (file-exists? (get-asset-target (car assets-obj))) + (begin + (format (current-error-port) "Warning!! There already exists one \"~a\"!~%" (get-asset-target (car assets-obj))) + (format (current-error-port) "This is a warning, If you know what happened, just ignored.~%"))) + (cp-asset (car assets-obj))) + (set! assets-obj (cdr assets-obj)) + (format #t "Install source file successfully!~%")) + (begin + (if (file-exists? (get-asset-target assets-obj)) (begin - (cp-asset assets-obj) - (format #t "Install source file successfully!~%")))) + (format (current-error-port) "Warning!! There already exists one \"~a\"!~%" (get-asset-target assets-obj)) + (format (current-error-port) "This is a warning, If you know what happened, just ignored~%"))) + (cp-asset assets-obj) + (format #t "Install source file successfully!~%"))) ;; read the post and build the page and write them to the disk - (write-content posts-directory build-directory process-layer)) + (write-content posts-directory build-directory + #:flag #t + #:reader-list reader-list + #:process-layer process-layer)) (format #t "Building successful!!~%")) diff --git a/Flax/ui.scm b/Flax/ui.scm index 6ef31eb..6012a29 100644 --- a/Flax/ui.scm +++ b/Flax/ui.scm @@ -1,4 +1,3 @@ -;; NOTE : unfinished file (define-module (Flax ui) #:use-module (Flax utils) #:use-module (Flax command build) @@ -10,23 +9,42 @@ #:export (flax)) -;; varibles -(define %commands '("build" "serve")) +;; command list +(define %commands% '("build" "serve")) +;; there are three numbers in the version string +;; -- the first is the main version number, when it updates, this means +;; Flax can be packaged and can run independently. Flax now is not +;; compatibal with previous main version. +;; -- the second number is the minor version number, when it updates, +;; Flax is stable with all branch version. Flax can be patched +;; and distributed. +;; Flax is compatibal with previous second version. +;; -- the third number is the branch version number. Every bug fix or feature +;; added or some procedure updated will update the number. +(define (show-version) + (format #t "Flax version 0.0.4 ~%")) -;; TODO : continue to update +(define --version-history-- + '("Flax 0.0.1 --- complete the basic functions, split the process procedure out ~%" + "Flax 0.0.2 --- refine the site procedure, refine the page procedure adding file extension support ~%" + "Flax 0.0.3 --- refine the write-content procedure, let the logic be better understood!! ~%" + "Flax 0.0.4 --- add markdown support and fix some bugs! ~%")) + +;; the basic information (define (show-flax) - (format #t "This is another static site generator~%") + (format #t "This is just another static site generator~%") (format #t "Please add \"-h\" or \"--help\" to get further help~%") (format #t "For more information please follow github io page~%")) +;; basic help information (define (show-flax-help) (format #t "Basic usage : ~%") (format #t "flax [ command ] [ options ] [ arguments ] ~%~%") (format #t "command list as follows :: ~%") - (format #t " build~%")) - - + (format #t " build~%") + (format #t "basic information argument:~%") + (format #t "[ -v || --version ] version number~%")) ;; The main function @@ -36,8 +54,12 @@ (() (show-flax)) ((or ("-h") ("--help")) (show-flax-help)) + ((or ("-v") ("--version")) + (show-version)) (("build") (build)) + (("build" (or "-h" "--help")) + (show-build-help)) (("build" args ...) (build #:config-file (car args))) (("serve") diff --git a/Flax/utils.scm b/Flax/utils.scm index 96f7812..db18a83 100644 --- a/Flax/utils.scm +++ b/Flax/utils.scm @@ -3,6 +3,7 @@ #:use-module (ice-9 ftw) #:use-module (ice-9 match) + #:use-module (ice-9 regex) #:use-module (srfi srfi-1) #:use-module (srfi srfi-13) #:use-module (srfi srfi-19) @@ -13,11 +14,12 @@ compose-file-name mkdir-p delete-file-recursively - make-user-module remove-stat is-directory? get-file-tree-list - config-load)) + make-user-module + config-load + string-split-at)) ;; return the absolute path of the file ;; TODO : need to do better @@ -98,37 +100,17 @@ (define (get-file-tree-list file-name) (remove-stat (file-system-tree file-name))) -;; delete file -(define* (delete-file-recursively dir #:key follow-mounts?) - "Delete DIR recursively, like `rm -rf', without following symlinks. Don't -follow mount points either, unless FOLLOW-MOUNTS? is true. Report but ignore -errors." - (let ((dev (stat:dev (lstat dir)))) - (file-system-fold (lambda (dir stat result) ; enter? - (or follow-mounts? - (= dev (stat:dev stat)))) - (lambda (file stat result) ; leaf - (delete-file file)) - (const #t) ; down - (lambda (dir stat result) ; up - (rmdir dir)) - (const #t) ; skip - (lambda (file stat errno result) - (format (current-error-port) - "warning: failed to delete ~a: ~a~%" - file (strerror errno))) - #t - dir - - ;; Don't follow symlinks. - lstat))) - -;; return a new user module with the additional modules -;; loaded -(define make-user-module - (lambda (modules) - (let ((module (make-fresh-user-module))) +;; return a new user module with the additional modules loaded +(define (make-user-module modules) + (let ((module (make-fresh-user-module))) (for-each (lambda (iface) (module-use! module (resolve-interface iface))) modules) - module))) + module)) + +(define (string-split-at str char-pred) + (let ((i (string-index str char-pred))) + (if i + (list (string-take str i) + (string-drop str (1+ i))) + (list str)))) diff --git a/README.md b/README.md index 3c05d62..e5cfe83 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,41 @@ -## this is a static site generator +## this is a static site generator ## - it's supported by Gnu Guile -- view [github.io](https://github.io) -## Features --[ ] Internal server --[ ] personalities +- developed from Gnu haunt([view haunt here](https://dthompson.us/projects/haunt.html)) +- simple to use, just need some config and some styles and meta posts written in markdown. +- you can write the post in sxml which will give you more control on the output file. -## +## Is there a demo page to view before i download it? +Yes, it is. You can View my Blog [Here](https://memorytoco.github.io/Lasga/). +It is purely genereted by **flax** along with some css style and maybe some js. + +## How to use it ? +1. Just clone the repository to your machine. +2. put the *Flax* directory to your local guile library directory or just add the path to load path list. +3. cp the guile script which is named **flax.scm** in **/usr/bin** and change the execution permission. +4. edit the flax.scm in the **/usr/bin**, make the line +``` +#!/usr/bin/guile --no-auto-compile +``` +to +``` +#!path/to/guile --no-auto-compile +``` +(you can get more information about the script execution mode in guile manual ([and the link is here](https://www.gnu.org/software/guile/manual/))) +5. Just test and type flax !! + + +## Where will it go? +> i will continue to complete it and make it stable enough to use. +> After all, i may not add it any other new features. +> i will focus on my another site generator written in c. +> which will be a completed system comming along with the latest commonmark engine(i do it), +> having server and one completed plugin system which lets anyone to write +> plugins in c for this new generator. It will use purely system call and standard library without +> any third party library. + +## There seems no document, where can i get help? +Well, i have added some comments in the source code, you can view it. + +I will explain the working flow and show the api i provided later. + +feel free to contact me @ **Memorytoco@gmail.com** ,i will get you around .