Skip to content

New Feature: Thermodynamics package - #1563

Open
hammondkd wants to merge 7 commits into
mathjax:developfrom
hammondkd:thermodynamics
Open

New Feature: Thermodynamics package#1563
hammondkd wants to merge 7 commits into
mathjax:developfrom
hammondkd:thermodynamics

Conversation

@hammondkd

@hammondkd hammondkd commented Sep 8, 2026

Copy link
Copy Markdown

This PR contains code to implement the vast majority of the commands in the LaTeX package thermodynamics (written by the same author).

This version does not implement all of the options the LaTeX package does, but most of the non-textbook-specific options are supported.

If this PR is incorporated into MathJax, I will add a section to the documentation on CTAN that denotes the limitations the MathJax version has that are different from the LaTeX package.

There are a lot of commands and environments in this package, and I was not certain how the MathJax developers do unit tests/etc., so with that in mind, I include an example HTML file that I used to test the functionality at the bottom of this message.

Some things to note:
(1) Before I started this project, I had not written anything in JavaScript since about 1998, and I had never heard of TypeScript before, so if you see something and think, "Why did he do it that way?" by all means, change it to something that makes more sense!
(2) I may have done some things in here that do not make a lot of sense (see point #1), and there are probably a few ways to break it that I haven't found yet.
(3) I was able to get this working and tested it off of the master branch, but the develop branch code currently posted does not seem to create a valid package that I can import in my browser. There should be no changes to any files except the five associated with the package, however.
(4) Some of the package options are currently commented out; these may (or may not?) be implemented later, but they won't work now.

Example file to test this package:

<!DOCTYPE html>
<html>
<head>
<script>
  window.MathJax = {
    loader: {load: ['[tex]/textcomp',
                    '[tex]/thermodynamics',
                    '[tex]/mhchem',
                    '[tex]/setoptions',
                   ]},
    tex: {
      packages: {'[+]': ['thermodynamics','textcomp','mhchem','setoptions']},
    }
  };
</script>
<script defer src="http://localhost/mathjax/tex-chtml.js"></script>
<title>Thermodynamics test page</title>
</head>
<body>
Eq.&nbsp;(1) of documentation:
\begin{equation}
  d\Ut = \Partial*{\Ut}{\St}{\Vt,\allNs} d\St
    + \Partial*{\Ut}{\Vt}{\St,\allNs} d\Vt
    + \sumall_i \Partial*{\Ut}{\Nt_i}{\St,\Vt,\allNsbut{i}} d\Nt_i
\end{equation}
&hellip;, if you wanted it to be
\begin{equation*}
  \begin{thermoextensiveplain}
  \begin{thermomolesrange}
  \renewcommand{\Nt}{N}
  \renewcommand{\ncomponents}{\mathcal{C}}
  d\Ut = \Partial*{\Ut}{\St}{\Vt,\allNs} d\St
    + \Partial*{\Ut}{\Vt}{\St,\allNs} d\Vt
    + \sumall_i \Partial*{\Ut}{\Nt_i}{\St,\Vt,\allNsbut{i}} d\Nt_i
  \end{thermomolesrange}
  \end{thermoextensiveplain}
  \renewcommand{\Nt}{n}
  \renewcommand{\ncomponents}{C}
\end{equation*}

renders (using the default options)
\[ \Partial*{\Hm}{T}{P} = T\Partial*{\Sm}{T}{P}
                        = -T\PartialSecond*{\Gm}{T}{P} = \cP \]

Similarly, macros are defined for mixed second partial derivatives that allow
things like
\[ \Partial*{\Gpm_i}{P}{T,\allNs}
    = \PartialMixSecond*{\Gt}{P}{\Nt_i}{T,\allNsbut{i}}
    = \PartialMixSecond*{\Gt}{\Nt_i}{P}{T,\allNsbut{i}}
    = \Partial*{\Vt}{\Nt_i}{T,P,\allNsbut{i}} = \Vpm_i \],

Examples using the enthalpy are
\[ \Ht \quad \Hm \quad \Hs \quad \Hpm_i. \]

<p>The heat capacities (see Table 2) are generally assumed to be molar (e.g.,
<pre>\cP</pre> is interpreted to be the molar heat capacity). To get the
specific heat capacities, they render as \(\cPs\) and \(\cVs\), respectively.
There are also extensive versions, so cPt and cVt will render as \(\cPt\)
and \(\cVt\), respectively. Note you need to use \(\cP_i^{\text{A}}\) and
\(\cP^{\text{A}}_i\). Using \(\cP_i^\IG\) and \(\cP^\IG_i\) will work as
expected. Will \(\cPpm_i^\IG\) and \(\cPpm^\IG_i\)?
What about \(\cPt_i^\IG\) and \(\cPt^\IG_i\)
       and \(\cPs_i^\IG\) and \(\cPs^\IG_i\)?
</p>

<p>You can also get partial molar heat capacities via \(\cPpm_i\) and
\(\cVpm_i\), though the
latter's mathematical definition is a bit hard to wrap one's head around:
\[ \cVpm_i = \Partial*{\cVt}{\Nt_i}{T,P,\allNsbut{i}}
           = \frac{\partial}{\partial\Nt_i}
                \left[ -T\PartialSecond{\Ft}{T}{\Vt,\allNs}
                \right]_{T,P,\allNsbut{i}} \]
\[ \Upm{i} \quad \Upm[\IG]{i} \quad \Vpm_i \quad \Vpm^\IG_i \]

<table>
  <tr>
    <th>Heat</th>
    <td>\(\Qt\)</td>
    <td>\(\Qm\)</td>
    <td>\(\Qs\)</td>
  </tr>
  <tr>
    <th>Work</th>
    <td>\(\Wt\)</td>
    <td>\(\Wm\)</td>
    <td>\(\Ws\)</td>
  </tr>
  <tr>
    <th>Total energy</th>
    <td>\(\Et\)</td>
    <td>\(\Em\)</td>
    <td>\(\Es\)</td>
    <td>\(\Epm_i\)</td>
    <td>\(\EEt\)</td>
    <td>\(\EE\)</td>
    <td>\(\EEs\)</td>
    <td>\(\EEpm_i\)</td><!-- FIXME giving a PM w/o a subscript is an error / why is this over-doing the recursion? -->
    <td>\(\ERt\)</td>
    <td>\(\ER\)</td>
    <td>\(\ERs\)</td>
    <td>\(\ERpm_i\)</td>
  </tr>
  <tr>
    <th>Internal energy</th>
    <td>\(\Ut\)</td>
    <td>\(\Um\)</td>
    <td>\(\Us\)</td>
    <td>\(\Upm_i\)</td>
    <td>\(\UEt\)</td>
    <td>\(\UE\)</td>
    <td>\(\UEs\)</td>
    <td>\(\UEpm_i\)</td>
    <td>\(\URt\)</td>
    <td>\(\UR\)</td>
    <td>\(\URs\)</td>
    <td>\(\URpm_i\)</td>
  </tr>
  <tr>
    <th>Enthalpy</th>
    <td>\(\Ht\)</td>
    <td>\(\Hm\)</td>
    <td>\(\Hs\)</td>
    <td>\(\Hpm_i\)</td>
    <td>\(\HEt\)</td>
    <td>\(\HE\)</td>
    <td>\(\HEs\)</td>
    <td>\(\HEpm_i\)</td>
    <td>\(\HRt\)</td>
    <td>\(\HR\)</td>
    <td>\(\HRs\)</td>
    <td>\(\HRpm_i\)</td>
  </tr>
  <tr>
    <th>Entropy</th>
    <td>\(\St\)</td>
    <td>\(\Sm\)</td>
    <td>\(\Ss\)</td>
    <td>\(\Spm_i\)</td>
    <td>\(\SEt\)</td>
    <td>\(\SE\)</td>
    <td>\(\SEs\)</td>
    <td>\(\SEpm_i\)</td>
    <td>\(\SRt\)</td>
    <td>\(\SR\)</td>
    <td>\(\SRs\)</td>
    <td>\(\SRpm_i\)</td>
  </tr>
  <tr>
    <th>Volume</th>
    <td>\(\Vt\)</td>
    <td>\(\Vm\)</td>
    <td>\(\Vs\)</td>
    <td>\(\Vpm_i\)</td>
    <td>\(\VEt\)</td>
    <td>\(\VE\)</td>
    <td>\(\VEs\)</td>
    <td>\(\VEpm_i\)</td>
    <td>\(\VRt\)</td>
    <td>\(\VR\)</td>
    <td>\(\VRs\)</td>
    <td>\(\VRpm_i\)</td>
  </tr>
  <tr>
    <th>Helmholtz free energy</th>
    <td>\(\Ft\)</td>
    <td>\(\Fm\)</td>
    <td>\(\Fs\)</td>
    <td>\(\Fpm_i\)</td>
    <td>\(\FEt\)</td>
    <td>\(\FE\)</td>
    <td>\(\FEs\)</td>
    <td>\(\FEpm_i\)</td>
    <td>\(\FRt\)</td>
    <td>\(\FR\)</td>
    <td>\(\FRs\)</td>
    <td>\(\FRpm_i\)</td>
  </tr>
  <tr>
    <th>Gibbs free energy</th>
    <td>\(\Gt\)</td>
    <td>\(\Gm\)</td>
    <td>\(\Gs\)</td>
    <td>\(\Gpm_i\)</td>
    <td>\(\GEt\)</td>
    <td>\(\GE\)</td>
    <td>\(\GEs\)</td>
    <td>\(\GEpm_i\)</td>
    <td>\(\GRt\)</td>
    <td>\(\GR\)</td>
    <td>\(\GRs\)</td>
    <td>\(\GRpm_i\)</td>
  </tr>
  <tr>
    <th>Surface Area</th>
    <td>\(\At\)</td>
    <td>\(\Am\)</td>
    <td>\(\As\)</td>
    <td>\(\Apm_i\)</td>
  </tr>
  <tr>
    <th>Grand Potential</th>
    <td>\(\Lt\)</td>
    <td>\(\Lm\)</td>
    <td>\(\Ls\)</td>
    <td>\(\Lpm_i\)</td>
    <td>\(\LEt\)</td>
    <td>\(\LE\)</td>
    <td>\(\LEs\)</td>
    <td>\(\LEpm_i\)</td>
    <td>\(\LRt\)</td>
    <td>\(\LR\)</td>
    <td>\(\LRs\)</td>
    <td>\(\LRpm_i\)</td>
  </tr>
  <tr>
    <th>Moles</th>
    <td>\(\Nt\)</td>
  </tr>
</table>
\[ \NewExtensiveProperty{J}{K} \Jt, \Jm, \Js \]
\[ \NewPartialMolarProperty{J}{K} \Jpm_i \]
\[ \NewResidualProperty{J}{K} \JRt, \JR, \JRs, \JRpm_i \]
\[ \NewExcessProperty{J}{K} \JEt, \JE, \JEs, \JEpm_i \]
\[ \NewThermodynamicProperty{B}{B} \Bt, \Bm, \Bs, \Bpm_i,
    \BRt, \BR, \BRs, \BRpm_i
    \BEt, \BE, \BEs, \BEpm_i \]
\[ \cP, \cPt, \cPs, \cV, \cVt, \cVs, \cPpm_i, \cVpm_i,
    \kappaS, \kappaT, \alphaS, \alphaP, \muJT \]
\[ \mu, \muit, \fpure, \fmix, \fsat, \phipure, \phimix, \phisat, \]
\[ \actabs_i, \actrel_i, \Epot, \xrxn \]
<!-- \muup or \upmu? -->
\[ \gamma, \gammait, \gammarat, \gammamol, \Henryrat, \Henrymol \]
\[ \fmix_i = x_i \gamma_i \fpure_i = x_i \gammarat_i \Henryrat_i
    = C_i \gammamol_i \Henrymol_i \]
\[ \Psat, \Pvap, \fsat, \phisat, \sat \]
\[ \Pstd, \std, \Cstd, \fstd, \mustd \]
\[ \Deltamix\Gm = \Gm - \sumall_i x_i \Gm_i
    = \Deltamix\Hm - T\Deltamix\Sm \]
\[ \Deltasub\Hm = \Hm^V - \Hm^S = \Hm^V - \Hm^L + (\Hm^L - \Hm^S)
    = \Deltafus\Hm + \Deltavap\Hm \]
\[ \Deltarxn\Hm^\std = \sumall_i \nu_i \Deltaf\Hm_i^\std \]
\begin{gather*}
  \HE^\std = \Hm^{\excess,\std} = \HE(T,\Pstd)
    = \HR(T,\Pstd) - \HR^\IS(T,\Pstd) = \HR^\std - \HR^{\IS,\std} \\
  \renewcommand{\excess}{{EX}}
  \HE^\std = \Hm^{\excess,\std} = \HE(T,\Pstd)
    = \HR(T,\Pstd) - \HR^\IS(T,\Pstd)
\end{gather*},

\[ \Partial{\Hm}{T}{P} = \cP \qquad \Partial*{\Hm}{T}{P} = \cP \]

\[ \Partial*{\Hm}{T}{P} = \Partialinline{\Hm}{T}{P} = T\Partial{\Sm}{T}{P} \]

\[ \Vpm_i = \Partial*{\Vt}{\Nt_i}{T,P,\allNsbut{i}}
    = \PartialMixSecond*{\Gt}{\Nt_i}{P}{T,\allNsbut{i}}
    = \PartialMixSecond*{\Gt}{P}{\Nt_i}{T,\allNsbut{i}}
    = \Partial{\Gpm_i}{P}{T,\allNs} \]

\begin{equation}
  \Vpm_i = \Partialinline{\Vt}{\Nt_i}{T,P,\allNsbut{i}}
    = \PartialMixSecondinline{\Gt}{\Nt_i}{P}{T,\allNsbut{i}}
    = \PartialMixSecondinline{\Gt}{P}{\Nt_i}{T,\allNsbut{i}}
    = \Partialinline{\Gpm_i}{P}{T,\allNs}
\end{equation}

\[ \Vpm_i = \Partial*{\Vt}{\Nt_i}{T,P,\allNsbut{i}}
    = \Partial*{\Gpm_i}{P}{T,\allNs}
    = \PartialBigg*{\Gpm_i}{P}{T,\allNs}
    = RT\Partial*{\log\fmix_i}{P}{T,\allNs}
    = RT\PartialBigg*{\log\fmix_i}{P}{T,\allNs}
    = RT\Partialbigg{\log\fmix_i}{P}{T,\allNs} \],

\[ \Vpm_i = \Partial*{\Vt}{\Nt_i}{T,P,\allNsbut{i}}
    = \Partial{\smash{\Gpm_i}}{P}{T,\allNs} \]

\[ \Vpm_i = \Partialinlinetext{\Vt}{\Nt_i}{T,P,\allNsbut{i}}
    = \PartialMixSecondinlinetext{\Gt}{\Nt_i}{P}{T,\allNsbut{i}}
    = \PartialMixSecondinlinetext{\Gt}{P}{\Nt_i}{T,\allNsbut{i}}
    = \Partialinlinetext{\Gpm_i}{P}{T,\allNs} \]

\[ \cPpm_i = T\Partial*{\Spm_i}{T}{P,\allXs}
    = T\PartialMixSecond*{\St}{T}{\Nt_i}{P,\allNsbut{i}}
    = -T\Partial{^3\Gt}{T^2\partial\Nt_i}{P,\allNsbut{i}} \]

\[ \Partial{\Ht}{\Nt_1}{T,P,\allNsbut{1}} =
    \Partial{\Ht}{\Nt_1}{T,P,\allNsbut[m]{1}} = \Hpm_1 \]

\[ \Partial*{\Hm}{x_i}{T,P,\allXsbut{i}}
    = \Partial*{\Hm}{x_i}{T,P,\allXsbut[m]{i}}
    = \Hpm_i - \Hpm_\ncomponents \]

\[ \Jacobian{K,L}{X,Y} = \Jacobiandet{K,L}{X,Y} \]

\[ \Jacobian{K,L,M}{X,Y,Z} = \Jacobiandet[\displaystyle]{K,L,M}{X,Y,Z} \]

\[ \Jacobian{f_1,\dots,f_m}{x_1,\dots,x_m}
    = \Jacobiandet{f_1,\dots,f_m}{x_1,\dots,x_m}
\]

\[ \begin{thermomolesrange}
    \Jacobian{f_1,\dots,f_m}{x_1,\dots,x_m} =
    \Jacobiandet{f_1,\dots,f_m}{x_1,\dots,x_m}
   \end{thermomolesrange}
\]
\[ \Partial{\Ht}{T}{P,\allNs}
    \quad
   \Partial{\Ht}{\Nt_1}{T,P,\allNsbut{1}}
    \quad
  \begin{thermomolesrange}
    \Partial{\Ht}{\Nt_1}{T,P,\allNsbut{1}}
  \end{thermomolesrange}
\]

\[ \sumall_i x_i = 1 \quad \text{or} \quad
    x_\ncomponents = 1 - \sumallbutlast_i x_i \quad \text{or} \quad
    \Gt = \sumall_j \mu_j\Nt_j \quad \text{and} \quad
    K = \prodall_k a_k^{\nu_k} \]

\[ \Ft = \Ut - T\St = -P\Vt + \sumall_i \mu_i \Nt_i + \sigma \At
\qquad \Hm = \Um + P\Vm \qquad \Et = \Ut + \frac12 mv^2 \]

\begin{align*}
\begin{thermointensiveplain}
  \Hpm_i = \Partial*{\Ht}{\Nt_i}{T,P,\allNsbut{i}}
         = \Partial{\Nt\Hm}{\Nt_i}{T,P,\allNsbut{i}}
\end{thermointensiveplain}
  &\quad \text{intensive-plain} \\
\begin{thermoextensiveplain}
  \Hpm_i = \Partial*{\Ht}{\Nt_i}{T,P,\allNsbut{i}}
         = \Partial{\Nt\Hm}{\Nt_i}{T,P,\allNsbut{i}}
\end{thermoextensiveplain}
  &\quad \text{extensive-plain} \\
\begin{thermoextensivesuperscript}
  \Hpm_i = \Partial*{\Ht}{\Nt_i}{T,P,\allNsbut{i}}
    = \Partial{\Nt\Hm}{\Nt_i}{T,P,\allNsbut{i}}
\end{thermoextensivesuperscript}
  &\quad \text{extensive-superscript} \\
\begin{thermointensivelowercase}
  \Hpm_i = \Partial*{\Ht}{\Nt_i}{T,P,\allNsbut{i}}
          = \Partial{\Nt\Hm}{\Nt_i}{T,P,\allNsbut{i}}
\end{thermointensivelowercase}
  &\quad \text{intensive-lowercase}
\end{align*}

\[ \Spm_i = \Spm_i^\IGM + \SRpm_i
    \begin{thermoshortpm}
          = \Spm_i^\IGM + \SRpm_i
    \end{thermoshortpm} \]

\begin{gather*}
  \begin{thermoparentheses}
    \Partial*{\Vm}{T}{P} = \PartialMixSecond{\Gm}{T}{P}{}
        = \PartialMixSecond{\Gm}{P}{T}{}
        = -\Partial{\Sm}{P}{T}
  \end{thermoparentheses} \\
  \begin{thermobrackets}
    \Partial*{\Vm}{T}{P} = \PartialMixSecond{\Gm}{T}{P}{}
        = \PartialMixSecond{\Gm}{P}{T}{}
        = -\Partial{\Sm}{P}{T}
  \end{thermobrackets} \\
  \begin{thermobraces}
    \Partial*{\Vm}{T}{P} = \PartialMixSecond{\Gm}{T}{P}{}
        = \PartialMixSecond{\Gm}{P}{T}{}
        = -\Partial{\Sm}{P}{T}
  \end{thermobraces} \\
  \begin{thermobar}
    \Partial*{\Vm}{T}{P} = \PartialMixSecond{\Gm}{T}{P}{}
        = \PartialMixSecond{\Gm}{P}{T}{}
        = -\Partial{\Sm}{P}{T}
  \end{thermobar} \\
  \begin{thermoplain}
    \Partial*{\Vm}{T}{P} = \PartialMixSecond{\Gm}{T}{P}{}
        = \PartialMixSecond{\Gm}{P}{T}{}
        = -\Partial{\Sm}{P}{T}
  \end{thermoplain} \\
  \begin{thermosubscripts}
    \Partial*{\Vm}{T}{P} = \PartialMixSecond{\Gm}{T}{P}{}
        = \PartialMixSecond{\Gm}{P}{T}{}
        = -\Partial{\Sm}{P}{T}
  \end{thermosubscripts} \\
  \begin{thermoNOsubscripts}
    \Partial*{\Vm}{T}{P} = \PartialMixSecond{\Gm}{T}{P}{}
        = \PartialMixSecond{\Gm}{P}{T}{}
        = -\Partial{\Sm}{P}{T}
  \end{thermoNOsubscripts} \\
  \begin{thermoplain}
  \begin{thermoNOsubscripts}
    \Partial*{\Vm}{T}{P} = \PartialMixSecond{\Gm}{T}{P}{}
        = \PartialMixSecond{\Gm}{P}{T}{}
        = -\Partial{\Sm}{P}{T}
    \\
    \Partial*{\Vt}{T}{P,\allNs} = \PartialMixSecond{\Gt}{T}{P}{\allNs}
        = \PartialMixSecond{\Gm}{P}{T}{\allNs}
        = -\Partial{\Sm}{P}{T,\allNs}
    \\
    \cP = T \PartialMixSecond{\St}{\Nt}{T}{P} = -\PartialSecond{\Gm}{T}{P}
  \end{thermoNOsubscripts} 
  \end{thermoplain}
\end{gather*}

<table>
  <tr>
   <th>Macro</th> <th>moles-index</th> <th>moles-range</th>
  </tr>
  <tr>
    <td>\allNs</td> <td>\(\allNs\)</td>
    <td>\(\begin{thermomolesrange}\allNs\end{thermomolesrange}\)</td>
  </tr>
  <tr>
    <td>\allNsbut{1}</td> <td>\(\allNsbut{1}\)</td>
    <td>\(\begin{thermomolesrange}\allNsbut{1}\end{thermomolesrange}\)</td>
  </tr>
  <tr>
    <td>\allNsbut{i}</td> <td>\(\allNsbut{i}\)</td>
    <td>\(\begin{thermomolesrange}\allNsbut{i}\end{thermomolesrange}\)</td>
  </tr>
  <tr>
    <td>\allNsbut{j}</td> <td>\(\allNsbut{j}\)</td>
    <td>\(\begin{thermomolesrange}\allNsbut{j}\end{thermomolesrange}\)</td>
  </tr>
  <tr>
    <td>\allNsbut{\ncomponents}</td> <td>\(\allNsbut{\ncomponents}\)</td>
    <td>\(\begin{thermomolesrange}\allNsbut{\ncomponents}\end{thermomolesrange}\)</td>
  </tr>
  <tr>
    <td>\allNsbut[k]{i}</td> <td>\(\allNsbut[k]{i}\)</td>
    <td>\(\begin{thermomolesrange}\allNsbut[k]{i}\end{thermomolesrange}\)</td>
  </tr>
  <tr>
    <td>\allXs</td> <td>\(\allXs\)</td>
    <td>\(\begin{thermomolesrange}\allXs\end{thermomolesrange}\)</td>
  </tr>
  <tr>
    <td>\allXsbut{1}</td> <td>\(\allXsbut{1}\)</td>
    <td>\(\begin{thermomolesrange}\allXsbut{1}\end{thermomolesrange}\)</td>
  </tr>
  <tr>
    <td>\allXsbut{i}</td> <td>\(\allXsbut{i}\)</td>
    <td>\(\begin{thermomolesrange}\allXsbut{i}\end{thermomolesrange}\)</td>
  </tr>
  <tr>
    <td>\allXsbut{j}</td> <td>\(\allXsbut{j}\)</td>
    <td>\(\begin{thermomolesrange}\allXsbut{j}\end{thermomolesrange}\)</td>
  </tr>
  <tr>
    <td>\allXsbut{\ncomponents-1}</td> <td>\(\allXsbut{\ncomponents-1}\)</td>
    <td>\(\begin{thermomolesrange}\allXsbut{\ncomponents-1}\end{thermomolesrange}\)</td>
  </tr>
  <tr>
    <td>\allXsbut[k]{\ncomponents-1}</td> <td>\(\allXsbut[k]{\ncomponents-1}\)</td>
    <td>\(\begin{thermomolesrange}\allXsbut[k]{\ncomponents-1}\end{thermomolesrange}\)</td>
  </tr>
  <tr>
    <td>\allXsbut{\ncomponents}</td> <td>\(\allXsbut{\ncomponents}\)</td>
    <td>\(\begin{thermomolesrange}\allXsbut{\ncomponents}\end{thermomolesrange}\)</td>
  </tr>
</table>

</body>
</html>

Signed-off-by: Karl Hammond <kaiserkarl31@yahoo.com>
Signed-off-by: Karl Hammond <kaiserkarl31@yahoo.com>
Signed-off-by: Karl Hammond <kaiserkarl31@yahoo.com>
Signed-off-by: Karl Hammond <kaiserkarl31@yahoo.com>
Signed-off-by: Karl Hammond <kaiserkarl31@yahoo.com>
Signed-off-by: Karl Hammond <kaiserkarl31@yahoo.com>
Signed-off-by: Karl Hammond <kaiserkarl31@yahoo.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant