<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Archiving and Interchange DTD v1.0 20120330//EN" "JATS-archivearticle1.dtd">
<article xmlns:xlink="http://www.w3.org/1999/xlink">
  <front>
    <journal-meta />
    <article-meta>
      <title-group>
        <article-title>UoB at AI-SOCO 2020: Approaches to Source Code Classification and the Surprising Power of n-grams</article-title>
      </title-group>
      <contrib-group>
        <contrib contrib-type="author">
          <string-name>Alexander Crosby</string-name>
          <xref ref-type="aff" rid="aff0">0</xref>
        </contrib>
        <contrib contrib-type="author">
          <string-name>Harish Tayyar Madabushi</string-name>
          <xref ref-type="aff" rid="aff0">0</xref>
        </contrib>
        <aff id="aff0">
          <label>0</label>
          <institution>University of Birmingham</institution>
          ,
          <addr-line>Edgbaston, Birmingham, B15 2TT</addr-line>
          ,
          <country country="UK">United Kingdom</country>
        </aff>
      </contrib-group>
      <abstract>
        <p>Authorship identification of source code is the process of identifying the composer of given source code. Code authorship identification plays an important role in many real-world scenarios, such as the detection of plagiarism and ghost writing in both education and workplace settings. Additionally, it can allow the identification of individuals or organisations that produce and distribute malware programs. In this paper we describe the experimentation and submission by team UoB to the AI-SOCO track at FIRE 2020, which achieved first place. We first perform extensive testing on a variety of techniques used in source code authorship identification including n-gram, stylometric, and abstract syntax tree derived features. We also investigate the application of CodeBERT, a new pre-trained model that demonstrates state-of-the-art performance in natural and programming language tasks. Finally, we explore the potential of ensembling multiple models together to create a single superior model. Our winning model utilises byte-level n-grams extracted from source codes to build feature vectors that represent an author's programming style. These feature vectors are then used to train a densely connected neural network model to carry out authorship classification on previously unseen source codes, achieving an accuracy of 95.11%.</p>
      </abstract>
      <kwd-group>
        <kwd>authorship identification</kwd>
        <kwd>source code</kwd>
        <kwd>machine learning</kwd>
        <kwd>n-grams</kwd>
      </kwd-group>
    </article-meta>
  </front>
  <body>
    <sec id="sec-1">
      <title>1. Introduction</title>
      <p>
        Source code authorship attribution is the task of identifying the author of a given piece of
code [
        <xref ref-type="bibr" rid="ref1">1</xref>
        ]. The main concept behind authorship attribution is that each author uses a number of
stylistic traits when writing code that can be used as a fingerprint to distinguish one author
from another [
        <xref ref-type="bibr" rid="ref2">2</xref>
        ]. Authorship identification, therefore, is accomplished by identifying these
stylistic fingerprints and using statistical and machine learning models to attribute source code
to an author [
        <xref ref-type="bibr" rid="ref3">3</xref>
        ].
      </p>
      <p>
        There are a number of real world applications of source code attribution, such as the detection
of plagiarism [
        <xref ref-type="bibr" rid="ref4">4</xref>
        ], or the use of a ghost-writer in academic, workplace and other environments.
Additionally, code authorship attribution can be used to identify authors of malware [
        <xref ref-type="bibr" rid="ref5">5</xref>
        ], who
may attempt to conceal their identity or may obfuscate their code to hide its function and
origin [
        <xref ref-type="bibr" rid="ref6">6</xref>
        ].
      </p>
      <p>
        Authorship Identification of Source Code (AI-SOCO) 2020 is a track organised for the Forum
for Information Retrieval Evaluation (FIRE) 2020 [
        <xref ref-type="bibr" rid="ref7">7</xref>
        ]. The track asks for the identification of
efective strategies that solve the problem of source code authorship attribution in issues related
to “cheating, in academic, work and open source environments” and that help in the detection
of authors of malware software [
        <xref ref-type="bibr" rid="ref7">7</xref>
        ].
      </p>
      <p>
        The track involves a pre-defined set of 100,000 source codes made up from 1,000 unique
authors who had submitted code as part of Codeforces online programming competitions [
        <xref ref-type="bibr" rid="ref8">8</xref>
        ].
This data set was broken down to create a training, development, and test set of source codes.
The test set contained 25,000 source codes which did not have an attributed author, leaving
75,000 pieces of source code for training and development. Of this, 50,000 source codes were
used for training and 25,000 for development. Using these data sets, participants were required
to build a system that determined the author of each unlabelled source code. In the development
stage, participants are ranked based on their model’s performance on the development set.
In the evaluation stage, participants are ranked on their model’s performance on the 25,000
unlabelled source codes.
      </p>
      <p>This paper describes our submissions to the AI-SOCO 2020 track1. Our multi-faceted approach
evaluates a variety of diferent techniques previously used in authorship identification tasks
and additionally creates an ensemble model which pulls on the strengths of each individual
model. We find that our n-gram-based approach described in Section 3.3.2 outperformed all
other models we investigated, including modern state-of-the-art approaches, and achieved first
place on both the development and test datasets.</p>
    </sec>
    <sec id="sec-2">
      <title>2. Related Work</title>
      <p>This section provides an overview of diferent approaches related to authorship identification
attribution to identify promising techniques that inform the construction of our models.</p>
      <sec id="sec-2-1">
        <title>2.1. Stylometric Approaches</title>
        <p>
          Stylometry is perhaps the oldest technique in code authorship attribution and is based on the
identification of features in written text that could be linked to stylistic choices in a person’s
writing. One such example is the work of Krsul and Spaford [
          <xref ref-type="bibr" rid="ref9">9</xref>
          ], who proposed a total of 49
diferent features in 3 main areas: (1) layout specific metrics such as indentation and comment
style; (2) programming style such as variable, function and comment naming style; and (3)
program structure such as usage of specific data structures, presence of debugging identifiers or
assertions, and error handling.
        </p>
      </sec>
      <sec id="sec-2-2">
        <title>2.2. n-gram Approaches</title>
        <p>n-grams have been used successfully in a variety of Natural Language Processing (NLP) tasks,
including spell checking, language modelling and authorship attribution of text and have
successfully been ported to the field of authorship attribution.</p>
        <p>1Source code and data are published at https://github.com/AlexCrosby/AI-SOCO</p>
        <p>
          Frantzeskou et al. [
          <xref ref-type="bibr" rid="ref10">10</xref>
          ] introduces the profile-based Source Code Author Profile (SCAP)
method. This method is a profile-based approach that creates a profile of frequently used
byte-level n-grams for each author. Classification can then be carried out by finding the profile
that best matches an unlabelled source code by counting common n-grams between source
code and profile.
        </p>
        <p>
          Kothari et al. [
          <xref ref-type="bibr" rid="ref11">11</xref>
          ] demonstrated that character-level n-grams could be combined with
stylometric features to boost prediction accuracy, suggesting that combining diferent authorship
identification techniques could be a promising approach to use in this track.
        </p>
      </sec>
      <sec id="sec-2-3">
        <title>2.3. Abstract Syntax Tree Approaches</title>
        <p>Abstract Syntax Trees (ASTs) are a representation of the abstract syntactic structure of a source
code, represented in a hierarchical tree structure, that are a common source of information in
program analysis tasks.</p>
        <p>
          Caliskan-Islam et al. [
          <xref ref-type="bibr" rid="ref12">12</xref>
          ] proposed a stylometric feature set extracted from a source code’s
AST and combining that with lexical and layout features elicited directly from the source code,
in line with more classical stylometry methodologies and running them through a random
forest classifier. Caliskan-Islam et al. [
          <xref ref-type="bibr" rid="ref12">12</xref>
          ] then found that the feature that best discriminated
between authors was AST node bigrams. Each bigram was made up from a node and the parent
node it was directly connected to to. The term frequencies of these bigrams, when used for
classification, demonstrated an accuracy comparable to using these bigrams in combination
with the extracted lexical and layout features.
        </p>
      </sec>
      <sec id="sec-2-4">
        <title>2.4. CodeBERT</title>
        <p>
          CodeBERT [
          <xref ref-type="bibr" rid="ref13">13</xref>
          ] is a pre-trained multi-layer bidirectional Transformer model based on the
same architecture used in RoBERTa. Unlike RoBERTa, CodeBERT is designed to be used in
both natural language and programming language applications, such as code documentation
generation and natural language code search. CodeBERT produces word-level vectors for a
source code using contextual information taken from surrounding word contexts, as opposed to
information from the code AST as is done by models such as code2vec [
          <xref ref-type="bibr" rid="ref14">14</xref>
          ] and code2seq [
          <xref ref-type="bibr" rid="ref15">15</xref>
          ].
        </p>
      </sec>
    </sec>
    <sec id="sec-3">
      <title>3. Methodology</title>
      <p>This section outlines the techniques used to generate each model used for authorship attribution
in the AI-SOCO 2020 track. Each model detailed was devised to identify meaningful vector
embeddings for source codes and assess their overall efectiveness, with the end goal being the
ensembling of a variety of diferent techniques to provide an overall superior model.</p>
      <sec id="sec-3-1">
        <title>3.1. Preprocessing</title>
        <p>Depending on the features required by each model, the source codes were preprocessed to make
extraction of said features possible. Two diferent preprocessed datasets were generated for
this purpose. The first of these involved the removal of all comment lines and the unfolding of
“#define” preprocessor directives which may otherwise obfuscate features extracted from the
program structure and is a requirement for AST extraction.</p>
        <p>The second preprocessed dataset was the ASTs for each source code extracted directly from
the first preprocessed dataset.</p>
        <p>
          Both of these preprocessing stages were carried out using the tool astminer [
          <xref ref-type="bibr" rid="ref16">16</xref>
          ] using Google
Cloud Platform’s Compute Engine.
        </p>
      </sec>
      <sec id="sec-3-2">
        <title>3.2. Initial Experimentation</title>
        <p>Our initial experimentations were expansions on the character count and bag-of-words term
frequency–inverse document frequency (TF-IDF) vectorisation techniques used in the baseline
models; plus a variant on the character count where only A-Z characters were considered,
ignoring case. These vectors were all used to train four diferent machine learning models:
Logistic Regression; k-nearest neighbours; Naïve Bayes classifier; and a support vector classifier.</p>
        <p>While these models did not perform particularly well, achieving a best accuracy of 74.996%
using the TF-IDF vectors in a Logistic Regression model shown in Section 3, they did identify
that the Naïve Bayes classifier was both quick to train and had moderate accuracy, meaning it
was a good candidate model to evaluate vectorisation techniques used in further models.</p>
      </sec>
      <sec id="sec-3-3">
        <title>3.3. n-gram Models</title>
        <sec id="sec-3-3-1">
          <title>3.3.1. Source Code Author Profile Method</title>
          <p>
            The SCAP method discussed in Section 2.2 was implemented based on its success in cases where
only very short pieces of code were available, such as in our dataset [
            <xref ref-type="bibr" rid="ref17">17</xref>
            ].
          </p>
          <p>In this method, character or byte-level n-grams are extracted from the raw source codes and
used to create vector representations. This method involves the generation of a profile for each
author by creating a set of the L most commonly occurring n-grams for each author throughout
their source codes. Then, to calculate an unseen source code’s similarity with each profile, the
Simplified Profile Intersection (SPI) is measured.</p>
          <p>Letting Pa be the author profile n-gram set and Ps being the n-gram set of the previously
unseen source code, the SPI value between Pa and Ps is given by the magnitude of the intersection
of the two profiles (see Equation 1).</p>
          <p>= | ∩ |
(1)</p>
          <p>The unseen source code is hence attributed to the author profile achieving the highest SPI
value.</p>
          <p>
            To select n-gram size , profile length  and whether to use character or byte n-grams, an
exhaustive grid search was carried out to identify the best performing settings. In addition to
a set  value, we also investigated using an unlimited profile length and excluding n-grams
that only have a frequency of 1 as proposed by Tennyson and Mitropoulos [
            <xref ref-type="bibr" rid="ref18">18</xref>
            ]. Overall, this
technique managed to achieve an accuracy of 92.212% on the development dataset as shown
in Section 4.1.1.
A second n-gram based approach was proposed based on the success of the SCAP method
(Section 3.3.1). In this model, the raw source codes were decomposed into their constituent
character or byte-level n-grams. Unlike SCAP however, these n-grams were represented as a
bag of n-grams which would be used to train machine learning models to predict authorship
through the co-occurrence of n-grams in any given source code.
          </p>
          <p>A Naïve Bayes classifier was used to identify the best candidate representations that would
later be used to train the neural network.</p>
          <p>The best candidate n-gram representation identified at this stage was then used downstream
as the input in a neural network classifier model.</p>
          <p>In addition to character and byte-level n-grams, a bag-of-Words (BoW) model was also
conceived. In this model, vectors represented word-level n-grams extracted from the training
dataset. Unlike the other n-gram models, only word n-grams of size 1 were used. However, the
entire vocabulary of the training dataset, a total of 60,770 words, is used rather than limiting
them to a specified max size as discussed in Section 5.5.</p>
          <p>This model achieved an accuracy of 95.416% on the development dataset as detailed in 4.1.2.
Due to the increased accuracy of this instance-based model over the profile-based SCAP method,
going forwards only this instance-based n-gram model was used. The final accuracy of this
model on the test dataset was 95.11% as mentioned in Section 4.4.</p>
        </sec>
      </sec>
      <sec id="sec-3-4">
        <title>3.4. Abstract Syntax Tree Model</title>
        <p>
          In this approach, features were derived from the preprocessed dataset containing the AST
structures derived from the source codes. This model was developed based on its successful
implementation by Caliskan-Islam et al. [
          <xref ref-type="bibr" rid="ref12">12</xref>
          ] and Wisse and Veenman [
          <xref ref-type="bibr" rid="ref19">19</xref>
          ].
        </p>
        <p>These ASTs contain information relating to the node type, the code that relates to said node,
and the relationships between each node. These nodes are then tokenised by substituting each
unique node with a numerical representation. Likewise n-grams of nodes are tokenised, in
which a node bi-gram would be a node and its parent node and so on.</p>
        <p>These tokens are then used to create a vector representation that describe the occurrence of
the top most commonly occurring tokens in the training dataset. Like the n-gram model, multiple
AST vectors variants were evaluated in order to identify best performing vector parameters.
These parameters were then to generate the vectors used downstream to train a neural network
classifier model. The final accuracy achieved by this model on the development dataset was
80.052% as shown in Section 4.2.</p>
      </sec>
      <sec id="sec-3-5">
        <title>3.5. Stylometry Model</title>
        <p>In this model, 136 diferent stylistic and layout features were extracted from both the raw and
preprocessed source codes without comments and “#define” directives. 100 of these 136 features
were counts of the printable characters as used in the baseline model.</p>
        <p>
          The remaining 36 features are documented in the repository released alongside this paper
and were collated due to their common use in multiple papers on this topic [
          <xref ref-type="bibr" rid="ref12">12, 20, 21</xref>
          ].
        </p>
        <p>136-dimensional vectors representing these features from each source code were then used
to train a densely-connected neural network classifier model. This model achieved an accuracy
of 75.376% on the development dataset as shown in Section 3.</p>
      </sec>
      <sec id="sec-3-6">
        <title>3.6. CodeBERT Model</title>
        <p>This model introduces CodeBERT to the task of authorship attribution, a domain that, to this
author’s knowledge, the model has not been applied to previously.</p>
        <p>We fine-tuned the CodeBERT model (provided at https://github.com/microsoft/CodeBERT)
for authorship attribution using an NVIDIA K80 GPU on an Amazon Web Services p2.xlarge
instance for 10 epochs using the Adam optimiser at a learning rate of 2 × 10− 5. As shown
in Section 3, this model achieved an accuracy of 86.724% on the development dataset.</p>
      </sec>
      <sec id="sec-3-7">
        <title>3.7. Weighted Average Ensemble</title>
        <p>The idea behind ensembling is that each model, when independently trained, is likely to
have diferent strengths while classifying source codes. By combining individual models their
strengths can be pulled together to get a more accurate classification than by any one model
alone [22].</p>
        <p>Following the creation of the previously mentioned models, five candidates were selected
based on performance and diference in feature representations. These models were: The
n-gram, BoW, AST, stylometry and CodeBERT models.</p>
        <p>One ensembling technique experimented with was a weighted averaging procedure. In an
average ensemble this is achieved by simply averaging the SoftMax outputs from each model
to get the average prediction of all models. A common problem with this method is that if
one model performs significantly worse, it can drag the overall prediction accuracy down. To
combat this, each model is given a diferent weighting, allowing some models to contribute
more to the pooled classification, and others less [22]</p>
        <p>Two diferent optimisation techniques were tested in identifying the best weight values:
Powell’s conjugate direction method [23], and Diferential Evolution [ 24]. These two methods
were used as an attempt to avoid getting stuck in a local minimum due to the reliance on any
single optimisation method. The best performing weights on the development dataset were
selected to be used in the final ensemble. This model outperformed all other models on the
development dataset, achieving an accuracy of 95.715% as discussed in Section 4.1.2. However,
it did not manage to outperform the instance-based n-gram model on the test dataset, achieving
an accuracy of 95.11% as shown in Section 4.4.</p>
      </sec>
      <sec id="sec-3-8">
        <title>3.8. Discarded Methods</title>
        <sec id="sec-3-8-1">
          <title>3.8.1. Convolutional Neural Network Model</title>
          <p>Another deep-learning model evaluated was a Convolutional Neural Network (CNN) model. In
this model, each word in the source codes are given a numerical token representation. This
ordered list of tokens is then fed into the CNN model.</p>
          <p>This model contains five main layers. The first is the embedding layer, that learns a
multidimensional vector representation for each word during training specific to our task.</p>
          <p>This sequence of embeddings is then fed into a 1-dimensional convolutional layer which
extracts features useful for classification decisions over the sequence of word embeddings. This
is then fed into a MaxPooling layer to down sample the convolutional layer’s output feature
map to reduce model size and training time.</p>
          <p>It is this pooled layer that is then fed into the LSTM layer of the CNN to generate a final
source code vector than is then classified with a final SoftMax layer. Unfortunately, in the initial
testing of this model the results were poor, failing to surpass any of our previous models with a
accuracy of 73.880% as shown in Section 3. As we did not have enough time to fully explore the
capability of this model, we decided to discontinue further research on this model in favour of
our better performing models.</p>
        </sec>
        <sec id="sec-3-8-2">
          <title>3.8.2. Stacked Neural Network Ensemble</title>
          <p>In addition to the weighted average ensemble discussed in Section 3.7, another stacked neural
network ensembling technique was trialled.</p>
          <p>In this model, a single multi-headed neural network model was constructed. This model uses
the same architectures as the individual models but concatenates them all at their final hidden
layer before the final SoftMax classification layer. This also allows all models to be trained
simultaneously, allowing for diferences in the models from the original versions that allow for
improved ensembling.</p>
          <p>Due to the size of this model, a few concessions were made to reduce its size: first, the
CodeBERT model was excluded from the ensemble since it was the largest individual model by
a considerable margin. Instead, the final hidden layer values from the CodeBERT model were
pre-calculated and input directly into this model at the concatenation layer. Additionally, only
the single best n-gram model from those discussed in Section 3.3 was used.</p>
          <p>Due to the size of this model, it experienced significant overfitting issues during development
which would have required significant changes to overcome. This model was hence discarded
in favour of the more promising weighted average ensemble strategy.</p>
        </sec>
      </sec>
    </sec>
    <sec id="sec-4">
      <title>4. Results</title>
      <p>This chapter outlines our findings and analysis of results of the application of our models defined
in Section 3.</p>
      <p>The highest accuracies achieved at each stage of experimentation on the development dataset
are presented in Table 1. The n-gram-based neural network model achieved the best individual
model accuracy at 95.416%. The top ensemble accuracy achieved was 95.716%, achieved through
the weighted averaging ensemble of the five models, discussed in Section 3.7.</p>
      <p>All models were evaluated based on their accuracy on the development dataset as that was
the only metric considered in evaluating and ranking submitted systems in the AI-SOCO 2020
track.</p>
      <sec id="sec-4-1">
        <title>4.1. n-gram Results</title>
        <sec id="sec-4-1-1">
          <title>4.1.1. Source Code Author Profile Method</title>
          <p>The highest accuracy achieved by the SCAP method on the development dataset was 92.212%
was the highest accuracy achieved using  = 9 and  = 8000 on character-level n-grams.</p>
        </sec>
        <sec id="sec-4-1-2">
          <title>4.1.2. n-gram Model Results</title>
          <p>As outlined in Section 3.3.2, initial vector parameter exploration was carried out using a Naïve
Bayes Model to find the best combination to feed to the neural network classifier model.</p>
          <p>The best overall accuracy at this stage was achieved using character-level n-gram vectors
made up of the normalised feature count of the top 10,000 occurring 8-grams in each of the
source code and achieved an accuracy of 85.648% on the development dataset.</p>
          <p>During the neural network hyperparameter optimisation stage, we found that diferent vector
parameters were more efective. Experimentations on these parameters in the neural network
model are shown in Table 2.</p>
          <p>The final vector parameters selected used byte-level 6-grams, using binary representation of
the top 20,000 most commonly occurring 6-grams. This achieved the final accuracy of 95.416%
on the development dataset as shown in Table 1. The architecture of the neural net used two
hidden layers containing 3,000 and 2,000 neurons respectively. The model also used dropout
layers with a dropout rate of 0.5 between the two hidden layers and between the second hidden
layer and final output layer. The model used an initial learning rate of 1 × 10− 4 using the
RMSProp algorithm.</p>
        </sec>
        <sec id="sec-4-1-3">
          <title>4.1.3. Bag-of-Words Model Results</title>
          <p>For the BoW model, we found that the highest accuracy achieved was 82.96% on the development
dataset, using a binary enumeration representation.</p>
        </sec>
      </sec>
      <sec id="sec-4-2">
        <title>4.2. Abstract Syntax Tree Model Results</title>
        <p>The highest accuracy achieved using ASTs used node unigrams. These nodes were enumerated
with a binary count representation, in which only the top 20,000 most commonly occurring
nodes were represented. Using a Naïve Bayes classifier model, this representation achieved an
overall accuracy of 64.308% on the development dataset. This vector representation was then
used to train a neural network classifier, achieving an accuracy of 80.052% on the development
dataset as shown in Table 1.</p>
      </sec>
      <sec id="sec-4-3">
        <title>4.3. Weighted Average Ensemble Results</title>
        <p>Both Powell’s conjugate direction method and Diferential Evolution were used as optimisation
techniques to find the best weights for the models of the ensemble as discussed in Section 3.7.
Both algorithms concurred on the weights for each model, that when used in ensembling, gives
an accuracy of 95.716% on the development dataset, as shown in Table 1. The weights derived
by Powell’s method and Diferential Evolution for each model were: n-gram - 0.3079; CodeBERT
- 0.19504; BoW - 0.09437; AST - 0.31464; and stylometry - 0.08805.</p>
      </sec>
      <sec id="sec-4-4">
        <title>4.4. Submitted Results</title>
        <p>For the development phase of the AI-SOCO 2020 track, we submitted the results from our
n-gram model which achieved an accuracy of 95.416%. The weighted average ensemble result
was not submitted as this phase ended prior to its completion. In this phase we achieved first
place.</p>
        <p>For the evaluation phase, we again submitted the n-gram model predictions on the test set
alongside the predictions from the weighted average ensemble. The results of our models in
this phase are shown in Table 3.</p>
        <p>With these results, we again managed to take first place in this phase of the track.</p>
      </sec>
    </sec>
    <sec id="sec-5">
      <title>5. Analysis and Discussion</title>
      <p>In this section, we discuss some observations made in two of our most powerful models that
subverted the author’s expectations, as well as analysing the models strengths and weaknesses.</p>
      <sec id="sec-5-1">
        <title>5.1. Weighted Average Ensemble</title>
        <p>While the weighted average ensemble was the best model overall, its results do highlight some
issues. Firstly, there is only a 0.3% accuracy increase over the n-gram model alone. From our
ensemble analysis, it is clear that whatever other models can classify correctly, the n-gram
model can typically make the same correct predictions, in addition to making predictions that
other models cannot, resulting in the ensemble’s component models providing little benefit. It
is also evident that when models share some degree of overlap, they are less efective in the
ifnal ensemble. This indicates that the final ensemble would likely benefit from having a more
diverse set of constituent models rather than models that extract features from the same raw
textual data.</p>
      </sec>
      <sec id="sec-5-2">
        <title>5.2. n-gram Model</title>
        <p>
          The n-gram model was ultimately our most powerful author classifier, with only the similar
SCAP method coming close to the same accuracy. This demonstrates that character and
byte-level n-grams are likely the best individual representation for the source codes in our
dataset. Frantzeskou et al. [
          <xref ref-type="bibr" rid="ref17">17</xref>
          ] discuss how their SCAP method has strong performance, even
when there is very limited training data per author available. Our results suggest that perhaps
the good performance has less to do with the SCAP method itself, and more to do with n-gram
features being more powerful than other vector representations in these limited feature datasets,
hence why our n-gram neural network model outperformed other models as well.
        </p>
        <p>One perplexing observation is how the optimised vector representation used in the Naïve
Bayes model difered significantly to the optimal vector used in the neural network mode. In
addition to a smaller  value being used, a binary count performed better than the frequency
count values. This is an odd observation, as the initial assumption was that more information
was contained in a normalised count, as it detailed how often an author used a specific n-gram
rather than if they just used it at least once or not. Similarly, TF-IDF of n-grams performed worse,
even more so than just normalised counts. Combined with our findings in Section 4.1.2, this
suggests that commonly occurring words, that would typically be weighted down in TF-IDF, are
indeed important in making classification decisions, as opposed to more unique features which
would not be represented in the final vectors. This poses a possible new avenue of approach for
future work for this model in which a better selection of n-grams could be identified to make
up our vector representation that could potentially improve accuracy.</p>
      </sec>
      <sec id="sec-5-3">
        <title>5.3. CodeBERT Model</title>
        <p>
          Despite having demonstrated state-of-the-art performance in a number of NL-PL tasks [
          <xref ref-type="bibr" rid="ref13">13</xref>
          ],
CodeBERT failed to outperform n-gram-based models. This is perhaps unsurprising as
CodeBERT’s focus is on NL-PL understanding tasks. It may be the case that classifications are being
made on the basis of vocabulary used or that the classification token does not encapsulate
enough information to distinguish between 1000 authors.
        </p>
      </sec>
      <sec id="sec-5-4">
        <title>5.4. Ensemble Analysis</title>
        <p>An ensemble analysis was carried out to investigate how each individual model contributed to
the overall ensemble.</p>
        <p>This study was carried out by analysing all ensemble combinations of any two given models
used in the final weighted average ensemble. Table 4 shows the accuracies of all these
combinations. This table shows that any combination involving n-grams will typically be the best
performing and that overall, other models do not make a significant impact above the base
n-gram accuracy. The highest accuracy achieved by an n-gram combination was n-gram ×
CodeBERT models, achieving 95.528% accuracy, a 0.112% increase over n-grams alone.</p>
        <p>Other combinations, however, can significantly increase the accuracy over the individual
components. For example, the AST × Stylometry ensemble accuracy is improved by 5.82% over
the AST model alone and 10.496% better over the stylometry model alone.</p>
        <p>An ablation study was also carried out, investigating the efect of removing individual models
from the final weighted average ensemble. Table 5 shows the efects of these ablations on the
ifnal ensemble accuracy.</p>
        <p>Whilst it is unsurprising that the BoW and stylometry models had little impact on the final
accuracies given their small weights deduced in Section 4.3, the results displayed by the AST
model are curious. Much like the BoW and stylometry models, it had a relatively small impact
on final ensemble accuracy, however in the ensemble this model is given a higher weight than
any of the other constituent models despite being second worst in terms of raw accuracy.</p>
        <p>It is not entirely clear why a model with such a significant weight has so little contribution,
but it could be attributed to the diversity of the information captured by the AST vectors. Unlike
the other models that extract their features from the raw source code, the AST model features
are discovered as the result of syntax analysis carried out by a compiler and represents the
actual working structure of the code. In other words, these other models have a higher degree
of overlap in the information they contain, since their features all come from the same source,
while the AST model has features that no other model has access to, and it is this diversity that
could confer the higher weighting.</p>
      </sec>
      <sec id="sec-5-5">
        <title>5.5. Error Analysis</title>
        <p>To investigate why our n-gram model significantly outperformed all other models and to explore
potential avenues of work that could lead to increased accuracy, an error analysis was carried
out.</p>
        <p>The first step in this process was to identify mistakes consistently made by all models. By
intersecting the errors made by each individual model, a set of 822 source codes were identified
that were never predicted correctly by any model belonging to 430 diferent authors. Over half
of these authors were one-of misclassifications, leaving only 189 authors that had multiple
misclassifications. By analysing the source codes from some of these authors, some consistent
characteristics were identified that were shared by these misclassifications. A case study of the
author labelled 376 provides a clear example of some of these features.</p>
        <p>Source codes from author 376 which are correctly identified in the ensemble model contain
the same “#define” pre-processor directives and comment signature at the top of the source
codes. Figure 1 however, exhibits three source codes from the same author that were not
classified correctly. Notable in these source codes, is that the comment and “#define”
preprocessor directives were absent, or in the case of Figure 1(a), altered from the authors typical
usage. These features were also missing in all other misclassified source codes from this author.
Additionally, the actual code contained is both short, typically being less than 30 lines, and
lacking complex variable names, preferring to use single letter identifiers. This is also consistent
with a significant proportion of misidentified source codes from other authors and it may be
this lack of extractable information that leads to the models consistently getting them wrong.</p>
        <p>Next, an n-gram specific error analysis was carried out where  = 6. To analyse the
weaknesses of this model, a number of author source codes were again analysed. Figure 2
contains three such source codes from the author labelled 672.</p>
        <p>All of these source codes, along with the remaining correctly identiefid source codes from
this author, share 52 common n-grams and, often, a unique comment at the start of the code.
1 #include &lt;bits/stdc++.h&gt;
2 using namespace std;
3
4 int t, a, b, c, d;
5
6 int main() {
7 for (cin &gt;&gt; t; t; t--) {
8 cin &gt;&gt; a &gt;&gt; b &gt;&gt; c &gt;&gt; d;
9 cout &lt;&lt; b &lt;&lt; " " &lt;&lt; c &lt;&lt; " " &lt;&lt; c &lt;&lt; endl;
10 }
11 return 0;
12 }</p>
        <p>Curiously however, the source code Figure 2(c) is misidentified by the n-gram model despite
the shared n-grams and comment. Upon investigating the shared features, a notable pattern
emerged where the 52 common n-grams exclusively corresponded to five repeating features
found in the authors source codes:
using namespace std;
int main() {
scanf("%
return 0;
A significant note is that none of the 52 common n-grams were derived from the unique comment
at the start of the source codes. Several conclusions can be made from this: firstly, features
1 /*jai mata di
2 let’s rock*/
3 #include &lt;bits/stdc++.h&gt;
4 using namespace std;
5 const int N=200004;
6 long long sum[N];
7 int a[N];
8 int main()
9 {
10 int n,m;
11 scanf("%d %d",&amp;n,&amp;m);
12 int i;
13 for(i=1;i&lt;=n;i++)
14 {
15 scanf("%d",&amp;a[i]);
16 }
17 sort(a+1,a+n+1);
18 long long ans=0;
19 for(i=1;i&lt;=n;i++)
20 {
21 sum[i%m]+=a[i];
22 ans=ans+sum[i%m];
23 printf("%lld ",ans);
24 }
25 printf("\n");
26 return 0;
27 }
val=val*10+i;
if(val&lt;=n) cnt++;
such as unique comments were largely unused in making classifications in this n-gram model.
This can largely be explained by the fact that only the top 20,000 most commonly occurring
n-grams were used in the model. These unique comments simply did not appear often enough
to be included in the model. Secondly, the remaining 52 common n-grams alone were not
enough to uniquely identify this author as they were commonly used in source codes by many
other authors. This means that while these n-grams may have made some contribution; other
n-grams that were not shared between these source codes were certainly considered in making
the classifications.</p>
        <p>It was the lack of consideration of the unique comments used by many authors discovered
during this analysis that prompted the creation of the BoW model. This model was designed to
use every word found in the dataset, so it would be able to make determinations on features
not common enough to be considered by the n-gram model. The BoW model does successfully
classify the source code shown in Figure 2(c) misidentified by the n-gram model. However, this
is not reflected in the final weighted average ensemble, where it is again misclassified, likely
due to the BoW only having a small weight and hence small contribution to the final result.</p>
        <p>Finally, to identify the strengths of the n-gram model, source codes that only the n-gram
model successfully identified were analysed.</p>
        <p>Surprisingly, it was found that the n-gram model can identify short source codes, seemingly
typical of those that are regularly misidentified by itself and other models, that lack distinct
features to the naked eye. Clearly the n-gram model is still able to identify combinations of
features that can be attributed to an individual author in these source codes regardless, unlike
other models. Unfortunately, due to the black-box nature of neural networks, it is not entirely
clear what the specific features are, but this could provide a focus for future research.</p>
      </sec>
    </sec>
    <sec id="sec-6">
      <title>6. Conclusion</title>
      <p>In this work we found that a simple n-gram based neural network classifier model was capable
of outperforming all of the other individual models that we investigated. We also found that
our n-gram-based model outperformed our weighted average ensemble, which was unexpected
as our weighted average ensemble had performed better on the development set.</p>
      <p>With this n-gram based model, we achieved first place in the track with an accuracy of 95.11%.</p>
      <p>Further research into this work could focus on other potential ensembling techniques that
may better translate to unseen data and deep learning approaches that could better leverage
the power of n-grams. Additionally we believe that a deeper analysis into what features are
being used as the basis of classification in our n-gram model could provide noteworthy insight
into how best to improve the model and why it performs so well compared to other models.</p>
    </sec>
    <sec id="sec-7">
      <title>Acknowledgments</title>
      <p>Thanks to the NVIDIA Deep Learning Institute for providing GPU resources through Amazon
Web Services.</p>
      <p>Investigation 15 (2015) 61–71.
[20] H. Ding, M. H. Samadzadeh, Extraction of java program fingerprints for software
authorship identification, Journal of Systems and Software 72 (2004) 49–57.
[21] C. Zhang, S. Wang, J. Wu, Z. Niu, Authorship identification of source codes, in: Asia-Pacific
Web (APWeb) and Web-Age Information Management (WAIM) Joint Conference on Web
and Big Data, Springer, 2017, pp. 282–296.
[22] F. Chollet, Deep Learning with Python, Manning, 2017.
[23] M. J. Powell, An eficient method for finding the minimum of a function of several variables
without calculating derivatives, The computer journal 7 (1964) 155–162.
[24] R. Storn, K. Price, Diferential evolution–a simple and eficient heuristic for global
optimization over continuous spaces, Journal of global optimization 11 (1997) 341–359.</p>
    </sec>
  </body>
  <back>
    <ref-list>
      <ref id="ref1">
        <mixed-citation>
          [1]
          <string-name>
            <given-names>P. W.</given-names>
            <surname>Oman</surname>
          </string-name>
          ,
          <string-name>
            <given-names>C. R.</given-names>
            <surname>Cook</surname>
          </string-name>
          ,
          <article-title>Programming style authorship analysis</article-title>
          ,
          <source>in: Proceedings of the 17th conference on ACM Annual Computer Science Conference</source>
          ,
          <year>1989</year>
          , pp.
          <fpage>320</fpage>
          -
          <lpage>326</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref2">
        <mixed-citation>
          [2]
          <string-name>
            <given-names>V.</given-names>
            <surname>Kalgutkar</surname>
          </string-name>
          ,
          <string-name>
            <given-names>R.</given-names>
            <surname>Kaur</surname>
          </string-name>
          ,
          <string-name>
            <given-names>H.</given-names>
            <surname>Gonzalez</surname>
          </string-name>
          ,
          <string-name>
            <given-names>N.</given-names>
            <surname>Stakhanova</surname>
          </string-name>
          ,
          <string-name>
            <given-names>A.</given-names>
            <surname>Matyukhina</surname>
          </string-name>
          ,
          <article-title>Code authorship attribution: Methods and challenges</article-title>
          ,
          <source>ACM Computing Surveys (CSUR) 52</source>
          (
          <year>2019</year>
          )
          <fpage>1</fpage>
          -
          <lpage>36</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref3">
        <mixed-citation>
          [3]
          <string-name>
            <given-names>R. C.</given-names>
            <surname>Lange</surname>
          </string-name>
          ,
          <string-name>
            <given-names>S.</given-names>
            <surname>Mancoridis</surname>
          </string-name>
          ,
          <article-title>Using code metric histograms and genetic algorithms to perform author identification for software forensics</article-title>
          ,
          <source>in: Proceedings of the 9th annual conference on Genetic and evolutionary computation</source>
          ,
          <year>2007</year>
          , pp.
          <fpage>2082</fpage>
          -
          <lpage>2089</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref4">
        <mixed-citation>
          [4]
          <string-name>
            <given-names>B.</given-names>
            <surname>Stein</surname>
          </string-name>
          ,
          <string-name>
            <given-names>N.</given-names>
            <surname>Lipka</surname>
          </string-name>
          ,
          <string-name>
            <given-names>P.</given-names>
            <surname>Prettenhofer</surname>
          </string-name>
          ,
          <article-title>Intrinsic plagiarism analysis</article-title>
          ,
          <source>Language Resources and Evaluation</source>
          <volume>45</volume>
          (
          <year>2011</year>
          )
          <fpage>63</fpage>
          -
          <lpage>82</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref5">
        <mixed-citation>
          [5]
          <string-name>
            <given-names>G.</given-names>
            <surname>Frantzeskou</surname>
          </string-name>
          ,
          <string-name>
            <given-names>S. G.</given-names>
            <surname>MacDonell</surname>
          </string-name>
          , E. Stamatatos,
          <article-title>Source code authorship analysis for supporting the cybercrime investigation process</article-title>
          ,
          <source>in: Handbook of Research on Computational Forensics, Digital Crime, and Investigation: Methods and Solutions, IGI Global</source>
          ,
          <year>2010</year>
          , pp.
          <fpage>470</fpage>
          -
          <lpage>495</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref6">
        <mixed-citation>
          [6]
          <string-name>
            <given-names>B.</given-names>
            <surname>Alsulami</surname>
          </string-name>
          , E. Dauber,
          <string-name>
            <given-names>R.</given-names>
            <surname>Harang</surname>
          </string-name>
          ,
          <string-name>
            <given-names>S.</given-names>
            <surname>Mancoridis</surname>
          </string-name>
          ,
          <string-name>
            <given-names>R.</given-names>
            <surname>Greenstadt</surname>
          </string-name>
          ,
          <article-title>Source code authorship attribution using long short-term memory based networks</article-title>
          ,
          <source>in: European Symposium on Research in Computer Security</source>
          , Springer,
          <year>2017</year>
          , pp.
          <fpage>65</fpage>
          -
          <lpage>82</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref7">
        <mixed-citation>
          [7]
          <string-name>
            <given-names>A.</given-names>
            <surname>Fadel</surname>
          </string-name>
          ,
          <string-name>
            <given-names>H.</given-names>
            <surname>Musleh</surname>
          </string-name>
          , I. Tufaha,
          <string-name>
            <given-names>M.</given-names>
            <surname>Al-Ayyoub</surname>
          </string-name>
          ,
          <string-name>
            <given-names>Y.</given-names>
            <surname>Jararweh</surname>
          </string-name>
          , E. Benkhelifa,
          <string-name>
            <given-names>P.</given-names>
            <surname>Rosso</surname>
          </string-name>
          ,
          <article-title>Overview of the PAN@FIRE 2020 task on Authorship Identification of SOurce COde (AI-SOCO), in: Proceedings of The 12th meeting of the Forum for Information Retrieval Evaluation (FIRE</article-title>
          <year>2020</year>
          ), CEUR Workshop Proceedings, CEUR-WS.org,
          <year>2020</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref8">
        <mixed-citation>
          [8]
          <string-name>
            <surname>Codeforces</surname>
          </string-name>
          ,
          <year>2020</year>
          . URL: http://codeforces.com/.
        </mixed-citation>
      </ref>
      <ref id="ref9">
        <mixed-citation>
          [9]
          <string-name>
            <given-names>I.</given-names>
            <surname>Krsul</surname>
          </string-name>
          ,
          <string-name>
            <given-names>E. H.</given-names>
            <surname>Spaford</surname>
          </string-name>
          ,
          <article-title>Authorship analysis: Identifying the author of a program</article-title>
          ,
          <source>Computers &amp; Security</source>
          <volume>16</volume>
          (
          <year>1997</year>
          )
          <fpage>233</fpage>
          -
          <lpage>257</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref10">
        <mixed-citation>
          [10]
          <string-name>
            <given-names>G.</given-names>
            <surname>Frantzeskou</surname>
          </string-name>
          ,
          <string-name>
            <given-names>E.</given-names>
            <surname>Stamatatos</surname>
          </string-name>
          ,
          <string-name>
            <given-names>S.</given-names>
            <surname>Gritzalis</surname>
          </string-name>
          ,
          <string-name>
            <given-names>C. E.</given-names>
            <surname>Chaski</surname>
          </string-name>
          ,
          <string-name>
            <given-names>B. S.</given-names>
            <surname>Howald</surname>
          </string-name>
          ,
          <article-title>Identifying authorship by byte-level n-grams: The source code author profile (scap) method</article-title>
          ,
          <source>International Journal of Digital Evidence</source>
          <volume>6</volume>
          (
          <year>2007</year>
          )
          <fpage>1</fpage>
          -
          <lpage>18</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref11">
        <mixed-citation>
          [11]
          <string-name>
            <given-names>J.</given-names>
            <surname>Kothari</surname>
          </string-name>
          ,
          <string-name>
            <given-names>M.</given-names>
            <surname>Shevertalov</surname>
          </string-name>
          ,
          <string-name>
            <given-names>E.</given-names>
            <surname>Stehle</surname>
          </string-name>
          ,
          <string-name>
            <given-names>S.</given-names>
            <surname>Mancoridis</surname>
          </string-name>
          ,
          <article-title>A probabilistic approach to source code authorship identification</article-title>
          ,
          <source>in: Fourth International Conference on Information Technology (ITNG'07)</source>
          , IEEE,
          <year>2007</year>
          , pp.
          <fpage>243</fpage>
          -
          <lpage>248</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref12">
        <mixed-citation>
          [12]
          <string-name>
            <given-names>A.</given-names>
            <surname>Caliskan-Islam</surname>
          </string-name>
          ,
          <string-name>
            <given-names>R.</given-names>
            <surname>Harang</surname>
          </string-name>
          ,
          <string-name>
            <given-names>A.</given-names>
            <surname>Liu</surname>
          </string-name>
          ,
          <string-name>
            <given-names>A.</given-names>
            <surname>Narayanan</surname>
          </string-name>
          ,
          <string-name>
            <given-names>C.</given-names>
            <surname>Voss</surname>
          </string-name>
          ,
          <string-name>
            <given-names>F.</given-names>
            <surname>Yamaguchi</surname>
          </string-name>
          , R. Greenstadt, De-anonymizing programmers via code stylometry,
          <source>in: 24th {USENIX} Security Symposium ({USENIX} Security 15)</source>
          ,
          <year>2015</year>
          , pp.
          <fpage>255</fpage>
          -
          <lpage>270</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref13">
        <mixed-citation>
          [13]
          <string-name>
            <given-names>Z.</given-names>
            <surname>Feng</surname>
          </string-name>
          ,
          <string-name>
            <given-names>D.</given-names>
            <surname>Guo</surname>
          </string-name>
          ,
          <string-name>
            <given-names>D.</given-names>
            <surname>Tang</surname>
          </string-name>
          ,
          <string-name>
            <given-names>N.</given-names>
            <surname>Duan</surname>
          </string-name>
          ,
          <string-name>
            <given-names>X.</given-names>
            <surname>Feng</surname>
          </string-name>
          ,
          <string-name>
            <given-names>M.</given-names>
            <surname>Gong</surname>
          </string-name>
          ,
          <string-name>
            <given-names>L.</given-names>
            <surname>Shou</surname>
          </string-name>
          ,
          <string-name>
            <given-names>B.</given-names>
            <surname>Qin</surname>
          </string-name>
          , T. Liu,
          <string-name>
            <given-names>D.</given-names>
            <surname>Jiang</surname>
          </string-name>
          , et al.,
          <article-title>Codebert: A pre-trained model for programming and natural languages</article-title>
          , arXiv preprint arXiv:
          <year>2002</year>
          .
          <volume>08155</volume>
          (
          <year>2020</year>
          ).
        </mixed-citation>
      </ref>
      <ref id="ref14">
        <mixed-citation>
          [14]
          <string-name>
            <given-names>U.</given-names>
            <surname>Alon</surname>
          </string-name>
          ,
          <string-name>
            <given-names>M.</given-names>
            <surname>Zilberstein</surname>
          </string-name>
          ,
          <string-name>
            <given-names>O.</given-names>
            <surname>Levy</surname>
          </string-name>
          ,
          <string-name>
            <surname>E. Yahav,</surname>
          </string-name>
          <article-title>code2vec: Learning distributed representations of code</article-title>
          ,
          <source>Proceedings of the ACM on Programming Languages</source>
          <volume>3</volume>
          (
          <year>2019</year>
          )
          <fpage>1</fpage>
          -
          <lpage>29</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref15">
        <mixed-citation>
          [15]
          <string-name>
            <given-names>U.</given-names>
            <surname>Alon</surname>
          </string-name>
          ,
          <string-name>
            <given-names>S.</given-names>
            <surname>Brody</surname>
          </string-name>
          ,
          <string-name>
            <given-names>O.</given-names>
            <surname>Levy</surname>
          </string-name>
          , E. Yahav, code2seq:
          <article-title>Generating sequences from structured representations of code</article-title>
          , arXiv preprint arXiv:
          <year>1808</year>
          .
          <volume>01400</volume>
          (
          <year>2018</year>
          ).
        </mixed-citation>
      </ref>
      <ref id="ref16">
        <mixed-citation>
          [16]
          <string-name>
            <given-names>V.</given-names>
            <surname>Kovalenko</surname>
          </string-name>
          , E. Bogomolov,
          <string-name>
            <given-names>T.</given-names>
            <surname>Bryksin</surname>
          </string-name>
          ,
          <string-name>
            <given-names>A.</given-names>
            <surname>Bacchelli</surname>
          </string-name>
          ,
          <article-title>Pathminer: a library for mining of path-based representations of code</article-title>
          ,
          <source>in: Proceedings of the 16th International Conference on Mining Software Repositories</source>
          , IEEE Press,
          <year>2019</year>
          , pp.
          <fpage>13</fpage>
          -
          <lpage>17</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref17">
        <mixed-citation>
          [17]
          <string-name>
            <given-names>G.</given-names>
            <surname>Frantzeskou</surname>
          </string-name>
          ,
          <string-name>
            <given-names>E.</given-names>
            <surname>Stamatatos</surname>
          </string-name>
          ,
          <string-name>
            <given-names>S.</given-names>
            <surname>Gritzalis</surname>
          </string-name>
          ,
          <string-name>
            <given-names>S.</given-names>
            <surname>Katsikas</surname>
          </string-name>
          ,
          <article-title>Efective identification of source code authors using byte-level information</article-title>
          ,
          <source>in: Proceedings of the 28th international conference on Software engineering</source>
          ,
          <year>2006</year>
          , pp.
          <fpage>893</fpage>
          -
          <lpage>896</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref18">
        <mixed-citation>
          [18]
          <string-name>
            <given-names>M. F.</given-names>
            <surname>Tennyson</surname>
          </string-name>
          ,
          <string-name>
            <given-names>F. J.</given-names>
            <surname>Mitropoulos</surname>
          </string-name>
          ,
          <article-title>Choosing a profile length in the scap method of source code authorship attribution</article-title>
          ,
          <source>in: IEEE SOUTHEASTCON</source>
          <year>2014</year>
          , IEEE,
          <year>2014</year>
          , pp.
          <fpage>1</fpage>
          -
          <lpage>6</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref19">
        <mixed-citation>
          [19]
          <string-name>
            <given-names>W.</given-names>
            <surname>Wisse</surname>
          </string-name>
          ,
          <string-name>
            <given-names>C.</given-names>
            <surname>Veenman</surname>
          </string-name>
          ,
          <article-title>Scripting dna: Identifying the javascript programmer</article-title>
          , Digital
        </mixed-citation>
      </ref>
    </ref-list>
  </back>
</article>