<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
  xmlns:atom="http://www.w3.org/2005/Atom"
  xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Shaokang&#39;s Blog</title>
    <link>https://shaokang.me/</link>
    
    <atom:link href="https://shaokang.me/rss2.xml" rel="self" type="application/rss+xml"/>
    
    <description></description>
    <pubDate>Thu, 28 Dec 2023 01:16:59 GMT</pubDate>
    <generator>http://hexo.io/</generator>
    
    <item>
      <title>Fighting loneliness using generative AI with avatar</title>
      <link>https://shaokang.me/2023/Fighting-loneliness-using-generative-AI-with-avatar/</link>
      <guid>https://shaokang.me/2023/Fighting-loneliness-using-generative-AI-with-avatar/</guid>
      <pubDate>Sat, 23 Dec 2023 09:38:49 GMT</pubDate>
      
      <description>&lt;p&gt;Note: This is a group project, and I am only responsible for a portion of the work. Citations have been removed to adjust for website rendering. The original PDF is at the end of this page.&lt;/p&gt;&lt;p&gt;ChatGPT’s potential for human-like communication is noteworthy, but the mental health implications of integrating a real human identity remain understudied. This research focuses on introducing an AvatarGPT, a human-like avatar, to the ChatGPT interface to delve into these effects. A between-subject study (N=10) was conducted to investigate users’ responses, evaluate, and compare the effectiveness of AvatarGPT and ChatGPT before and after a conversation using the UCLA Loneliness Scale. Results show that neither using an avatar (p≈0.39) nor conversing without the avatar (p≈0.11) significantly improved loneliness scores. Additionally, using the avatar did not enhance willingness to speak, as measured by increased word counts, or significantly reducing loneliness score in percentage (p≈0.59). We believe that with a larger participant pool and a longer experimental period, we would be able to observe a more significant increase in emotional change.&lt;/p&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p>Note: This is a group project, and I am only responsible for a portion of the work. Citations have been removed to adjust for website rendering. The original PDF is at the end of this page.</p><p>ChatGPT’s potential for human-like communication is noteworthy, but the mental health implications of integrating a real human identity remain understudied. This research focuses on introducing an AvatarGPT, a human-like avatar, to the ChatGPT interface to delve into these effects. A between-subject study (N=10) was conducted to investigate users’ responses, evaluate, and compare the effectiveness of AvatarGPT and ChatGPT before and after a conversation using the UCLA Loneliness Scale. Results show that neither using an avatar (p≈0.39) nor conversing without the avatar (p≈0.11) significantly improved loneliness scores. Additionally, using the avatar did not enhance willingness to speak, as measured by increased word counts, or significantly reducing loneliness score in percentage (p≈0.59). We believe that with a larger participant pool and a longer experimental period, we would be able to observe a more significant increase in emotional change.<a id="more"></a></p><h2 id="introduction"><a class="markdownIt-Anchor" href="#introduction"></a> Introduction</h2><p>In recent years, exciting technological advances and research in robotics have led to a wide range of applications in many areas. One kind of robotics called Socially Assistive Robots(SAR) is widely used in health care and emotional support areas for it has the ability to provide emotional, cognitive and social support. These robots have been used to combat cognitive decline and depression through various methods such as making jokes and dancing. However, they provide emotional support only through basic reflective listening techniques and simple interactions, such as repeating or paraphrasing people’s words and their conversation patterns could use a lot of improvement.</p><p>Meanwhile, advancements in natural language processing and AI have given rise to innovative tools that offer a new dimension of human-computer interaction. ChatGPT, a language model developed by OpenAI, possesses the ability to understand and generate natural language, enabling smooth conversational interactions with users. Its natural language processing capabilities present immense potential for applications in emotional support and mental health.</p><p>Integrating an avatar interface with ChatGPT is primarily motivated by the limitations of text-only input in traditional chatbot interactions. By incorporating an avatar-based interactive interface, it is possible to enhance user engagement and enrich the overall experience. This approach is expected to foster greater initiative in user interactions with the chatbot, making the exchanges more intuitive and personable and improving user interaction and satisfaction.</p><p>The integration of LLMs like ChatGPT represents a further leap in mental health care. LLMs offer more natural, deeper conversational interactions, crucial for personalized emotional support and therapy. Incorporating LLMs into SAR with virtual avatars enriches the user experience, providing a sense of real social interaction and deeper emotional resonance and opening new possibilities for personalized and emotional support.</p><p>Thus, we implemented a new chat interface called AvatarGPT, ChatGPT with a vivid avatar interface to ’speak out’ the texts answered by ChatGPT, to provide mental health care. We then conducted a between-subject experiment with 10 participants in which some participants were using AvatarGPT (the treatment group) and some were given a basic ChatGPT (the control group). We formulated our research question as follows: Will the presence of a human-like avatar in the interface of ChatGPT increase the feeling of human connection during a conversation and, consequently, help reduce the symptoms of depression, especially loneliness?</p><p>To address this research question, we considered the following hypotheses:</p><p>H1:</p><p>Conversing with ChatGPT with an avatar would reduce user loneliness</p><p>H2:</p><p>Use avatar would increase speaking willingness</p><p>H3:</p><p>Conversations with more words would indicate greater reduced loneliness</p><h3 id="contribution"><a class="markdownIt-Anchor" href="#contribution"></a> Contribution</h3><p>Surprisingly, we found that neither ChatGPT nor AvatarGPT significantly contributes to people’s mental health in terms of reducing loneliness. In addition, we didn’t observe an increased level of willingness to speak or a more significant reduction in loneliness percentage across the two conditions.</p><h2 id="related-work"><a class="markdownIt-Anchor" href="#related-work"></a> Related work</h2><p>In the field of mental health care, the application of Socially Assistive Robots (SAR) is increasingly being emphasized, especially with the development of AI. Mental health issues pose a significant burden on individuals and society. In the US, about 25% of the population meets the criteria for a diagnosable psychiatric condition each year. Against this backdrop, SAR demonstrates tremendous potential. These robots have already assumed various roles in mental healthcare, including companions, coaches, and play partners.</p><p>For example, a robot called Paro has been used as a companion providing emotional support and reducing loneliness, akin to trained therapy animals. Also, simple robots with basic conversational abilities have proven beneficial for otherwise healthy older adults facing social isolation and loneliness.</p><p>AI now also become a valuable tool in this field, aiding professionals and enhancing patient care. Some AI systems, like Horyzons, provide accessible social therapy for youths with psychosis, allowing them to share and express emotions in a safe, moderated online environment. This platform reduces the intimidation associated with traditional group therapy by facilitating anonymous interaction. Also, Online Mental Health Communities use AI-mediated communication to better form relationships and communicate between people.</p><h2 id="method"><a class="markdownIt-Anchor" href="#method"></a> Method</h2><p>We conducted a between-subjects experiment to investigate the influence of interactions with ChatGPT and AvatarGPT on participants’ self-reported loneliness levels. Participants, recruited from a campus setting, were randomly assigned to one of two groups. Each group engaged in interactive tasks with either ChatGPT or AvatarGPT(modified to include a speaking humanoid avatar integrated into the ChatGPT interface). The experiment included a pre-survey to establish baseline loneliness, 2 interactive tasks for each group, and a post-survey for reassessment. Our study aims to find out how these interactions impact participants’ emotional states and feelings of loneliness.</p><h4 id="pre-survey-establish-baseline-level-of-loneliness"><a class="markdownIt-Anchor" href="#pre-survey-establish-baseline-level-of-loneliness"></a> Pre-Survey: Establish Baseline Level of Loneliness</h4><p>Prior to the start of the experiment, participants were asked to complete the modifed UCLA Loneliness Scale survey independently, without any integration with ChatGPT. By comparing the pre-survey responses with subsequent post-survey responses, we can effectively measure any changes in participants’ feelings of loneliness resulting from their interactions with AvatarGPT.</p><h4 id="task-1-question-answering-task"><a class="markdownIt-Anchor" href="#task-1-question-answering-task"></a> Task 1: Question-Answering Task</h4><p>Participants in this task will engage in a conversation with either ChatGPT or AvatarGPT, during which they will respond to questions related to their personal life, hobbies, or daily challenges. The primary goal is to encourage participants to share their feelings and thoughts openly, as well as to prompt them to pose additional questions. To initiate the task, ChatGPT or AvatarGPT is given the following prompt: “I need you to act like the interviewer, so speak like a human. I need you to ask me questions about life, hobbies, or daily challenges. Engage in a conversation with me. I need you to talk to me and encourage me to share my feelings and pose additional questions. Ask specific questions. Start off the conversation with ’Thank you for coming!’”</p><p>The participants are instructed to chat for a duration of 5 minutes. Importantly, during this time, the experimenter should not intervene. After the 5-minute conversation, the task will conclude, and participants will proceed to Task 2.</p><h4 id="task-2-scenario-generation-task"><a class="markdownIt-Anchor" href="#task-2-scenario-generation-task"></a> Task 2: Scenario Generation Task</h4><p>In this task, participants will engage in collaborative storytelling with either ChatGPT or AvatarGPT, focusing on themes of friendship and support. The objective is to jointly create a story plot that embodies these themes, while also integrating personal experiences and emotional elements to add authenticity and depth to the narrative. Participants are encouraged to work together to construct a story that flows seamlessly and feels interconnected. To initiate the task, participants are instructed as follows: “The goal of this task is to collaboratively create a story plot that revolves around themes of friendship and support in the next 5 minutes. We encourage you to infuse your personal experiences and emotions into the narrative to make it authentic and meaningful. Remember, this is a collaborative effort. Feel free to build on each other’s ideas, creating a narrative that flows seamlessly. Collaboration is key to making our story rich and interconnected. Let’s start with a simple prompt to kick things off. Imagine a setting or a situation where the characters need friendship and support. It could be anything – a challenging moment, a celebration, or even a quiet, reflective scene. Build upon this prompt in your contributions.” After the 5-minute storytelling session concludes, the conversation will stop, and participants will proceed to the post-survey.</p><h4 id="post-survey-reassessment-of-participant-responses"><a class="markdownIt-Anchor" href="#post-survey-reassessment-of-participant-responses"></a> Post-Survey: Reassessment of Participant Responses</h4><p>Following completion of the experimental tasks, participants will be asked to take the same survey that they completed as the pre-survey. The purpose of this post-survey is to assess whether there have been any changes in participant responses or perceptions after engaging in the interactive tasks with ChatGPT or AvatarGPT. By comparing pre-survey and post-survey responses, we aim to examine the potential impact of these interactions on participants’ feelings, experiences, and attitudes. This comparison will enable us to gain insights into the effectiveness of the interactions and their potential influence on various aspects of participants’ well-being and emotional state.</p><h4 id="participants-and-recruitment"><a class="markdownIt-Anchor" href="#participants-and-recruitment"></a> Participants and recruitment</h4><p>We recruit 10 people via interactions with students on campus. All of them self-identified as 1) at least 18 years old.</p><h2 id="experiment-description"><a class="markdownIt-Anchor" href="#experiment-description"></a> Experiment description</h2><p>In our experiment, we introduced the AvatarGPT by adding an avatar to the right bottom corner of the website ChatGPT interface in the browser window, as shown in <a href="#img:runsample">1</a>. The modified interface will be represented to participants in Task 1 and Task 2.</p><p>Specifically, we employed a JavaScript program through Tampermonkey to integrate a humanoid face into the corner of the ChatGPT interface. This humanoid face was designed to simulate speaking by moving its mouth synchronously with the textual responses generated by ChatGPT. The primary objective was to create an association in the user’s mind, where they would attribute the words produced by ChatGPT as being spoken by the avatar.</p><img src="/2023/Fighting-loneliness-using-generative-AI-with-avatar/avatar.png"><p><em>A sample running environment for AvatarGPT</em></p><h3 id="data-collection"><a class="markdownIt-Anchor" href="#data-collection"></a> Data collection</h3><p>In our study, we used a slightly modified UCLA Loneliness Scale to measure participants’ loneliness levels [<a href="http://bit.ly/cse216survey1" target="_blank" rel="noopener">bit.ly/cse216survey1</a>]. The UCLA Loneliness scale is a well-established questionnaire for assessing loneliness that employs a frequency-based response format. However, we adapted it by retaining the same questions but using an agreeance-based response scale. Participants were required to indicated their agreement levels with 20 negatively phrased statements. This allowed us to gauge participants’ current loneliness within the context of our short-term experiment. Lower scores indicate a more optimistic emotional state, while higher scores reflect a more pessimistic one.</p><p>In more detail regarding the evaluation and calculation of scores, the participant’s responses are scored on a scale from 1 to 5 for each question. A score of 1 represents “Strongly Disagree,” indicating that the participant completely disagrees with the negative statement, suggesting a more optimistic emotional state. Conversely, a score of 5 represents “Strongly Agree,” indicating a high level of agreement with the negative statement, which may suggest a more pessimistic emotional state. Once we finish converting all answers from categories to scores, we simply use the average overall responses as the final representation of one’s loneliness scale.</p><h2 id="result"><a class="markdownIt-Anchor" href="#result"></a> Result</h2><p>10 people are randomly assigned to two groups, either AvatarGPT group or ChatGPT group. Among 10 participants, 6 (2 Male, 3 Female, 1 prefer not to say) were assigned to ChatGPT group. The age is between 19-25 (M=21.3, Median=21). 4 participants (2 Male, 1 Female, 1 prefer not to say) were assigned to AvatarGPT group. The age is in between 21-24 (M=21.7, Median=21.5).</p><p>We collected the score based on 3.2 and analyzed the effect of interactions on participant loneliness for each group by addressing each hypothesis one by one.</p><h3 id="h1-conversing-with-chatgpt-with-an-avatar-would-reduce-user-loneliness"><a class="markdownIt-Anchor" href="#h1-conversing-with-chatgpt-with-an-avatar-would-reduce-user-loneliness"></a> H1: Conversing with ChatGPT with an avatar would reduce user loneliness</h3><p>We calculated the score based on the method mentioned in 3.2, representing the final result as shown in 2 for both groups. We then conducted a Student paired t-test to assess the impact of the interactions for each condition. In ChtGPT group, where participants engaged with the original interface of ChatGPT, we did not observe a significant difference in scores before and after the chat (t≈2.2, p≈0.11). Similarly, in AvatarGPT group, where participants interacted with the avatar version of ChatGPT, we also did not find a significant difference in scores before and after the chat (t≈2.4, p≈0.39). Lower scores indicate lower levels of measured loneliness.</p><img src="/2023/Fighting-loneliness-using-generative-AI-with-avatar/H1.jpg"><p><em>A Student paired t-test shows neither ChtGPT nor AvatarGPT has a significant contribution to reducing an individual’s loneliness score.</em></p><h2 id="h2-use-avatar-would-increase-speaking-willingness"><a class="markdownIt-Anchor" href="#h2-use-avatar-would-increase-speaking-willingness"></a> H2: Use avatar would increase speaking willingness</h2><p>From the recorded conversations, we analyzed both the word counts from the subjects and those generated by ChatGPT or AvatarGPT. The result is shown in <a href="#img:H2">3</a> for each condition.</p><p>We conducted a Student paired t-test to analyze the relationship between total word counts and avatar usage. Our results indicated no significant difference between the usage of the avatar and participants’ willingness to type (t$\approx<span class="katex"><span class="katex-mathml"><math><semantics><mrow><mn>2</mn><mi mathvariant="normal">.</mi><mn>4</mn><mo separator="true">,</mo><mi>p</mi></mrow><annotation encoding="application/x-tex">2.4, p</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:.64444em"></span><span class="strut bottom" style="height:.8388800000000001em;vertical-align:-.19444em"></span><span class="base textstyle uncramped"><span class="mord mathrm">2</span><span class="mord mathrm">.</span><span class="mord mathrm">4</span><span class="mpunct">,</span><span class="mord mathit">p</span></span></span></span>\approx$0.83).</p><img src="/2023/Fighting-loneliness-using-generative-AI-with-avatar/H2.jpg"><p><em>A Student paired t-test shows using an avatar would not increase the willingness to speak significantly.</em></p><h2 id="h3-conversations-with-more-words-would-indicate-greater-reduced-loneliness"><a class="markdownIt-Anchor" href="#h3-conversations-with-more-words-would-indicate-greater-reduced-loneliness"></a> H3: Conversations with more words would indicate greater reduced loneliness</h2><p>To quantify the changes in feelings of loneliness, we assess these variations using the percentage change in scores from the Pre-Survey. This method involves comparing the scores of the same participant across two separate surveys and calculating the difference between these scores. Specifically, we record the scores of a participant from two different instances of the survey. Then, we calculate the difference between these two scores. This difference is then divided by the score from the Pre-Survey, resulting in a value that represents the change in feelings of loneliness. This value reflects the extent of change in loneliness between the two tests, essentially representing the proportion of the change in scores relative to the score of the first test. The result for each condition is shown in <a href="#img:H3">4</a>.</p><p>We conducted an ANOVA test to examine the relationship between word counts and the change in scores expressed as a percentage. Our analysis revealed no significant difference between these variables (F(1, 8) $\approx<span class="katex"><span class="katex-mathml"><math><semantics><mrow><mn>0</mn><mi mathvariant="normal">.</mi><mn>3</mn><mn>1</mn><mo separator="true">,</mo><mi>p</mi></mrow><annotation encoding="application/x-tex">0.31, p</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:.64444em"></span><span class="strut bottom" style="height:.8388800000000001em;vertical-align:-.19444em"></span><span class="base textstyle uncramped"><span class="mord mathrm">0</span><span class="mord mathrm">.</span><span class="mord mathrm">3</span><span class="mord mathrm">1</span><span class="mpunct">,</span><span class="mord mathit">p</span></span></span></span>\approx$0.59, $\eta^2\approx$0.04). It’s worth noting that a negative score indicates that participants reported heightened feelings of loneliness after the conversation.</p><img src="/2023/Fighting-loneliness-using-generative-AI-with-avatar/H3.jpg"><p><em>An ANOVA test shows using an avatar would not reduce loneliness in terms of the ratio of the score difference.</em></p><h2 id="limitation"><a class="markdownIt-Anchor" href="#limitation"></a> Limitation</h2><p>One notable limitation of our study is the lack of validation for the modified version of the UCLA Loneliness Scale employed in this research. While the UCLA Loneliness Scale is well-established measuring loneliness, our adaptation was designed to assess transient or short-term loneliness as a mood rather than a traditional emotional state. Given that there was no widely recognized scale available specifically tailored to the measurement of transient loneliness in the context of our study, this adaptation was a necessary step. However, this modification raises questions about the scale’s validity and whether it accurately captures the targeted construct. future research should consider conducting validation studies to assess the reliability of our adapted scale for measuring short-term loneliness.</p><p>Another limitation of our study is the specific avatar chosen for the interactions with participants. We selected an arbitrary humanoid woman avatar presented in black and white, which was aligned with the color scheme of ChatGPT. Individual perceptions of avatars can vary widely, and some participants reported the chosen avatar to be “scary” or “distracting”. A more systematic approach to avatar selection should be considered.</p><h2 id="future-work"><a class="markdownIt-Anchor" href="#future-work"></a> Future work</h2><p>Exploring the impact of personalized avatar designs and behaviors on user engagement is important as customization options for avatars could enhance interactions. Investigating the long-term effects of both ChatGPT and AvatarGPT on user well-being and attachment to avatars. Comparative studies with other mental health support tools can provide insights into AvatarGPT’s unique advantages and limitations in different contexts, contributing to more effective and responsible AI-driven mental health care systems.</p><h2 id="conclusion"><a class="markdownIt-Anchor" href="#conclusion"></a> Conclusion</h2><p>Even though both robotics and large language models are trying to simulate human behavior, our current research result reveals the distance between them and real humans. In this research, our results show that neither using an avatar nor conversing without the avatar significantly improved loneliness scores. Additionally, using the avatar did not enhance willingness to speak, or significantly reduce loneliness score in percentage. We believe that with a larger participant pool and a longer experimental period, we would be able to observe a more significant increase in emotional change.</p><p>The original PDF file</p><div class="row"><embed src="sample-manuscript.pdf" width="100%" height="550" type="application/pdf"></div>]]></content:encoded>
      
      
      <category domain="https://shaokang.me/categories/research/">research</category>
      
      
      <category domain="https://shaokang.me/tags/research/">research</category>
      
      
      <comments>https://shaokang.me/2023/Fighting-loneliness-using-generative-AI-with-avatar/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Simple interative Haskell game</title>
      <link>https://shaokang.me/2023/Simple-interative-Haskell-game/</link>
      <guid>https://shaokang.me/2023/Simple-interative-Haskell-game/</guid>
      <pubDate>Fri, 15 Dec 2023 09:39:45 GMT</pubDate>
      
      <description>&lt;p&gt;Note: This is a group project for CSE 230, principles of functional programming language. I am responsible for coding the GUI and handling the interaction between the front-end and back-end using the brick library based on the Haskell programming language. Runnable project can be seen at: &lt;a href=&quot;https://github.com/t3chou/haskell-game-of-life&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;t3chou/haskell-game-of-life (github.com)&lt;/a&gt;&lt;/p&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p>Note: This is a group project for CSE 230, principles of functional programming language. I am responsible for coding the GUI and handling the interaction between the front-end and back-end using the brick library based on the Haskell programming language. Runnable project can be seen at: <a href="https://github.com/t3chou/haskell-game-of-life" target="_blank" rel="noopener">t3chou/haskell-game-of-life (github.com)</a><a id="more"></a></p><p>In this project, we</p><ul><li>Designed the core logic in pure functional language</li><li>Wrote the GUI in pure functional language</li><li>Designed a user-friendly interface</li><li>Did property tests to catch logical errors</li></ul><h2 id="overview"><a class="markdownIt-Anchor" href="#overview"></a> Overview</h2><p>This project implements Conway’s Game of Life by using Haskell, which is great for modeling complex mathematical concepts with the design of Haskell. The Game of Life, a zero-player game, evolves from an initial state, showing emergent behavior based on some rules and status (Birth, Survival, and Death). Haskell’s strong typing and pure functionality align perfectly with this game.</p><h2 id="game-description"><a class="markdownIt-Anchor" href="#game-description"></a> Game Description</h2><p>The Game of Life occurs on an infinite grid of cells. The status of each cell will be changed based on neighboring cells following those rules:</p><ul><li><strong>Birth</strong>: A dead cell with three live neighbors becomes alive.</li><li><strong>Survival</strong>: A live cell with two or three live neighbors stays alive.</li><li><strong>Death</strong>:<ul><li><strong>Overpopulation</strong>: A live cell with over three live neighbors dies.</li><li><strong>Loneliness</strong>: A live cell with under two live neighbors dies.</li></ul></li></ul><h2 id="implementation"><a class="markdownIt-Anchor" href="#implementation"></a> implementation</h2><p>Haskell’s fits for expressing the game’s rules. Key aspects of our implementation include:</p><ol><li><strong>Functional Grid Representation</strong>: Using list comprehensions and higher-order functions for the grid.</li><li><strong>State Transformation</strong>: Pure functions for state transitions between generations.</li><li><strong>Interaction Functionality</strong>: Implementing pause/continue in the game, boosting the interaction between users and the game with the help of the brick library.</li><li><strong>Unit Testing</strong>: Using QuickCheck to test each functionality, and game logic.</li><li><strong>Managing Dependencies</strong>: Making use of tools like Cabal or Stack to manage dependencies.</li></ol><h2 id="project-goals"><a class="markdownIt-Anchor" href="#project-goals"></a> Project Goals</h2><ol><li><strong>Mathematical Fidelity</strong>: Ensure full implementation of the game following Conway’s rules.</li><li><strong>User Interactions</strong>: Interacting with a user-friendly interface by key presses for pausing/continuing the game or quitting using the brick library.</li><li><strong>Using existing libraries of the hackage ecosystem</strong>: Utilizing existing libraries like containers and vector.</li></ol><p>This project aims to create a Conway’s Game of Life simulation in Haskell, as well as representing a string connection between a mathematical model and functional programming.</p><h2 id="source-acknowledgment"><a class="markdownIt-Anchor" href="#source-acknowledgment"></a> Source acknowledgment</h2><ol><li>As required by the course website, we are using the Brick library to implement the GUI interface. We did look at the official guidelines from <a href="https://github.com/jtdaugherty/brick" target="_blank" rel="noopener">https://github.com/jtdaugherty/brick</a> to implement any components relevant to GUI because the Brick library has never been taught in class.</li><li>We use <a href="https://hoogle.haskell.org/" target="_blank" rel="noopener">Haskell’s Hoodle</a> to explore and employ functions for implementing our project because not all Haskell components were covered during class.</li><li>We use <a href="https://hackage.haskell.org/package/QuickCheck" target="_blank" rel="noopener">QuickCheck</a> library to accomplish the unit testing requirments as required by the course website.</li></ol><h2 id="code"><a class="markdownIt-Anchor" href="#code"></a> Code</h2><p>The following shows codes for the front-end interface based on the brick library. In more detail, the GUI contains clickable buttons, a user-friendly setting interface, and a playable game with everything being programmed using state in Haskell:</p><figure class="highlight haskell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br></pre></td><td class="code"><pre><span class="line"><span class="title">clickable</span><span class="meta">&#123;-# LANGUAGE CPP #-&#125;</span></span><br><span class="line"><span class="meta">&#123;-# LANGUAGE OverloadedStrings #-&#125;</span></span><br><span class="line"><span class="meta">&#123;-# LANGUAGE TemplateHaskell #-&#125;</span></span><br><span class="line"><span class="keyword">module</span> Main (<span class="title">main</span>) <span class="keyword">where</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="keyword">qualified</span> Life       <span class="keyword">as</span> L</span><br><span class="line"><span class="keyword">import</span> <span class="keyword">qualified</span> PresetGrid <span class="keyword">as</span> P</span><br><span class="line"><span class="keyword">import</span> Control.Concurrent (<span class="title">threadDelay</span>)</span><br><span class="line"><span class="keyword">import</span> <span class="keyword">qualified</span> Data.Text <span class="keyword">as</span> T</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> Lens.Micro ((^.), (%~), set)</span><br><span class="line"><span class="keyword">import</span> Lens.Micro.TH (<span class="title">makeLenses</span>)</span><br><span class="line"><span class="keyword">import</span> Lens.Micro.Mtl (<span class="title">use</span>, (.=), (%=))</span><br><span class="line"><span class="keyword">import</span> Control.Monad (<span class="title">void</span>)</span><br><span class="line"><span class="keyword">import</span> Control.Monad.Trans (<span class="title">liftIO</span>)</span><br><span class="line"><span class="meta">#if !(MIN_VERSION_base(4,11,0))</span></span><br><span class="line"><span class="keyword">import</span> Data.Monoid ((&lt;&gt;))</span><br><span class="line"><span class="meta">#endif</span></span><br><span class="line"><span class="keyword">import</span> <span class="keyword">qualified</span> Graphics.Vty <span class="keyword">as</span> V</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="keyword">qualified</span> Brick.Types <span class="keyword">as</span> T</span><br><span class="line"><span class="keyword">import</span> Brick.AttrMap</span><br><span class="line"><span class="keyword">import</span> Brick.Util</span><br><span class="line"><span class="keyword">import</span> Brick.Types (<span class="type">Widget</span>, <span class="type">ViewportType(Vertical)</span>, <span class="type">EventM</span></span><br><span class="line">  , <span class="type">BrickEvent(..)</span> </span><br><span class="line">  )</span><br><span class="line"><span class="keyword">import</span> <span class="keyword">qualified</span> Brick.Widgets.Center <span class="keyword">as</span> C</span><br><span class="line"><span class="keyword">import</span> <span class="keyword">qualified</span> Brick.Widgets.Border <span class="keyword">as</span> B</span><br><span class="line"><span class="keyword">import</span> <span class="keyword">qualified</span> Brick.Widgets.Border.Style <span class="keyword">as</span> BS</span><br><span class="line"><span class="keyword">import</span> Brick.Main</span><br><span class="line">  ( <span class="type">App</span>(..), neverShowCursor, defaultMain</span><br><span class="line">  , suspendAndResume, halt, getVtyHandle, showFirstCursor, vScrollBy, viewportScroll</span><br><span class="line">  )</span><br><span class="line"><span class="keyword">import</span> Brick.Widgets.Core</span><br><span class="line"><span class="keyword">import</span> <span class="keyword">qualified</span> Data.Array <span class="keyword">as</span> A</span><br><span class="line"><span class="keyword">import</span> Life (<span class="type">GridState(..)</span>)</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">data</span> <span class="type">Name</span> = <span class="type">Block</span> | <span class="type">Beehive</span> | <span class="type">Loaf</span> | <span class="type">Boat</span> | <span class="type">Tub</span> | <span class="type">Blinker</span> | <span class="type">Toad</span> | <span class="type">Beacon</span> | <span class="type">Reset</span> | <span class="type">Next</span> | <span class="type">Quit</span> | <span class="type">Cell</span> &#123; <span class="title">_idx</span> :: <span class="type">L</span>.<span class="type">GridIndex</span> , <span class="title">_cst</span> :: <span class="type">L</span>.<span class="type">CellState</span>&#125;</span></span><br><span class="line">          <span class="keyword">deriving</span> (<span class="type">Show</span>, <span class="type">Ord</span>, <span class="type">Eq</span>)</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">data</span> <span class="type">St</span> =</span></span><br><span class="line">    <span class="type">St</span> &#123; _clicked :: [<span class="type">T</span>.<span class="type">Extent</span> <span class="type">Name</span>]</span><br><span class="line">       , _lastReportedClick :: <span class="type">Maybe</span> (<span class="type">Name</span>, <span class="type">T</span>.<span class="type">Location</span>)</span><br><span class="line">       , _state :: <span class="type">L</span>.<span class="type">GridState</span></span><br><span class="line">       , _step :: <span class="type">Int</span> </span><br><span class="line">       , _msg :: <span class="type">String</span></span><br><span class="line">       &#125;</span><br><span class="line"></span><br><span class="line"><span class="title">makeLenses</span> ''<span class="type">St</span></span><br><span class="line"></span><br><span class="line"><span class="title">drawUi</span> :: <span class="type">St</span> -&gt; [<span class="type">Widget</span> <span class="type">Name</span>]</span><br><span class="line"><span class="title">drawUi</span> st =</span><br><span class="line">  [vBox [ </span><br><span class="line">          <span class="type">B</span>.hBorderWithLabel (str <span class="string">"haskell game of life"</span>)</span><br><span class="line">         , vBox [ buttonLayer st</span><br><span class="line">             &lt;+&gt; <span class="type">B</span>.vBorder</span><br><span class="line">             &lt;+&gt; <span class="type">C</span>.vCenter (padAll <span class="number">3</span> $ hLimit <span class="number">10</span> $ vBox [ strWrap (<span class="string">"Click to modify state\n\nCurrent:"</span>) , padTop (<span class="type">Pad</span> <span class="number">1</span>) (gridLayer st <span class="type">L</span>.gridRows <span class="type">L</span>.gridCols)])</span><br><span class="line">                  , str <span class="string">"(Press Esc to quit or n for the next state)"</span> ]]]</span><br><span class="line"></span><br><span class="line"><span class="title">gridLayer</span> :: <span class="type">St</span> -&gt; <span class="type">Int</span> -&gt; <span class="type">Int</span> -&gt; <span class="type">Widget</span> <span class="type">Name</span></span><br><span class="line"><span class="title">gridLayer</span> st rs cs = vBox (map (\r -&gt; hBox (map (\c -&gt; mc (r, c) (_state st)) [<span class="number">0.</span>.cs<span class="number">-1</span>])) [<span class="number">0.</span>.rs<span class="number">-1</span>])</span><br><span class="line">    <span class="keyword">where</span></span><br><span class="line">        mkCell cell = </span><br><span class="line">            clickable cell $</span><br><span class="line">            <span class="comment">--    padTopBottom 1 $</span></span><br><span class="line">            <span class="comment">--    padLeftRight (if wasClicked then 2 else 3) $</span></span><br><span class="line">            str (<span class="keyword">if</span> _cst cell == <span class="type">L</span>.<span class="type">Alive</span> <span class="keyword">then</span> <span class="string">"o"</span> <span class="keyword">else</span> <span class="string">"."</span>)</span><br><span class="line">        mc idx (<span class="type">GridState</span> g)  = mkCell (<span class="type">Cell</span> idx (g <span class="type">A</span>.! idx)) <span class="comment">--str (case g A.! idx of</span></span><br><span class="line">            <span class="comment">--L.Alive -&gt; "o"</span></span><br><span class="line">            <span class="comment">--L.Dead  -&gt; ".") </span></span><br><span class="line">        <span class="comment">-- cellChar L.Alive = "o"</span></span><br><span class="line">        <span class="comment">-- cellChar L.Dead  = "."</span></span><br><span class="line"></span><br><span class="line"><span class="title">buttonLayer</span> :: <span class="type">St</span> -&gt; <span class="type">Widget</span> <span class="type">Name</span></span><br><span class="line"><span class="title">buttonLayer</span> st =</span><br><span class="line">    vBox [(padLeft (<span class="type">Pad</span> <span class="number">1</span>) $ str (<span class="string">"Current steps:"</span> &lt;&gt; show (_step st))) , <span class="type">B</span>.hBorder,</span><br><span class="line">    (padLeft (<span class="type">Pad</span> <span class="number">1</span>) $  str <span class="string">"Select profile (always live):"</span>) </span><br><span class="line">    ,(hBox $ padAll <span class="number">1</span> &lt;$&gt; buttons), </span><br><span class="line">    vBox [ (padLeft (<span class="type">Pad</span> <span class="number">1</span>) $  str <span class="string">"Select profile (oscillators):"</span>) </span><br><span class="line">    ,(hBox $ padAll <span class="number">1</span> &lt;$&gt; buttons1), (padLeft (<span class="type">Pad</span> <span class="number">1</span>) $  str <span class="string">"Controls:"</span>) </span><br><span class="line">    ,(hBox $ padAll <span class="number">1</span> &lt;$&gt; buttons2)]]</span><br><span class="line">    <span class="keyword">where</span></span><br><span class="line">        buttons = mkButton &lt;$&gt; buttonData</span><br><span class="line">        buttonData = [ (<span class="type">Block</span>, <span class="string">"Block"</span>, attrName <span class="string">"Block"</span>)</span><br><span class="line">                     , (<span class="type">Beehive</span>, <span class="string">"Beehive"</span>, attrName <span class="string">"Beehive"</span>)</span><br><span class="line">                     , (<span class="type">Loaf</span>, <span class="string">"Loaf"</span>, attrName <span class="string">"Loaf"</span>)</span><br><span class="line">                     , (<span class="type">Boat</span>, <span class="string">"Boat"</span>, attrName <span class="string">"Boat"</span>)</span><br><span class="line">                     , (<span class="type">Tub</span>, <span class="string">"Tub"</span>, attrName <span class="string">"Tub"</span>)</span><br><span class="line">                     ]</span><br><span class="line">        buttons1 = mkButton &lt;$&gt; buttonData1</span><br><span class="line">        buttonData1 = [ (<span class="type">Blinker</span>, <span class="string">"Blinker"</span>, attrName <span class="string">"Blinker"</span>)</span><br><span class="line">                     , (<span class="type">Toad</span>, <span class="string">"Toad"</span>, attrName <span class="string">"Toad"</span>)</span><br><span class="line">                     , (<span class="type">Beacon</span>, <span class="string">"Beacon"</span>, attrName <span class="string">"Beacon"</span>)</span><br><span class="line">                     ]</span><br><span class="line">        buttons2 = mkButton &lt;$&gt; buttonData2</span><br><span class="line">        buttonData2 = [ (<span class="type">Reset</span>, <span class="string">"Reset"</span>, attrName <span class="string">"Reset"</span>)</span><br><span class="line">                     , (<span class="type">Next</span>, <span class="string">"Next"</span>, attrName <span class="string">"Next"</span>)</span><br><span class="line">                     , (<span class="type">Quit</span>, <span class="string">"Quit"</span>, attrName <span class="string">"Quit"</span>)</span><br><span class="line">                     ]</span><br><span class="line">        mkButton (name, label, attr) =</span><br><span class="line">            <span class="keyword">let</span> wasClicked = (fst &lt;$&gt; st^.lastReportedClick) == <span class="type">Just</span> name</span><br><span class="line">            <span class="keyword">in</span> clickable name $</span><br><span class="line">               withDefAttr attr $</span><br><span class="line">               <span class="type">B</span>.border $</span><br><span class="line">            <span class="comment">--    padTopBottom 1 $</span></span><br><span class="line">               padLeftRight (<span class="keyword">if</span> wasClicked <span class="keyword">then</span> <span class="number">2</span> <span class="keyword">else</span> <span class="number">3</span>) $</span><br><span class="line">               str (<span class="keyword">if</span> wasClicked <span class="keyword">then</span> <span class="string">"&lt;"</span> &lt;&gt; label &lt;&gt; <span class="string">"&gt;"</span> <span class="keyword">else</span> label)</span><br><span class="line"></span><br><span class="line"><span class="title">appEvent</span> :: <span class="type">T</span>.<span class="type">BrickEvent</span> <span class="type">Name</span> e -&gt; <span class="type">T</span>.<span class="type">EventM</span> <span class="type">Name</span> <span class="type">St</span> ()</span><br><span class="line"><span class="title">appEvent</span> ev@(<span class="type">T</span>.<span class="type">MouseDown</span> n _ _ loc) = <span class="keyword">do</span></span><br><span class="line">        lastReportedClick .= <span class="type">Just</span> (n, loc)</span><br><span class="line">        <span class="keyword">case</span> n <span class="keyword">of</span></span><br><span class="line">            <span class="type">Block</span> -&gt; <span class="keyword">do</span> </span><br><span class="line">                state .= (<span class="type">P</span>.strToGrid <span class="type">P</span>.block)</span><br><span class="line">                step .= <span class="number">0</span></span><br><span class="line">            <span class="type">Beehive</span> -&gt; <span class="keyword">do</span> </span><br><span class="line">                state .= (<span class="type">P</span>.strToGrid <span class="type">P</span>.beehive)</span><br><span class="line">                step .= <span class="number">0</span></span><br><span class="line">            <span class="type">Loaf</span> -&gt; <span class="keyword">do</span> </span><br><span class="line">                state .= (<span class="type">P</span>.strToGrid <span class="type">P</span>.loaf)</span><br><span class="line">                step .= <span class="number">0</span></span><br><span class="line">            <span class="type">Boat</span> -&gt; <span class="keyword">do</span> </span><br><span class="line">                state .= (<span class="type">P</span>.strToGrid <span class="type">P</span>.boat)</span><br><span class="line">                step .= <span class="number">0</span></span><br><span class="line">            <span class="type">Tub</span> -&gt; <span class="keyword">do</span> </span><br><span class="line">                state .= (<span class="type">P</span>.strToGrid <span class="type">P</span>.tub)</span><br><span class="line">                step .= <span class="number">0</span></span><br><span class="line">            <span class="type">Blinker</span> -&gt; <span class="keyword">do</span> </span><br><span class="line">                state .= (<span class="type">P</span>.strToGrid <span class="type">P</span>.blinker)</span><br><span class="line">                step .= <span class="number">0</span></span><br><span class="line">            <span class="type">Toad</span> -&gt; <span class="keyword">do</span> </span><br><span class="line">                state .= (<span class="type">P</span>.strToGrid <span class="type">P</span>.toad)</span><br><span class="line">                step .= <span class="number">0</span></span><br><span class="line">            <span class="type">Beacon</span> -&gt; <span class="keyword">do</span> </span><br><span class="line">                state .= (<span class="type">P</span>.strToGrid <span class="type">P</span>.beacon)</span><br><span class="line">                step .= <span class="number">0</span></span><br><span class="line">            <span class="type">Reset</span> -&gt; <span class="keyword">do</span> </span><br><span class="line">                state .= <span class="type">P</span>.deadGrid</span><br><span class="line">                step .= <span class="number">0</span></span><br><span class="line">            <span class="type">Next</span> -&gt; <span class="keyword">do</span> </span><br><span class="line">                state %= <span class="type">L</span>.evolution</span><br><span class="line">                step %= (+ <span class="number">1</span>)</span><br><span class="line">            <span class="type">Quit</span> -&gt; <span class="keyword">do</span> </span><br><span class="line">                halt</span><br><span class="line">            <span class="type">Cell</span> idx cst -&gt; state %= (\s -&gt; <span class="type">L</span>.toggleState s idx)</span><br><span class="line">            </span><br><span class="line">            </span><br><span class="line"><span class="title">appEvent</span> (<span class="type">T</span>.<span class="type">VtyEvent</span> (<span class="type">V</span>.<span class="type">EvKey</span> (<span class="type">V</span>.<span class="type">KChar</span> 'n') [])) = <span class="keyword">do</span></span><br><span class="line">    state %= <span class="type">L</span>.evolution</span><br><span class="line">    step %= (+ <span class="number">1</span>)</span><br><span class="line"><span class="title">appEvent</span> (<span class="type">T</span>.<span class="type">MouseUp</span> &#123;&#125;) =</span><br><span class="line">    lastReportedClick .= <span class="type">Nothing</span></span><br><span class="line"><span class="title">appEvent</span> (<span class="type">T</span>.<span class="type">VtyEvent</span> (<span class="type">V</span>.<span class="type">EvMouseUp</span> &#123;&#125;)) =</span><br><span class="line">    lastReportedClick .= <span class="type">Nothing</span></span><br><span class="line"><span class="title">appEvent</span> (<span class="type">T</span>.<span class="type">VtyEvent</span> (<span class="type">V</span>.<span class="type">EvKey</span> <span class="type">V</span>.<span class="type">KEsc</span> [])) =</span><br><span class="line">    halt</span><br><span class="line"><span class="title">appEvent</span> ev = </span><br><span class="line">    return ()</span><br><span class="line"></span><br><span class="line"><span class="title">aMap</span> :: <span class="type">AttrMap</span></span><br><span class="line"><span class="title">aMap</span> = attrMap <span class="type">V</span>.defAttr</span><br><span class="line">    [ (attrName <span class="string">"Block"</span>,   <span class="type">V</span>.white `on` <span class="type">V</span>.green)</span><br><span class="line">    , (attrName <span class="string">"Beehive"</span>,   <span class="type">V</span>.white `on` <span class="type">V</span>.green)</span><br><span class="line">    , (attrName <span class="string">"Loaf"</span>,   <span class="type">V</span>.white `on` <span class="type">V</span>.green)</span><br><span class="line">    , (attrName <span class="string">"Boat"</span>,   <span class="type">V</span>.white `on` <span class="type">V</span>.green)</span><br><span class="line">    , (attrName <span class="string">"Tub"</span>,   <span class="type">V</span>.white `on` <span class="type">V</span>.green)</span><br><span class="line">    , (attrName <span class="string">"Blinker"</span>,   <span class="type">V</span>.white `on` <span class="type">V</span>.blue)</span><br><span class="line">    , (attrName <span class="string">"Toad"</span>,   <span class="type">V</span>.white `on` <span class="type">V</span>.blue)</span><br><span class="line">    , (attrName <span class="string">"Beacon"</span>,   <span class="type">V</span>.white `on` <span class="type">V</span>.blue)</span><br><span class="line">    , (attrName <span class="string">"Reset"</span>,   <span class="type">V</span>.white `on` <span class="type">V</span>.cyan)</span><br><span class="line">    , (attrName <span class="string">"Next"</span>,   <span class="type">V</span>.white `on` <span class="type">V</span>.cyan)</span><br><span class="line">    , (attrName <span class="string">"Quit"</span>,   <span class="type">V</span>.white `on` <span class="type">V</span>.cyan)</span><br><span class="line">    ]</span><br><span class="line"></span><br><span class="line"><span class="title">app</span> :: <span class="type">App</span> <span class="type">St</span> e <span class="type">Name</span></span><br><span class="line"><span class="title">app</span> =</span><br><span class="line">    <span class="type">App</span> &#123; appDraw = drawUi</span><br><span class="line">          , appStartEvent = <span class="keyword">do</span></span><br><span class="line">              vty &lt;- getVtyHandle</span><br><span class="line">              liftIO $ <span class="type">V</span>.setMode (<span class="type">V</span>.outputIface vty) <span class="type">V</span>.<span class="type">Mouse</span> <span class="type">True</span></span><br><span class="line">          , appHandleEvent = appEvent</span><br><span class="line">          , appAttrMap = const aMap</span><br><span class="line">          , appChooseCursor = showFirstCursor</span><br><span class="line">          &#125;</span><br><span class="line"></span><br><span class="line"><span class="title">main</span> :: <span class="type">IO</span> ()</span><br><span class="line"><span class="title">main</span> = <span class="keyword">do</span></span><br><span class="line">    void $ defaultMain app $ <span class="type">St</span> [] <span class="type">Nothing</span> <span class="type">P</span>.deadGrid <span class="number">0</span> <span class="string">""</span></span><br></pre></td></tr></table></figure>]]></content:encoded>
      
      
      <category domain="https://shaokang.me/categories/Haskell/">Haskell</category>
      
      
      <category domain="https://shaokang.me/tags/Haskell/">Haskell</category>
      
      
      <comments>https://shaokang.me/2023/Simple-interative-Haskell-game/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Usability analysis of autocomplete</title>
      <link>https://shaokang.me/2023/Usability-analysis-of-autocomplete/</link>
      <guid>https://shaokang.me/2023/Usability-analysis-of-autocomplete/</guid>
      <pubDate>Sat, 23 Sep 2023 08:38:49 GMT</pubDate>
      
      <description>&lt;p&gt;The original paper is under review, citation format:&lt;/p&gt;&lt;p&gt;Shaokang Jiang and Michael Coblenz. An Analysis of the Costs and Benefits of Autocomplete in IDEs. In review, ACM International Symposium on Foundations of Software Engineering (FSE 2024)&lt;/p&gt;&lt;p&gt;Key points:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Worked with Michael Coblenz on the usability analysis of autocomplete.&lt;/li&gt;&lt;li&gt;Designed and executed an experiment with 32 participants using an eye tracker to evaluate the costs and benefits of IDE-based autocomplete features to programmers who use an unfamiliar API; analyzed data using JMP; and wrote a paper for the study.&lt;/li&gt;&lt;li&gt;Found that participants who used autocomplete learned more about the API while spending less time reading the documentation; found autocomplete did not significantly reduce the number of keystrokes required to finish tasks.&lt;/li&gt;&lt;/ul&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p>The original paper is under review, citation format:</p><p>Shaokang Jiang and Michael Coblenz. An Analysis of the Costs and Benefits of Autocomplete in IDEs. In review, ACM International Symposium on Foundations of Software Engineering (FSE 2024)</p><p>Key points:</p><ul><li>Worked with Michael Coblenz on the usability analysis of autocomplete.</li><li>Designed and executed an experiment with 32 participants using an eye tracker to evaluate the costs and benefits of IDE-based autocomplete features to programmers who use an unfamiliar API; analyzed data using JMP; and wrote a paper for the study.</li><li>Found that participants who used autocomplete learned more about the API while spending less time reading the documentation; found autocomplete did not significantly reduce the number of keystrokes required to finish tasks.<a id="more"></a></li><li>Acquired fundamental skills in conducting empirical research studies and learned various methods for handling and understanding the implications of eye-tracking data.</li><li>Successfully designed an experiment with well-formed hypotheses and a comprehensive knowledge test suite to accurately capture the benefits and costs of autocomplete. Additionally, designed procedures and produced scripts to analyze data from various sources, including a substantial amount of data from a consumer-level eye tracker.</li></ul><p>In more detail:</p><p>Upon starting my master’s program, I took a usability analysis of programming languages course. Realizing Python type hints could be useful in checking types, and providing more context to IDE for generating useful information, all these properties could be helpful for programmers to write better code. The reduced number of typing errors could potentially assist competitive programmers more by minimizing time spent on fixing typing errors. I investigated the impact of Python type hints feature on the performance of competitive programmers (N=5). Our findings revealed that Python type hints did not significantly enhance their task completion performance (𝑝 ≈ 0.51, 𝑑 ≈ 0.81). Survey results indicated that programmers tended to dislike type hints and autocomplete suggestions, citing them as annoying.</p><p>Together with my previous teaching experiences, where I observed programmers grappling with autocomplete suggestions and observed eyes and mouse drifting during active autocomplete use, I aimed to understand the genuine benefits and costs of autocomplete. Considering that autocomplete could potentially be harmful to learning due to the ease of access to knowledge, we conducted an experiment (N=28) to measure the learning impact of autocomplete when programmers face new materials and gauge the productivity effect during its usage. The results are expected to benefit all programmers using modern IDEs, with potential applicability to the general public relying on browser autocomplete.</p><p>During the experiment, I utilized an eye tracker to detect users’ gaze, aiming to understand the specific parts and autocomplete options that programmers focused on. I developed a novel monitoring platform based on VSCode, integrating eye-tracking at the source code level. Additionally, I designed a knowledge test suite to measure new knowledge acquisition after tasks and introduced a post-study survey for capturing individuals’ opinions.</p><p>I found the main benefit of autocomplete speeding up information acquisition by significantly reducing the time spent reading documentation (𝑝 &lt; 0.01, 𝑑 = 1.76). It also significantly increases the knowledge testing score (𝑝 &lt; 0.01, 𝑑 = 1.1). An insignificant result in the total number of keystrokes across experimental conditions (𝑝 ≈ 0.65, 𝑑 = 0.18) helps us assert that autocomplete does not reduce typing time, thus not making programmers more productive. From designing to executing this study, I learned a lot, including ways of determining the area of interest in eye-tracking studies, methods of designing participant-friendly tasks that align with the project’s goals, quantitative analysis techniques, and methods for hypothesis testing.</p><p>I faced numerous challenges during my research project. Integrating an eye-tracker allowed me to delve deeper into the usefulness of autocomplete and the involved cognitive processes, but it also presented challenges. Given the limitations of the previous monitoring platform, including a restricted area of interest, a less popular platform, high latency, and artificial coding restrictions, I developed a new monitoring platform based on the more popular VSCode, integrating eye-tracking at the source code level. I tested various eye trackers, wrote code to evaluate fixation algorithms, and consulted with I-trace experts for optimization insights.</p><p>Experiment design posed another significant challenge, requiring the creation of a robust, controllable, and effective experiment that could reveal the benefits or drawbacks of autocomplete. After proposing various experiment versions and conducting pilot experiments, I selected a design utilizing a task suite based on common-sense knowledge and a modern API library. This design included a knowledge test suite, an eye tracker, and a post-study survey. The successful execution of the entire experiment suggests that I effectively overcame these challenges, showcasing my ability to be both persistent and resourceful in graduate school.</p>]]></content:encoded>
      
      
      <category domain="https://shaokang.me/categories/research/">research</category>
      
      
      <category domain="https://shaokang.me/tags/research/">research</category>
      
      
      <comments>https://shaokang.me/2023/Usability-analysis-of-autocomplete/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Eye tracking fixation algorithm</title>
      <link>https://shaokang.me/2023/Eye-tracking-fixation-algorithm/</link>
      <guid>https://shaokang.me/2023/Eye-tracking-fixation-algorithm/</guid>
      <pubDate>Sun, 27 Aug 2023 22:51:05 GMT</pubDate>
      
      <description>&lt;p&gt;This page contains JavaScript implementations of some common algorithms for handling raw eye-tracking data, such as generating fixations and managing vertical drifting, which served for the tracking part of autocomplete research. For example, IDT, attach, K-cluster.js. It also includes some data visualization script we used in internal testing. All codescripts designed to be run under NodeJs.&lt;/p&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p>This page contains JavaScript implementations of some common algorithms for handling raw eye-tracking data, such as generating fixations and managing vertical drifting, which served for the tracking part of autocomplete research. For example, IDT, attach, K-cluster.js. It also includes some data visualization script we used in internal testing. All codescripts designed to be run under NodeJs.<a id="more"></a></p><h1 id="fixation"><a class="markdownIt-Anchor" href="#fixation"></a> Fixation</h1><h3 id="idt"><a class="markdownIt-Anchor" href="#idt"></a> IDT</h3><p>One of the most common algorithms for detecting fixations is the Identification by Dispersion-Threshold (IDT) algorithm. According to Salvucci and Goldberg (2000), it is based on the data reduction algorithm by Widdel (1984). The IDT algorithm works with x- and y data, and two fixed thresholds: the maximum fixation dispersion threshold and the minimum fixation duration threshold. To be a fixation, data samples constituting at least enough time to fulfill the duration threshold has to be within a spatial area not exceeding the dispersion threshold. The samples fulfilling these criteria are marked as belonging to a fixation. One particular detail of this specific implementation is that it is part of a package that also merges short nearby fixations, and also paired with a saccade detector (Komogortsev, Gobert, Jayarathna, Koh, &amp; Gowda, 2010).</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// possible time error of using this: 20ms</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="class"><span class="keyword">class</span> <span class="title">Point</span> </span>&#123;</span><br><span class="line">    curLine = <span class="number">-41</span>;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * </span></span><br><span class="line"><span class="comment">     * @param &#123;Number&#125; x </span></span><br><span class="line"><span class="comment">     * @param &#123;Number&#125; y </span></span><br><span class="line"><span class="comment">     * @param &#123;Number&#125; time </span></span><br><span class="line"><span class="comment">     * @param &#123;Number&#125; curBox y axis location of autocompletion box associate with this points</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">constructor</span>(x, y, time, curBox) &#123;</span><br><span class="line">        <span class="keyword">this</span>.x = x;</span><br><span class="line">        <span class="keyword">this</span>.y = y;</span><br><span class="line">        <span class="keyword">this</span>.time = time;</span><br><span class="line">        <span class="keyword">this</span>.curBox = curBox;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    toString() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">"("</span> + <span class="keyword">this</span>.x + <span class="string">","</span> + <span class="keyword">this</span>.y + <span class="string">","</span> + <span class="keyword">this</span>.time + <span class="string">","</span> + <span class="keyword">this</span>.curBox + <span class="string">")"</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="class"><span class="keyword">class</span> <span class="title">Fixation</span> </span>&#123;</span><br><span class="line">    points = [];</span><br><span class="line">    x = <span class="number">0</span>;</span><br><span class="line">    y = <span class="number">0</span>;</span><br><span class="line">    time = <span class="number">0</span>;</span><br><span class="line">    duration = <span class="number">0</span>;</span><br><span class="line">    line = <span class="number">-1</span>;</span><br><span class="line">    lineAns = <span class="number">-40</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">IDT</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>(duration, dispersion) &#123;</span><br><span class="line">        <span class="keyword">this</span>.duration = duration;</span><br><span class="line">        <span class="keyword">this</span>.dispersion = dispersion;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    maxBy = <span class="function">(<span class="params">comparator, array</span>) =&gt;</span></span><br><span class="line">        array.reduce(<span class="function">(<span class="params">acc, val</span>) =&gt;</span> comparator(acc, val) &gt; <span class="number">0</span> ? acc : val);</span><br><span class="line">    minBy = <span class="function">(<span class="params">comparator, array</span>) =&gt;</span></span><br><span class="line">        array.reduce(<span class="function">(<span class="params">acc, val</span>) =&gt;</span> comparator(acc, val) &lt; <span class="number">0</span> ? acc : val);</span><br><span class="line"></span><br><span class="line">    compareX = <span class="function">(<span class="params">a, b</span>) =&gt;</span> a.x - b.x;</span><br><span class="line">    compareY = <span class="function">(<span class="params">a, b</span>) =&gt;</span> a.y - b.y;</span><br><span class="line"></span><br><span class="line">    computeGazeDifference(points) &#123;</span><br><span class="line">        <span class="keyword">if</span> (points.length == <span class="number">0</span>) <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">let</span> xmax = <span class="keyword">this</span>.maxBy(<span class="keyword">this</span>.compareX, points).x;</span><br><span class="line">        <span class="keyword">let</span> xmin = <span class="keyword">this</span>.minBy(<span class="keyword">this</span>.compareX, points).x;</span><br><span class="line">        <span class="keyword">let</span> ymax = <span class="keyword">this</span>.maxBy(<span class="keyword">this</span>.compareY, points).y;</span><br><span class="line">        <span class="keyword">let</span> ymin = <span class="keyword">this</span>.minBy(<span class="keyword">this</span>.compareY, points).y;</span><br><span class="line">        <span class="comment">// console.log(xmax, xmin, ymax, ymin);</span></span><br><span class="line">        <span class="keyword">return</span> ((xmax - xmin) + (ymax - ymin));</span><br><span class="line">    &#125;<span class="comment">// Not a real dispersion: why not using square root: Pythagorean theorem a^2 + b^2 = c^2 to measure the difference: Most of available code online is using this</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// guessing original step 1 is check whether the point is valid</span></span><br><span class="line"></span><br><span class="line">    calculateTime(points) &#123;</span><br><span class="line">        <span class="keyword">return</span> points[points.length - <span class="number">1</span>].time - points[<span class="number">0</span>].time;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    generateFixation(points) &#123;</span><br><span class="line">        <span class="keyword">let</span> fixation = [];<span class="comment">// array of Fixation</span></span><br><span class="line">        <span class="keyword">let</span> <span class="built_in">window</span> = [];<span class="comment">//array of points for each run</span></span><br><span class="line">        <span class="keyword">let</span> i = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">let</span> tmpDuration = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">while</span> (tmpDuration &lt; <span class="keyword">this</span>.duration &amp;&amp; i &lt; points.length) &#123;</span><br><span class="line">            <span class="built_in">window</span>.push(points[i]);</span><br><span class="line">            tmpDuration += points[i].time;</span><br><span class="line">            i++;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">while</span> (i &lt; points.length) &#123;</span><br><span class="line">            <span class="keyword">if</span> ((<span class="keyword">this</span>.computeGazeDifference(<span class="built_in">window</span>) &lt;= <span class="keyword">this</span>.dispersion) &amp;&amp; (<span class="keyword">this</span>.calculateTime(<span class="built_in">window</span>) &gt;= <span class="keyword">this</span>.duration)) &#123;</span><br><span class="line">                <span class="keyword">while</span> (<span class="keyword">this</span>.computeGazeDifference(<span class="built_in">window</span>) &lt;= <span class="keyword">this</span>.dispersion) &#123;</span><br><span class="line">                    <span class="keyword">if</span> (i &lt; points.length - <span class="number">1</span>) &#123;</span><br><span class="line">                        <span class="built_in">window</span>.push(points[i]);</span><br><span class="line">                        ++i;</span><br><span class="line">                    &#125;</span><br><span class="line">                    <span class="keyword">else</span> &#123; <span class="keyword">break</span>; &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                fixation.push(<span class="keyword">this</span>.computeEstimate(<span class="built_in">window</span>));</span><br><span class="line">                <span class="built_in">window</span> = [];</span><br><span class="line">                <span class="built_in">window</span>.push(points[i]);</span><br><span class="line">                i++;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="keyword">this</span>.calculateTime(<span class="built_in">window</span>) &lt; <span class="keyword">this</span>.duration) &#123;</span><br><span class="line">                <span class="built_in">window</span>.push(points[i]);</span><br><span class="line">                i++;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="built_in">window</span>.shift();</span><br><span class="line">                <span class="keyword">if</span> (<span class="keyword">this</span>.calculateTime(<span class="built_in">window</span>) &lt; <span class="keyword">this</span>.duration) &#123;</span><br><span class="line">                    <span class="built_in">window</span>.push(points[i]);</span><br><span class="line">                    i++;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> fixation;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    computeEstimate(points) &#123;</span><br><span class="line">        <span class="keyword">let</span> fixation = <span class="keyword">new</span> Fixation();</span><br><span class="line">        <span class="keyword">let</span> x = <span class="number">0</span>, y = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> points) &#123;</span><br><span class="line">            x += i.x;</span><br><span class="line">            y += i.y;</span><br><span class="line">            fixation.points.push(i);</span><br><span class="line">        &#125;</span><br><span class="line">        fixation.x = (x / fixation.points.length);</span><br><span class="line">        fixation.y = (y / fixation.points.length);</span><br><span class="line">        fixation.time = fixation.points[<span class="number">0</span>].time;</span><br><span class="line">        fixation.duration = <span class="keyword">this</span>.calculateTime(fixation.points);</span><br><span class="line">        <span class="keyword">if</span> (fixation.points[<span class="number">0</span>].curLine != <span class="number">-41</span>) &#123;</span><br><span class="line">            <span class="keyword">let</span> occurrences = fixation.points.reduce(<span class="function"><span class="keyword">function</span> (<span class="params">acc, curr</span>) </span>&#123;</span><br><span class="line">                <span class="keyword">return</span> acc[curr.curLine] ? ++acc[curr.curLine] : acc[curr.curLine] = <span class="number">1</span>, acc</span><br><span class="line">            &#125;, &#123;&#125;);</span><br><span class="line">            fixation.lineAns = <span class="built_in">Object</span>.keys(occurrences).reduce(<span class="function">(<span class="params">a, b</span>) =&gt;</span> occurrences[a] &gt; occurrences[b] ? a : b);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> fixation;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    getSetting() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>.duration + <span class="string">","</span> + <span class="keyword">this</span>.dispersion;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * @param &#123;Point[]&#125; data </span></span><br><span class="line"><span class="comment"> * @param &#123;Number&#125; dur </span></span><br><span class="line"><span class="comment"> * @param &#123;Number&#125; dis </span></span><br><span class="line"><span class="comment"> * @returns &#123;Fixation[]&#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">generateIDT</span>(<span class="params">data, dur, dis</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> fix = <span class="keyword">new</span> IDT(dur, dis);</span><br><span class="line">    <span class="keyword">return</span> fix.generateFixation(data);<span class="comment">// fixation in type Fixation</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="vertical-drift"><a class="markdownIt-Anchor" href="#vertical-drift"></a> Vertical drift</h1><h3 id="k-clusterjs"><a class="markdownIt-Anchor" href="#k-clusterjs"></a> K-cluster.js</h3><p>This is a script to handle vertical drift by categorize all points to K-clusters.</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; Point &#125; <span class="keyword">from</span> <span class="string">'./IDT.js'</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// Should be used to guess lines instead of generating fixation pattern</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> kMeans = <span class="function">(<span class="params">data, k = <span class="number">1</span></span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> centroids = data.slice(<span class="number">0</span>, k);</span><br><span class="line">    <span class="keyword">const</span> distances = <span class="built_in">Array</span>.from(&#123; <span class="attr">length</span>: data.length &#125;, () =&gt;</span><br><span class="line">        <span class="built_in">Array</span>.from(&#123; <span class="attr">length</span>: k &#125;, () =&gt; <span class="number">0</span>)</span><br><span class="line">    );</span><br><span class="line">    <span class="keyword">const</span> classes = <span class="built_in">Array</span>.from(&#123; <span class="attr">length</span>: data.length &#125;, () =&gt; <span class="number">-1</span>);</span><br><span class="line">    <span class="keyword">let</span> itr = <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> (itr) &#123;</span><br><span class="line">        itr = <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">let</span> d <span class="keyword">in</span> data) &#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">let</span> c = <span class="number">0</span>; c &lt; k; c++) &#123;</span><br><span class="line">                distances[d][c] = <span class="built_in">Math</span>.hypot(</span><br><span class="line">                    ...Object.keys(data[<span class="number">0</span>]).map(<span class="function"><span class="params">key</span> =&gt;</span> data[d][key] - centroids[c][key])</span><br><span class="line">                );</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">const</span> m = distances[d].indexOf(<span class="built_in">Math</span>.min(...distances[d]));</span><br><span class="line">            <span class="keyword">if</span> (classes[d] !== m) itr = <span class="literal">true</span>;</span><br><span class="line">            classes[d] = m;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">let</span> c = <span class="number">0</span>; c &lt; k; c++) &#123;</span><br><span class="line">            centroids[c] = <span class="built_in">Array</span>.from(&#123; <span class="attr">length</span>: data[<span class="number">0</span>].length &#125;, () =&gt; <span class="number">0</span>);</span><br><span class="line">            <span class="keyword">const</span> size = data.reduce(<span class="function">(<span class="params">acc, _, d</span>) =&gt;</span> &#123;</span><br><span class="line">                <span class="keyword">if</span> (classes[d] === c) &#123;</span><br><span class="line">                    acc++;</span><br><span class="line">                    <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">in</span> data[<span class="number">0</span>]) centroids[c][i] += data[d][i];</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">return</span> acc;</span><br><span class="line">            &#125;, <span class="number">0</span>);</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">in</span> data[<span class="number">0</span>]) &#123;</span><br><span class="line">                centroids[c][i] = <span class="built_in">parseFloat</span>(<span class="built_in">Number</span>(centroids[c][i] / size).toFixed(<span class="number">2</span>));</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">console</span>.log(data)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> classes;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(kMeans([[<span class="number">0</span>, <span class="number">0</span>], [<span class="number">0</span>, <span class="number">1</span>], [<span class="number">1</span>, <span class="number">3</span>], [<span class="number">2</span>, <span class="number">0</span>]], <span class="number">4</span>))</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">KCluster</span>(<span class="params">points, screenSizeVec, autocompleteLoc</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// <span class="doctag">TODO:</span> not necessary now</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="attachjs"><a class="markdownIt-Anchor" href="#attachjs"></a> attach.js</h3><p>This is the baseline algorithm for fixing the vertical drift for eye-tracker. Previous research use this as a baseline while also have a good performance.</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; Point, Fixation &#125; <span class="keyword">from</span> <span class="string">'./IDT.js'</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * @param &#123;Fixation[]&#125; fixations </span></span><br><span class="line"><span class="comment"> * @returns </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">attachFixation</span>(<span class="params">fixations</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// set lines, actually, only fix negative offset and outofrange offset </span></span><br><span class="line">    <span class="comment">// 303px with 30px per line, so 10 lines in total</span></span><br><span class="line">    <span class="comment">// 0-1 stands for the first line.</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> fixations) &#123;</span><br><span class="line">        <span class="keyword">if</span> (i.y &lt; <span class="number">1</span>) &#123;</span><br><span class="line">            i.line = <span class="number">1</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (i.y &gt;= <span class="number">9</span>) &#123;</span><br><span class="line">            i.line = <span class="number">10</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            i.line = (i.y | <span class="number">0</span>) + <span class="number">1</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> fixations;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="internal-test-script"><a class="markdownIt-Anchor" href="#internal-test-script"></a> Internal test script</h1><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> * <span class="keyword">as</span> IDT <span class="keyword">from</span> <span class="string">'./IDT.js'</span>;</span><br><span class="line"><span class="keyword">import</span> * <span class="keyword">as</span> IDTM <span class="keyword">from</span> <span class="string">'./IDT-proposed.js'</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; attachFixation &#125; <span class="keyword">from</span> <span class="string">'./attach.js'</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; generatePattern, fixit &#125; <span class="keyword">from</span> <span class="string">'./autoFix.js'</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; convertFile &#125; <span class="keyword">from</span> <span class="string">'./readData.js'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> screenY = <span class="number">864</span>;</span><br><span class="line"><span class="keyword">let</span> dataFile = <span class="string">"./testData.txt"</span></span><br><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">simpleAttach</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> sourceSession = <span class="keyword">await</span> convertFile(dataFile);</span><br><span class="line">    <span class="keyword">let</span> source = [];<span class="comment">// array of result fixations </span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> j <span class="keyword">of</span> <span class="built_in">Object</span>.keys(sourceSession)) &#123;</span><br><span class="line">        <span class="keyword">if</span> (j.localeCompare(<span class="string">"screenY"</span>) != <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">let</span> k <span class="keyword">of</span> <span class="built_in">Object</span>.keys(sourceSession[j])) &#123;</span><br><span class="line">                <span class="keyword">let</span> tmpPoints = [];</span><br><span class="line">                <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> sourceSession[j][k]) &#123; <span class="comment">// in format: x,y,time,curBoxloc,curLine : For fixation, curline is determined by majority point</span></span><br><span class="line">                    <span class="keyword">let</span> newP = <span class="keyword">new</span> IDT.Point(i[<span class="number">0</span>], i[<span class="number">1</span>] * <span class="number">30</span>, i[<span class="number">2</span>], i[<span class="number">3</span>]);</span><br><span class="line">                    newP.curLine = i[<span class="number">4</span>]; <span class="comment">// line number start from 1</span></span><br><span class="line">                    tmpPoints.push(newP);</span><br><span class="line">                &#125;</span><br><span class="line">                source = source.concat(tmpPoints);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">let</span> newSource = [];</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> source) &#123;</span><br><span class="line">        i.y = i.y / <span class="number">30</span>;<span class="comment">// divide by 30 to return to previous format</span></span><br><span class="line">        <span class="keyword">if</span> (i.y &gt; <span class="number">-400</span>) newSource.push(i);</span><br><span class="line">    &#125;</span><br><span class="line">    source = newSource;</span><br><span class="line">    source = attachFixation(source);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> tempResult = &#123; <span class="string">"correct"</span>: <span class="number">0</span>, <span class="string">"incorrect"</span>: <span class="number">0</span> &#125;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> source) &#123;</span><br><span class="line">        <span class="keyword">if</span> (i.line == i.curLine) &#123;</span><br><span class="line">            tempResult[<span class="string">"correct"</span>]++;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            tempResult[<span class="string">"incorrect"</span>]++;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">"result:"</span> + tempResult[<span class="string">"correct"</span>] + <span class="string">" "</span> + tempResult[<span class="string">"incorrect"</span>]);</span><br><span class="line">    <span class="built_in">console</span>.log(tempResult[<span class="string">"correct"</span>] / (tempResult[<span class="string">"correct"</span>] + tempResult[<span class="string">"incorrect"</span>]))</span><br><span class="line">    <span class="keyword">return</span> tempResult[<span class="string">"correct"</span>] / (tempResult[<span class="string">"correct"</span>] + tempResult[<span class="string">"incorrect"</span>])</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">IDT_perline_Attach</span>(<span class="params">dur, dis</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// Need to get the best fixation working pair</span></span><br><span class="line">    <span class="comment">// fixation should be done on each session of data, categorize by autocompletion box position</span></span><br><span class="line">    <span class="keyword">let</span> sourceSession = <span class="keyword">await</span> convertFile(dataFile);</span><br><span class="line">    <span class="comment">// in format &#123;"boxY":&#123;"line":[data]&#125;, "screenY": 864&#125;</span></span><br><span class="line">    screenY = <span class="built_in">parseInt</span>(sourceSession[<span class="string">"screenY"</span>])</span><br><span class="line">    <span class="keyword">let</span> source = [];<span class="comment">// array of result fixations </span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> j <span class="keyword">of</span> <span class="built_in">Object</span>.keys(sourceSession)) &#123;</span><br><span class="line">        <span class="keyword">if</span> (j.localeCompare(<span class="string">"screenY"</span>) != <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">let</span> k <span class="keyword">of</span> <span class="built_in">Object</span>.keys(sourceSession[j])) &#123;</span><br><span class="line">                <span class="keyword">let</span> tmpPoints = [];</span><br><span class="line">                <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> sourceSession[j][k]) &#123; <span class="comment">// in format: x,y,time,curBoxloc,curLine : For fixation, curline is determined by majority point</span></span><br><span class="line">                    <span class="keyword">let</span> newP = <span class="keyword">new</span> IDT.Point(i[<span class="number">0</span>], i[<span class="number">1</span>] * <span class="number">30</span>, i[<span class="number">2</span>], i[<span class="number">3</span>]);</span><br><span class="line">                    newP.curLine = i[<span class="number">4</span>]; </span><br><span class="line">                    tmpPoints.push(newP);</span><br><span class="line">                &#125;</span><br><span class="line">                source = source.concat(IDT.generateIDT(tmpPoints, dur, dis));</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">let</span> newSource = [];</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> source) &#123;</span><br><span class="line">        i.y = i.y / <span class="number">30</span>;<span class="comment">// divide by 30 to return to previous format</span></span><br><span class="line">        <span class="keyword">if</span> (i.y &gt; <span class="number">-400</span>) newSource.push(i);</span><br><span class="line">    &#125;</span><br><span class="line">    source = newSource;</span><br><span class="line">    <span class="comment">// let pattern = generatePattern(source, screenY);</span></span><br><span class="line">    <span class="comment">// source = fixit(source, pattern, screenY);</span></span><br><span class="line">    source = attachFixation(source);</span><br><span class="line">    <span class="keyword">let</span> tempResult = &#123; <span class="string">"correct"</span>: <span class="number">0</span>, <span class="string">"incorrect"</span>: <span class="number">0</span> &#125;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> source) &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">let</span> j <span class="keyword">of</span> i.points) &#123;</span><br><span class="line">            <span class="keyword">if</span> (i.line == j.curLine) &#123;</span><br><span class="line">                tempResult[<span class="string">"correct"</span>]++;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                tempResult[<span class="string">"incorrect"</span>]++;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">"dur:"</span> + dur + <span class="string">"dis:"</span> + dis + <span class="string">"result:"</span> + tempResult[<span class="string">"correct"</span>] / (tempResult[<span class="string">"correct"</span>] + tempResult[<span class="string">"incorrect"</span>]));</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">"Points: "</span> + source.reduce(<span class="function">(<span class="params">a, b</span>) =&gt;</span> a += b.points.length, <span class="number">0</span>))</span><br><span class="line">    <span class="comment">// return source.reduce((a, b) =&gt; a += b.points.length, 0);</span></span><br><span class="line">    <span class="keyword">return</span> [tempResult[<span class="string">"correct"</span>] / <span class="function">(<span class="params">tempResult[<span class="string">"correct"</span>] + tempResult[<span class="string">"incorrect"</span>]</span>), <span class="params">source</span>.<span class="params">reduce</span>(<span class="params">(a, b</span>) =&gt;</span> a += b.points.length, <span class="number">0</span>)];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">IDT_persession_Attach</span>(<span class="params">dur, dis</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> sourceSession = <span class="keyword">await</span> convertFile(dataFile);</span><br><span class="line">    <span class="comment">// in format &#123;"boxY":&#123;"line":[data]&#125;, "screenY": 864&#125;</span></span><br><span class="line">    screenY = <span class="built_in">parseInt</span>(sourceSession[<span class="string">"screenY"</span>])</span><br><span class="line">    <span class="keyword">let</span> source = [];<span class="comment">// array of result fixations </span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> j <span class="keyword">of</span> <span class="built_in">Object</span>.keys(sourceSession)) &#123;</span><br><span class="line">        <span class="keyword">if</span> (j.localeCompare(<span class="string">"screenY"</span>) != <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">let</span> tmpPoints = [];</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">let</span> k <span class="keyword">of</span> <span class="built_in">Object</span>.keys(sourceSession[j])) &#123;</span><br><span class="line">                <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> sourceSession[j][k]) &#123; <span class="comment">// in format: x,y,time,curBoxloc,curLine : For fixation, curline is determined by majority point</span></span><br><span class="line">                    <span class="keyword">let</span> newP = <span class="keyword">new</span> IDT.Point(i[<span class="number">0</span>], i[<span class="number">1</span>] * <span class="number">30</span>, i[<span class="number">2</span>], i[<span class="number">3</span>]);</span><br><span class="line">                    newP.curLine = i[<span class="number">4</span>]; <span class="comment">// line number start from 1</span></span><br><span class="line">                    tmpPoints.push(newP);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            source = source.concat(IDT.generateIDT(tmpPoints, dur, dis));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">let</span> newSource = [];</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> source) &#123;</span><br><span class="line">        i.y = i.y / <span class="number">30</span>;<span class="comment">// divide by 30 to return to previous format</span></span><br><span class="line">        <span class="keyword">if</span> (i.y &gt; <span class="number">-400</span>) newSource.push(i);</span><br><span class="line">    &#125;</span><br><span class="line">    source = newSource;</span><br><span class="line">    <span class="comment">// let pattern = generatePattern(source, screenY);</span></span><br><span class="line">    <span class="comment">// source = fixit(source, pattern, screenY);</span></span><br><span class="line">    source = attachFixation(source);</span><br><span class="line">    <span class="keyword">let</span> tempResult = &#123; <span class="string">"correct"</span>: <span class="number">0</span>, <span class="string">"incorrect"</span>: <span class="number">0</span> &#125;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> source) &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">let</span> j <span class="keyword">of</span> i.points) &#123;</span><br><span class="line">            <span class="keyword">if</span> (i.line == j.curLine) &#123;</span><br><span class="line">                tempResult[<span class="string">"correct"</span>]++;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                tempResult[<span class="string">"incorrect"</span>]++;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">"dur:"</span> + dur + <span class="string">"dis:"</span> + dis + <span class="string">"result:"</span> + tempResult[<span class="string">"correct"</span>] / (tempResult[<span class="string">"correct"</span>] + tempResult[<span class="string">"incorrect"</span>]));</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">"Points: "</span> + source.reduce(<span class="function">(<span class="params">a, b</span>) =&gt;</span> a += b.points.length, <span class="number">0</span>))</span><br><span class="line">    <span class="comment">// return source.reduce((a, b) =&gt; a += b.points.length, 0);</span></span><br><span class="line">    <span class="keyword">return</span> [tempResult[<span class="string">"correct"</span>] / <span class="function">(<span class="params">tempResult[<span class="string">"correct"</span>] + tempResult[<span class="string">"incorrect"</span>]</span>), <span class="params">source</span>.<span class="params">reduce</span>(<span class="params">(a, b</span>) =&gt;</span> a += b.points.length, <span class="number">0</span>)];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">IDTM_perline_Attach</span>(<span class="params">dur, dis</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> sourceSession = <span class="keyword">await</span> convertFile(dataFile);</span><br><span class="line">    <span class="comment">// in format &#123;"boxY":&#123;"line":[data]&#125;, "screenY": 864&#125;</span></span><br><span class="line">    screenY = <span class="built_in">parseInt</span>(sourceSession[<span class="string">"screenY"</span>])</span><br><span class="line">    <span class="keyword">let</span> source = [];<span class="comment">// array of result fixations </span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> j <span class="keyword">of</span> <span class="built_in">Object</span>.keys(sourceSession)) &#123;</span><br><span class="line">        <span class="keyword">if</span> (j.localeCompare(<span class="string">"screenY"</span>) != <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">let</span> k <span class="keyword">of</span> <span class="built_in">Object</span>.keys(sourceSession[j])) &#123;</span><br><span class="line">                <span class="keyword">let</span> tmpPoints = [];</span><br><span class="line">                <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> sourceSession[j][k]) &#123; <span class="comment">// in format: x,y,time,curBoxloc,curLine : For fixation, curline is determined by majority point</span></span><br><span class="line">                    <span class="keyword">let</span> newP = <span class="keyword">new</span> IDT.Point(i[<span class="number">0</span>], i[<span class="number">1</span>] * <span class="number">30</span>, i[<span class="number">2</span>], i[<span class="number">3</span>]);</span><br><span class="line">                    newP.curLine = i[<span class="number">4</span>]; <span class="comment">// line number start from 1</span></span><br><span class="line">                    tmpPoints.push(newP);</span><br><span class="line">                &#125;</span><br><span class="line">                source = source.concat(IDTM.generateIDTM(tmpPoints, dur, dis));</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">let</span> newSource = [];</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> source) &#123;</span><br><span class="line">        i.y = i.y / <span class="number">30</span>;<span class="comment">// divide by 30 to return to previous format</span></span><br><span class="line">        <span class="keyword">if</span> (i.y &gt; <span class="number">-400</span>) newSource.push(i);</span><br><span class="line">    &#125;</span><br><span class="line">    source = newSource;</span><br><span class="line">    <span class="comment">// let pattern = generatePattern(source, screenY);</span></span><br><span class="line">    <span class="comment">// source = fixit(source, pattern, screenY);</span></span><br><span class="line">    source = attachFixation(source);</span><br><span class="line">    <span class="keyword">let</span> tempResult = &#123; <span class="string">"correct"</span>: <span class="number">0</span>, <span class="string">"incorrect"</span>: <span class="number">0</span> &#125;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> source) &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">let</span> j <span class="keyword">of</span> i.points) &#123;</span><br><span class="line">            <span class="keyword">if</span> (i.line == j.curLine) &#123;</span><br><span class="line">                tempResult[<span class="string">"correct"</span>]++;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                tempResult[<span class="string">"incorrect"</span>]++;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">"dur:"</span> + dur + <span class="string">"dis:"</span> + dis + <span class="string">"result:"</span> + tempResult[<span class="string">"correct"</span>] / (tempResult[<span class="string">"correct"</span>] + tempResult[<span class="string">"incorrect"</span>]));</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">"Points: "</span> + source.reduce(<span class="function">(<span class="params">a, b</span>) =&gt;</span> a += b.points.length, <span class="number">0</span>))</span><br><span class="line">    <span class="keyword">return</span> [tempResult[<span class="string">"correct"</span>] / <span class="function">(<span class="params">tempResult[<span class="string">"correct"</span>] + tempResult[<span class="string">"incorrect"</span>]</span>), <span class="params">source</span>.<span class="params">reduce</span>(<span class="params">(a, b</span>) =&gt;</span> a += b.points.length, <span class="number">0</span>)];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">IDTM_persession_Attach</span>(<span class="params">dur, dis</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> sourceSession = <span class="keyword">await</span> convertFile(dataFile);</span><br><span class="line">    screenY = <span class="built_in">parseInt</span>(sourceSession[<span class="string">"screenY"</span>])</span><br><span class="line">    <span class="keyword">let</span> source = [];<span class="comment">// array of result fixations </span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> j <span class="keyword">of</span> <span class="built_in">Object</span>.keys(sourceSession)) &#123;</span><br><span class="line">        <span class="keyword">if</span> (j.localeCompare(<span class="string">"screenY"</span>) != <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">let</span> tmpPoints = [];</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">let</span> k <span class="keyword">of</span> <span class="built_in">Object</span>.keys(sourceSession[j])) &#123;</span><br><span class="line">                <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> sourceSession[j][k]) &#123; <span class="comment">// in format: x,y,time,curBoxloc,curLine : For fixation, curline is determined by majority point</span></span><br><span class="line">                    <span class="keyword">let</span> newP = <span class="keyword">new</span> IDT.Point(i[<span class="number">0</span>], i[<span class="number">1</span>] * <span class="number">30</span>, i[<span class="number">2</span>], i[<span class="number">3</span>]);</span><br><span class="line">                    newP.curLine = i[<span class="number">4</span>]; <span class="comment">// line number start from 1</span></span><br><span class="line">                    tmpPoints.push(newP);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            source = source.concat(IDTM.generateIDTM(tmpPoints, dur, dis));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">let</span> newSource = [];</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> source) &#123;</span><br><span class="line">        i.y = i.y / <span class="number">30</span>;</span><br><span class="line">        <span class="keyword">if</span> (i.y &gt; <span class="number">-400</span>) newSource.push(i);</span><br><span class="line">    &#125;</span><br><span class="line">    source = newSource;</span><br><span class="line">    source = attachFixation(source);</span><br><span class="line">    <span class="keyword">let</span> tempResult = &#123; <span class="string">"correct"</span>: <span class="number">0</span>, <span class="string">"incorrect"</span>: <span class="number">0</span> &#125;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> source) &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">let</span> j <span class="keyword">of</span> i.points) &#123;</span><br><span class="line">            <span class="keyword">if</span> (i.line == j.curLine) &#123;</span><br><span class="line">                tempResult[<span class="string">"correct"</span>]++;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                tempResult[<span class="string">"incorrect"</span>]++;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">"dur:"</span> + dur + <span class="string">"dis:"</span> + dis + <span class="string">"result:"</span> + tempResult[<span class="string">"correct"</span>] / (tempResult[<span class="string">"correct"</span>] + tempResult[<span class="string">"incorrect"</span>]));</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">"Points: "</span> + source.reduce(<span class="function">(<span class="params">a, b</span>) =&gt;</span> a += b.points.length, <span class="number">0</span>))</span><br><span class="line">    <span class="comment">// return source.reduce((a, b) =&gt; a += b.points.length, 0);</span></span><br><span class="line">    <span class="keyword">return</span> [tempResult[<span class="string">"correct"</span>] / <span class="function">(<span class="params">tempResult[<span class="string">"correct"</span>] + tempResult[<span class="string">"incorrect"</span>]</span>), <span class="params">source</span>.<span class="params">reduce</span>(<span class="params">(a, b</span>) =&gt;</span> a += b.points.length, <span class="number">0</span>)];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">getBestFixation</span>(<span class="params">dur, dis</span>) </span>&#123;<span class="comment">// do pattern</span></span><br><span class="line">    <span class="keyword">let</span> sourceSession = <span class="keyword">await</span> convertFile(dataFile);</span><br><span class="line">    <span class="comment">// in format &#123;"boxY":&#123;"line":[data]&#125;, "screenY": 864&#125;</span></span><br><span class="line">    screenY = <span class="built_in">parseInt</span>(sourceSession[<span class="string">"screenY"</span>])</span><br><span class="line">    <span class="keyword">let</span> source = [];<span class="comment">// array of result fixations </span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> j <span class="keyword">of</span> <span class="built_in">Object</span>.keys(sourceSession)) &#123;</span><br><span class="line">        <span class="keyword">if</span> (j.localeCompare(<span class="string">"screenY"</span>) != <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">let</span> k <span class="keyword">of</span> <span class="built_in">Object</span>.keys(sourceSession[j])) &#123;</span><br><span class="line">                <span class="keyword">let</span> tmpPoints = [];</span><br><span class="line">                <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> sourceSession[j][k]) &#123; <span class="comment">// in format: x,y,time,curBoxloc,curLine : For fixation, curline is determined by majority point</span></span><br><span class="line">                    <span class="keyword">let</span> newP = <span class="keyword">new</span> IDT.Point(i[<span class="number">0</span>], i[<span class="number">1</span>] * <span class="number">30</span>, i[<span class="number">2</span>], i[<span class="number">3</span>]);</span><br><span class="line">                    newP.curLine = i[<span class="number">4</span>]; <span class="comment">// line number start from 1</span></span><br><span class="line">                    tmpPoints.push(newP);</span><br><span class="line">                &#125;</span><br><span class="line">                source = source.concat(IDT.generateIDT(tmpPoints, dur, dis));</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> newSource = [];</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> source) &#123;</span><br><span class="line">        i.y = i.y / <span class="number">30</span>;<span class="comment">// divide by 30 to return to previous format</span></span><br><span class="line">        <span class="keyword">if</span> (i.y &gt; <span class="number">-400</span>) newSource.push(i);</span><br><span class="line">    &#125;</span><br><span class="line">    source = newSource;</span><br><span class="line"></span><br><span class="line">    source = attachFixation(source);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> pattern = generatePattern(source, screenY);</span><br><span class="line">    source = fixit(source, pattern, screenY);</span><br><span class="line"></span><br><span class="line">    source = attachFixation(source);</span><br><span class="line">    <span class="keyword">let</span> tempResult = &#123; <span class="string">"correct"</span>: <span class="number">0</span>, <span class="string">"incorrect"</span>: <span class="number">0</span> &#125;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> source) &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">let</span> j <span class="keyword">of</span> i.points) &#123;</span><br><span class="line">            <span class="keyword">if</span> (i.line == j.curLine) &#123;</span><br><span class="line">                tempResult[<span class="string">"correct"</span>]++;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                tempResult[<span class="string">"incorrect"</span>]++;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">"dur:"</span> + dur + <span class="string">"dis:"</span> + dis + <span class="string">"result:"</span> + tempResult[<span class="string">"correct"</span>] / (tempResult[<span class="string">"correct"</span>] + tempResult[<span class="string">"incorrect"</span>]));</span><br><span class="line">    <span class="comment">// return source.reduce((a, b) =&gt; a += b.points.length, 0);</span></span><br><span class="line">    <span class="keyword">return</span> [tempResult[<span class="string">"correct"</span>] / <span class="function">(<span class="params">tempResult[<span class="string">"correct"</span>] + tempResult[<span class="string">"incorrect"</span>]</span>), <span class="params">source</span>.<span class="params">reduce</span>(<span class="params">(a, b</span>) =&gt;</span> a += b.points.length, <span class="number">0</span>)];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">report</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="comment">// duration starts from 2500 with 500 increment</span></span><br><span class="line">    <span class="keyword">let</span> bestPossible = [];</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> dur = <span class="number">500</span>; dur &lt; <span class="number">2000</span>; dur += <span class="number">50</span>) &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">let</span> dis = <span class="number">2</span>; dis &lt; <span class="number">80</span>; dis += <span class="number">2</span>) &#123;</span><br><span class="line">            <span class="keyword">let</span> resultRatio = <span class="keyword">await</span> IDT_perline_Attach(dur, dis);</span><br><span class="line">            bestPossible.push(&#123; <span class="string">"dur"</span>: dur, <span class="string">"dis"</span>: dis, <span class="string">"result"</span>: resultRatio[<span class="number">0</span>] * <span class="number">100</span>, <span class="string">"points"</span>: resultRatio[<span class="number">1</span>] &#125;)</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    bestPossible.sort(<span class="function">(<span class="params">a, b</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> b[<span class="string">"result"</span>] - a[<span class="string">"result"</span>];</span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="built_in">console</span>.log(bestPossible);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">IDTM_persession_Attach(<span class="number">550</span>, <span class="number">30</span>)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">calculateCorrect</span>(<span class="params">result</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> <span class="built_in">Object</span>.keys(result)) &#123;</span><br><span class="line">        result[i][<span class="string">"ratio"</span>] = <span class="built_in">parseFloat</span>(((result[i][<span class="string">"correct"</span>] / (result[i][<span class="string">"correct"</span>] + result[i][<span class="string">"incorrect"</span>])) * <span class="number">100</span>).toFixed(<span class="number">2</span>));</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>IDT visualization script contains some sensitive information. I can provide if requested.</p><h1 id="reference"><a class="markdownIt-Anchor" href="#reference"></a> Reference</h1><p>Andersson, Richard, et al. “One algorithm to rule them all? An evaluation and discussion of ten eye movement event-detection algorithms.” <em>Behavior research methods</em> 49 (2017): 616-637.</p><p>Kliegl, Reinhold, and Richard K. Olson. “Reduction and calibration of eye monitor data.” <em>Behavior Research Methods &amp; Instrumentation</em> 13.2 (1981): 107-111.</p><p>Carr, Jon W., et al. “Algorithms for the automated correction of vertical drift in eye-tracking data.” <em>Behavior Research Methods</em> 54.1 (2022): 287-310.</p>]]></content:encoded>
      
      
      <category domain="https://shaokang.me/categories/website/">website</category>
      
      <category domain="https://shaokang.me/categories/website/JS/">JS</category>
      
      
      
      <comments>https://shaokang.me/2023/Eye-tracking-fixation-algorithm/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>JSP java emulator</title>
      <link>https://shaokang.me/2023/JSP-java-emulator/</link>
      <guid>https://shaokang.me/2023/JSP-java-emulator/</guid>
      <pubDate>Fri, 23 Jun 2023 08:37:11 GMT</pubDate>
      
      <description>&lt;p&gt;A simple JSP Java emulator was built to demonstrate the solution code behavior of the DSC 30 final project, where I served as a TA. The entire program was deployed to azure, containing code for handling different threads to run the solution code in the cloud instantly and render the running result on &lt;a href=&quot;https://myplayer.azurewebsites.net&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://myplayer.azurewebsites.net&lt;/a&gt;&lt;/p&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p>A simple JSP Java emulator was built to demonstrate the solution code behavior of the DSC 30 final project, where I served as a TA. The entire program was deployed to azure, containing code for handling different threads to run the solution code in the cloud instantly and render the running result on <a href="https://myplayer.azurewebsites.net" target="_blank" rel="noopener">https://myplayer.azurewebsites.net</a><a id="more"></a></p><p>The Servlet part of managing, rendering, and connecting applications and front-end:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> website;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.BufferedReader;</span><br><span class="line"><span class="keyword">import</span> java.io.File;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.InputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.InputStreamReader;</span><br><span class="line"><span class="keyword">import</span> java.io.OutputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.PrintWriter;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.LinkedList;</span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.servlet.ServletException;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.http.HttpServlet;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.http.HttpServletRequest;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.http.HttpServletResponse;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.http.HttpSession;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Servlet implementation class hello</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">hello</span> <span class="keyword">extends</span> <span class="title">HttpServlet</span> </span>&#123;</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">long</span> serialVersionUID = <span class="number">1L</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> HashMap&lt;String, Process&gt; runner = <span class="keyword">new</span> HashMap&lt;String, Process&gt;();</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> HashMap&lt;String, Long&gt; runtime = <span class="keyword">new</span> HashMap&lt;String, Long&gt;();</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@see</span> HttpServlet#HttpServlet()</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">hello</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="keyword">super</span>();</span><br><span class="line"><span class="comment">// TODO Auto-generated constructor stub</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@see</span> HttpServlet#doGet(HttpServletRequest request, HttpServletResponse</span></span><br><span class="line"><span class="comment"> *      response)</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">doGet</span><span class="params">(HttpServletRequest request, HttpServletResponse response)</span></span></span><br><span class="line"><span class="function"><span class="keyword">throws</span> ServletException, IOException </span>&#123;</span><br><span class="line"><span class="comment">// TODO Auto-generated method stub</span></span><br><span class="line">HttpSession session = request.getSession();</span><br><span class="line"><span class="keyword">try</span> &#123;</span><br><span class="line"><span class="keyword">if</span> (runner.containsKey(session.getId())) &#123;</span><br><span class="line"><span class="comment">// continue</span></span><br><span class="line">String code = request.getParameter(<span class="string">"code"</span>);</span><br><span class="line"><span class="keyword">if</span> (code.isEmpty()) &#123;</span><br><span class="line">response.setContentType(<span class="string">"application/json"</span>);</span><br><span class="line">PrintWriter out = response.getWriter();</span><br><span class="line">out.print(<span class="string">""</span>);</span><br><span class="line">out.flush();</span><br><span class="line">&#125; <span class="keyword">else</span> <span class="keyword">if</span> (code.trim().compareTo(<span class="string">"13"</span>) == <span class="number">0</span>) &#123;</span><br><span class="line"><span class="keyword">if</span> (runner.containsKey(session.getId())) &#123;</span><br><span class="line">runner.get(session.getId()).destroy();</span><br><span class="line">&#125;</span><br><span class="line">runner.remove(session.getId());</span><br><span class="line">runtime.remove(session.getId());</span><br><span class="line">response.setContentType(<span class="string">"application/json"</span>);</span><br><span class="line">PrintWriter out = response.getWriter();</span><br><span class="line">out.print(<span class="string">"Exit, please close browser."</span>);</span><br><span class="line">out.flush();</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">Process p = runner.get(session.getId());</span><br><span class="line">OutputStream os = p.getOutputStream();</span><br><span class="line">InputStream in = p.getInputStream();</span><br><span class="line">os.write((code + System.lineSeparator()).getBytes());</span><br><span class="line">os.flush();</span><br><span class="line">BufferedReader dis = <span class="keyword">new</span> BufferedReader(<span class="keyword">new</span> InputStreamReader(in));</span><br><span class="line">String disr = <span class="string">""</span>;</span><br><span class="line"><span class="keyword">while</span> (<span class="keyword">true</span>) &#123;</span><br><span class="line">String newLine = dis.readLine();</span><br><span class="line"><span class="keyword">if</span> (newLine.trim().equalsIgnoreCase(<span class="string">"end"</span>)) &#123;</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line">&#125;</span><br><span class="line">disr += newLine + <span class="string">"\n"</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">response.setContentType(<span class="string">"application/json"</span>);</span><br><span class="line">PrintWriter out = response.getWriter();</span><br><span class="line">out.print(disr);</span><br><span class="line">out.flush();</span><br><span class="line"></span><br><span class="line">runtime.put(session.getId(), session.getLastAccessedTime());</span><br><span class="line">&#125;</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">String javaHome = System.getProperty(<span class="string">"java.home"</span>);</span><br><span class="line">String javaBin = javaHome + File.separator + <span class="string">"bin"</span> + File.separator + <span class="string">"java"</span>;</span><br><span class="line">File f = <span class="keyword">new</span> File(MyPlayer.class.getProtectionDomain().getCodeSource().getLocation().getPath());</span><br><span class="line">String className = MyPlayer.class.getName();</span><br><span class="line">List&lt;String&gt; command = <span class="keyword">new</span> LinkedList&lt;String&gt;();</span><br><span class="line">command.add(javaBin);</span><br><span class="line">command.add(<span class="string">"-cp"</span>);</span><br><span class="line">command.add(f.getAbsolutePath());</span><br><span class="line">command.add(className);</span><br><span class="line">ProcessBuilder builder = <span class="keyword">new</span> ProcessBuilder(command);</span><br><span class="line"></span><br><span class="line">Process p = builder.start();</span><br><span class="line">OutputStream os = p.getOutputStream();</span><br><span class="line">InputStream in = p.getInputStream();</span><br><span class="line">BufferedReader dis = <span class="keyword">new</span> BufferedReader(<span class="keyword">new</span> InputStreamReader(in));</span><br><span class="line">String disr = <span class="string">""</span>;</span><br><span class="line"><span class="keyword">while</span> (<span class="keyword">true</span>) &#123;</span><br><span class="line">String newLine = dis.readLine();</span><br><span class="line"><span class="keyword">if</span> (newLine.trim().equalsIgnoreCase(<span class="string">"end"</span>)) &#123;</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line">&#125;</span><br><span class="line">disr += newLine + <span class="string">"\n"</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">response.setContentType(<span class="string">"application/json"</span>);</span><br><span class="line">PrintWriter out = response.getWriter();</span><br><span class="line">out.print(disr);</span><br><span class="line">out.flush();</span><br><span class="line"></span><br><span class="line">runner.put(session.getId(), p);</span><br><span class="line">runtime.put(session.getId(), session.getLastAccessedTime());</span><br><span class="line">&#125;</span><br><span class="line">&#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line"><span class="keyword">if</span> (runner.containsKey(session.getId())) &#123;</span><br><span class="line">runner.get(session.getId()).destroy();</span><br><span class="line">&#125;</span><br><span class="line">runner.remove(session.getId());</span><br><span class="line">runtime.remove(session.getId());</span><br><span class="line">response.setContentType(<span class="string">"application/json"</span>);</span><br><span class="line">PrintWriter out = response.getWriter();</span><br><span class="line">e.printStackTrace(out);</span><br><span class="line">out.flush();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// remove all long running job</span></span><br><span class="line"><span class="keyword">for</span> (String a : runtime.keySet()) &#123;</span><br><span class="line"><span class="keyword">if</span> ((session.getLastAccessedTime() - runtime.get(a)) &gt;= <span class="number">180000</span>) &#123;<span class="comment">// 3 minutes</span></span><br><span class="line"><span class="keyword">if</span> (runner.containsKey(a)) &#123;</span><br><span class="line">runner.get(a).destroy();</span><br><span class="line">&#125;</span><br><span class="line">runner.remove(a);</span><br><span class="line">runtime.remove(a);</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">destroy</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="keyword">for</span> (String a : runner.keySet()) &#123;</span><br><span class="line">runner.get(a).destroy();</span><br><span class="line">runner.remove(a);</span><br><span class="line">runtime.remove(a);</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content:encoded>
      
      
      <category domain="https://shaokang.me/categories/website/">website</category>
      
      <category domain="https://shaokang.me/categories/website/JSP/">JSP</category>
      
      
      
      <comments>https://shaokang.me/2023/JSP-java-emulator/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>An economical computer</title>
      <link>https://shaokang.me/2023/An-economical-computer/</link>
      <guid>https://shaokang.me/2023/An-economical-computer/</guid>
      <pubDate>Thu, 23 Mar 2023 08:38:49 GMT</pubDate>
      
      <description>&lt;p&gt;Note: This is a group project for a course. I am responsible for coding the actual model and optimizing its structure to make the model run much faster (over 200 times). I am also responsible for scraping data from the official site and setting up github action to regularly update the data source using puppeteer, which could simulate real user behavior and can never been blocked. You can find the relevant repository at &lt;a href=&quot;https://github.com/ShaokangJiang/CSE-203B-crapping&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ShaokangJiang/CSE-203B-crapping (github.com)&lt;/a&gt;. My code can be seen at the end of this post.&lt;/p&gt;&lt;p&gt;Nowadays, new computer components are introduced into the retail market annually. Customers may find that the abundant component choices make it difficult to choose the optimum combination of hardware components while building a new computer. This project aims to take in the main components of a computer hardware build and provide several of the highest-performing options that can meet a consumer’s budget.&lt;/p&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p>Note: This is a group project for a course. I am responsible for coding the actual model and optimizing its structure to make the model run much faster (over 200 times). I am also responsible for scraping data from the official site and setting up github action to regularly update the data source using puppeteer, which could simulate real user behavior and can never been blocked. You can find the relevant repository at <a href="https://github.com/ShaokangJiang/CSE-203B-crapping" target="_blank" rel="noopener">ShaokangJiang/CSE-203B-crapping (github.com)</a>. My code can be seen at the end of this post.</p><p>Nowadays, new computer components are introduced into the retail market annually. Customers may find that the abundant component choices make it difficult to choose the optimum combination of hardware components while building a new computer. This project aims to take in the main components of a computer hardware build and provide several of the highest-performing options that can meet a consumer’s budget.<a id="more"></a></p><p>Original PDF:</p><div class="row"><embed src="CSE_203_Project.pdf" width="100%" height="550" type="application/pdf"></div><p>Extracted text:</p><h1 id="team-assignments"><a class="markdownIt-Anchor" href="#team-assignments"></a> Team Assignments</h1><h2 id="team-members"><a class="markdownIt-Anchor" href="#team-members"></a> Team members</h2><p>Maxim Edelson Shaokang Jiang Junhua Yang Jinghong Luo</p><h2 id="data-curation"><a class="markdownIt-Anchor" href="#data-curation"></a> Data Curation</h2><p>Maxim is scrapping data using python and do completeness, correctness<br>checking of all data. Shaokang was scrapping data using Node.js and<br>autoscrapping feature. Both of them are discussing on how to formulate a<br>better, more meaningful data.</p><h2 id="linear-programming-formulation-and-analysis"><a class="markdownIt-Anchor" href="#linear-programming-formulation-and-analysis"></a> Linear Programming Formulation and Analysis</h2><p>Maxim, Junhua and Jinghong are using python to formulate and analysis<br>the problem. All of us are working to test and revise the python<br>solution code and make it more feasible in running. Shaokang is using<br>GAMS to formulate and analysis the problem.</p><h2 id="paper-writing"><a class="markdownIt-Anchor" href="#paper-writing"></a> Paper Writing</h2><p>Maxim did majority of introduction, problem setup and primal<br>formulation. Shaokang did majority of intended approaches, result and<br>conclusion. Jinghong did intended contributions and contribution vs<br>previous part. All people are working on the primal, dual, KKT<br>formulation and paper reviewing, editing.</p><h1 id="introduction"><a class="markdownIt-Anchor" href="#introduction"></a> Introduction</h1><h2 id="motivation"><a class="markdownIt-Anchor" href="#motivation"></a> Motivation</h2><p>Nowadays, new computer components are introduced into the retail market<br>annually. Customers may find that the abundant component choices make it<br>difficult to choose the optimum combination of hardware components while<br>building a new computer. This project aims to take in the main<br>components of a computer hardware build and provide several of the<br>highest-performing options that can meet a consumer’s budget.</p><h2 id="previous-works"><a class="markdownIt-Anchor" href="#previous-works"></a> Previous Works</h2><p>Linear programming is a modern, powerful mathematical technique that is<br>commonly used to solve optimization problems with constraints<br>[@bradley1971transformation],[@dantzig2002linear],[@sultan2014linear].<br>In particular, there are already many research publications that focus<br>on using linear programming to solve linearly constrained optimization<br>problems. By leveraging linear programming techniques, researchers and<br>practitioners can efficiently solve complex problems with multiple<br>constraints and objectives, enabling them to make more informed<br>decisions.</p><p>One example of using linear programming is the “diet problem”, which<br>seeks to find the optimal combination of foods to meet nutritional<br>requirements at the lowest cost. This problem can be formulated as a<br>linear programming problem, where the objective is to minimize the total<br>cost of the food, subject to constraints on the required nutrients.<br>Authors from paper [@paper1] aim to solve the diet problem of McDonald’s<br>sets menu in the hope of finding the optimal cost while satisfying the<br>daily calories and nutritional requirements for a person.</p><h2 id="intended-contributions"><a class="markdownIt-Anchor" href="#intended-contributions"></a> Intended Contributions</h2><p>In this paper, we have explored state-of-art methods of applying linear<br>programming with constraints to help us formulate our problem and<br>analyze it using primal, dual, and KKT conditions. We came up with our<br>hardware component performance measurement formula in order to formulate<br>the optimization problem and set appropriate constraints based on<br>real-world scenarios. The novelty and main attraction of this paper is<br>applying integer programming techniques to solve computer building<br>problem, which is a relatively new and under-explored area in the<br>computer industry. We also compare the efficiency between commercial and<br>open source solvers.</p><h2 id="organization-of-the-paper"><a class="markdownIt-Anchor" href="#organization-of-the-paper"></a> Organization of the Paper</h2><p>The rest of the paper is divided into different sections illustrating<br>our work. First, we go in-depth to discuss the problem statement in<br>section 3, demonstrating the reasoning behind our objective function and<br>constraints, as well as computing the dual formulation and KKT<br>conditions of the primal problem. In section 4, we talk about the method<br>we use to build the linear programming problem. Then we present the<br>results and conclude our work in section 5.</p><h3 id="contribution-vs-previous-works"><a class="markdownIt-Anchor" href="#contribution-vs-previous-works"></a> Contribution vs Previous Works</h3><p>Even though the application of linear programming have been widely used<br>in various fields to solve complex optimization problems, its<br>application in the computer industry has yet received attentions on.<br>With this paper, we hope to make significant impact on the computer<br>community by offering this new way of identifying the computer build to<br>customers who are looking for cost-effective builds with optimal<br>performance. We think by exploring into the novel field of computer<br>building with linear programming makes us unique compared to the other<br>previous works.</p><h1 id="statement-of-the-problem"><a class="markdownIt-Anchor" href="#statement-of-the-problem"></a> Statement of the Problem</h1><h2 id="problem-setup"><a class="markdownIt-Anchor" href="#problem-setup"></a> Problem Setup</h2><p>Before formulating the primal problem, it is necessary to discuss how we<br>have arrived to the problem itself. In this paper, we utilized data from<br>the website <a href="https://www.userbenchmark.com" target="_blank" rel="noopener">UserBenchmark.com</a> by web<br>scraping down component names, benchmarks, prices, samples per<br>component, and value for GPUs, CPUs, SSDs, HDDs, and RAM (automatically<br>updating). Using the datasets we collected, we crafted g(s) (equation<br>(1)), which is used as a part of our objective function (equation (3)).<br>This objective function allows us estimate the performance of a hardware<br>based on its price, benchmark, value of the component, and number of<br>benchmark samples.</p><p><span class="katex-display"><span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>g</mi><mo>(</mo><mi>s</mi><mo>)</mo><mo>=</mo><mfrac><mrow><mtext><mi mathvariant="normal">b</mi><mi mathvariant="normal">e</mi><mi mathvariant="normal">n</mi><mi mathvariant="normal">c</mi><mi mathvariant="normal">h</mi><mi mathvariant="normal">m</mi><mi mathvariant="normal">a</mi><mi mathvariant="normal">r</mi><mi mathvariant="normal">k</mi><mtext> </mtext><mi mathvariant="normal">*</mi><mtext> </mtext><mi mathvariant="normal">v</mi><mi mathvariant="normal">a</mi><mi mathvariant="normal">l</mi><mi mathvariant="normal">u</mi><mi mathvariant="normal">e</mi><mtext> </mtext><mi mathvariant="normal">*</mi><mtext> </mtext><mi mathvariant="normal">s</mi><mi mathvariant="normal">a</mi><mi mathvariant="normal">m</mi><mi mathvariant="normal">p</mi><mi mathvariant="normal">l</mi><mi mathvariant="normal">e</mi><mi mathvariant="normal">s</mi></mtext></mrow><mrow><mtext><mi mathvariant="normal">p</mi><mi mathvariant="normal">r</mi><mi mathvariant="normal">i</mi><mi mathvariant="normal">c</mi><mi mathvariant="normal">e</mi></mtext></mrow></mfrac></mrow><annotation encoding="application/x-tex">g(s) = \frac{\text{benchmark * value * samples}}{\text{price}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:1.427em"></span><span class="strut bottom" style="height:2.30744em;vertical-align:-.8804400000000001em"></span><span class="base displaystyle textstyle uncramped"><span class="mord mathit" style="margin-right:.03588em">g</span><span class="mopen">(</span><span class="mord mathit">s</span><span class="mclose">)</span><span class="mrel">=</span><span class="mord reset-textstyle displaystyle textstyle uncramped"><span class="sizing reset-size5 size5 reset-textstyle textstyle uncramped nulldelimiter"></span><span class="mfrac"><span class="vlist"><span style="top:.6860000000000002em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle textstyle cramped"><span class="mord textstyle cramped"><span class="text mord textstyle cramped"><span class="mord mathrm">p</span><span class="mord mathrm">r</span><span class="mord mathrm">i</span><span class="mord mathrm">c</span><span class="mord mathrm">e</span></span></span></span></span><span style="top:-.22999999999999998em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle textstyle uncramped frac-line"></span></span><span style="top:-.677em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle textstyle uncramped"><span class="mord textstyle uncramped"><span class="text mord textstyle uncramped"><span class="mord mathrm">b</span><span class="mord mathrm">e</span><span class="mord mathrm">n</span><span class="mord mathrm">c</span><span class="mord mathrm">h</span><span class="mord mathrm">m</span><span class="mord mathrm">a</span><span class="mord mathrm">r</span><span class="mord mathrm">k</span><span class="mord mspace"> </span><span class="mord mathrm">*</span><span class="mord mspace"> </span><span class="mord mathrm" style="margin-right:.01389em">v</span><span class="mord mathrm">a</span><span class="mord mathrm">l</span><span class="mord mathrm">u</span><span class="mord mathrm">e</span><span class="mord mspace"> </span><span class="mord mathrm">*</span><span class="mord mspace"> </span><span class="mord mathrm">s</span><span class="mord mathrm">a</span><span class="mord mathrm">m</span><span class="mord mathrm">p</span><span class="mord mathrm">l</span><span class="mord mathrm">e</span><span class="mord mathrm">s</span></span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="sizing reset-size5 size5 reset-textstyle textstyle uncramped nulldelimiter"></span></span></span></span></span></span></p><p>Formula (1) computes a ratio of performance to cost, adjusted by the<br>hardware’s overall value and the sample size used to obtain the<br>benchmark score. A higher score indicates better performance for the<br>price. It’s important to note that this formula is just one possible way<br>to measure hardware performance, and that there are many other factors<br>that may be relevant depending on the context.</p><p>Next, to define our constraints, we look back to our motivation of the<br>paper, which is to find highest-performing hardware build options that<br>can meet the budget. To do this, we need to 1) constrain the total<br>budget of all hardware combinations to be less than the fixed budget we<br>specified, and 2) limit the count of each hardware component in a<br>combination to 1 (i.e., one GPU, one CPU, etc…) because we are<br>looking for the optimum combination of hardware components in terms of<br>performance per cost.</p><h2 id="primal-formulation"><a class="markdownIt-Anchor" href="#primal-formulation"></a> Primal Formulation</h2><p><span class="katex-display"><span class="katex"><span class="katex-mathml"><math><semantics><mrow><mtext><mi mathvariant="normal">F</mi><mi mathvariant="normal">r</mi><mi mathvariant="normal">o</mi><mi mathvariant="normal">m</mi><mtext> </mtext><mi mathvariant="normal">(</mi><mn>1</mn><mi mathvariant="normal">)</mi><mi mathvariant="normal">,</mi><mtext> </mtext><mi mathvariant="normal">l</mi><mi mathvariant="normal">e</mi><mi mathvariant="normal">t</mi><mtext> </mtext></mtext><mi>g</mi><mo>(</mo><mi>s</mi><mo>)</mo><mo>=</mo><mfrac><mrow><msub><mi>s</mi><mn>1</mn></msub><mo>∗</mo><msub><mi>s</mi><mn>2</mn></msub><mo>∗</mo><msub><mi>s</mi><mn>3</mn></msub></mrow><mrow><msub><mi>s</mi><mn>4</mn></msub></mrow></mfrac><mtext><mtext> </mtext><mi mathvariant="normal">w</mi><mi mathvariant="normal">h</mi><mi mathvariant="normal">e</mi><mi mathvariant="normal">r</mi><mi mathvariant="normal">e</mi><mtext> </mtext></mtext><mi>s</mi><mo>∈</mo><msup><mi>R</mi><mrow><mn>4</mn></mrow></msup></mrow><annotation encoding="application/x-tex">\text{From (1), let } g(s) = \frac{s_1*s_2*s_3}{s_4} \text{ where } s \in R^{4}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:1.14228em"></span><span class="strut bottom" style="height:1.97828em;vertical-align:-.8360000000000001em"></span><span class="base displaystyle textstyle uncramped"><span class="text mord displaystyle textstyle uncramped"><span class="mord mathrm">F</span><span class="mord mathrm">r</span><span class="mord mathrm">o</span><span class="mord mathrm">m</span><span class="mord mspace"> </span><span class="mord mathrm">(</span><span class="mord mathrm">1</span><span class="mord mathrm">)</span><span class="mord mathrm">,</span><span class="mord mspace"> </span><span class="mord mathrm">l</span><span class="mord mathrm">e</span><span class="mord mathrm">t</span><span class="mord mspace"> </span></span><span class="mord mathit" style="margin-right:.03588em">g</span><span class="mopen">(</span><span class="mord mathit">s</span><span class="mclose">)</span><span class="mrel">=</span><span class="mord reset-textstyle displaystyle textstyle uncramped"><span class="sizing reset-size5 size5 reset-textstyle textstyle uncramped nulldelimiter"></span><span class="mfrac"><span class="vlist"><span style="top:.686em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle textstyle cramped"><span class="mord textstyle cramped"><span class="mord"><span class="mord mathit">s</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">4</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span></span></span></span><span style="top:-.22999999999999998em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle textstyle uncramped frac-line"></span></span><span style="top:-.677em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle textstyle uncramped"><span class="mord textstyle uncramped"><span class="mord"><span class="mord mathit">s</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">1</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mbin">∗</span><span class="mord"><span class="mord mathit">s</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">2</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mbin">∗</span><span class="mord"><span class="mord mathit">s</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">3</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="sizing reset-size5 size5 reset-textstyle textstyle uncramped nulldelimiter"></span></span><span class="text mord displaystyle textstyle uncramped"><span class="mord mspace"> </span><span class="mord mathrm" style="margin-right:.01389em">w</span><span class="mord mathrm">h</span><span class="mord mathrm">e</span><span class="mord mathrm">r</span><span class="mord mathrm">e</span><span class="mord mspace"> </span></span><span class="mord mathit">s</span><span class="mrel">∈</span><span class="mord"><span class="mord mathit" style="margin-right:.00773em">R</span><span class="vlist"><span style="top:-.413em;margin-right:.05em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle uncramped"><span class="mord scriptstyle uncramped"><span class="mord mathrm">4</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span></span></span></span></span></p><p>In equation (1), <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>s</mi><mn>1</mn></msub></mrow><annotation encoding="application/x-tex">s_1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:.43056em"></span><span class="strut bottom" style="height:.58056em;vertical-align:-.15em"></span><span class="base textstyle uncramped"><span class="mord"><span class="mord mathit">s</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">1</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span></span></span></span> is the component benchmark (with a range of<br>0-100), <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>s</mi><mn>2</mn></msub></mrow><annotation encoding="application/x-tex">s_2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:.43056em"></span><span class="strut bottom" style="height:.58056em;vertical-align:-.15em"></span><span class="base textstyle uncramped"><span class="mord"><span class="mord mathit">s</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">2</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span></span></span></span> is the number of recorded benchmark samples min-max<br>normalized between 0-1, <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>s</mi><mn>3</mn></msub></mrow><annotation encoding="application/x-tex">s_3</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:.43056em"></span><span class="strut bottom" style="height:.58056em;vertical-align:-.15em"></span><span class="base textstyle uncramped"><span class="mord"><span class="mord mathit">s</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">3</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span></span></span></span> describes whether this component is<br>valuable from the user’s perspective (with a range of 0-100), and <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>s</mi><mn>4</mn></msub></mrow><annotation encoding="application/x-tex">s_4</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:.43056em"></span><span class="strut bottom" style="height:.58056em;vertical-align:-.15em"></span><span class="base textstyle uncramped"><span class="mord"><span class="mord mathit">s</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">4</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span></span></span></span><br>is the current component price with no upper bounds.\</p><p>Let <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>n</mi><mo>∈</mo><mrow><mi mathvariant="double-struck">N</mi></mrow></mrow><annotation encoding="application/x-tex">n \in \mathbb{N}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:.68889em"></span><span class="strut bottom" style="height:.72799em;vertical-align:-.0391em"></span><span class="base textstyle uncramped"><span class="mord mathit">n</span><span class="mrel">∈</span><span class="mord textstyle uncramped"><span class="mord mathbb">N</span></span></span></span></span> be the number of components in each category<br>(CPU, GPU, SSD, RAM)</p><p><span class="katex-display"><span class="katex"><span class="katex-mathml"><math><semantics><mrow><mtext><mi mathvariant="normal">m</mi><mi mathvariant="normal">a</mi><mi mathvariant="normal">x</mi><mtext> </mtext></mtext><msub><mo>∑</mo><mrow><mi>i</mi><mo>∈</mo><mi>n</mi></mrow></msub><mi>g</mi><mo>(</mo><msub><mi>c</mi><mi>i</mi></msub><mo>)</mo><mo>∗</mo><msub><mi>x</mi><mrow><mn>1</mn><mi>i</mi></mrow></msub><mo>+</mo><msub><mo>∑</mo><mrow><mi>i</mi><mo>∈</mo><mi>n</mi></mrow></msub><mi>g</mi><mo>(</mo><msub><mi>d</mi><mi>i</mi></msub><mo>)</mo><mo>∗</mo><msub><mi>x</mi><mrow><mn>2</mn><mi>i</mi></mrow></msub><mo>+</mo><msub><mo>∑</mo><mrow><mi>i</mi><mo>∈</mo><mi>n</mi></mrow></msub><mi>g</mi><mo>(</mo><msub><mi>e</mi><mi>i</mi></msub><mo>)</mo><mo>∗</mo><msub><mi>x</mi><mrow><mn>3</mn><mi>i</mi></mrow></msub><mo>+</mo><msub><mo>∑</mo><mrow><mi>i</mi><mo>∈</mo><mi>n</mi></mrow></msub><mi>g</mi><mo>(</mo><msub><mi>f</mi><mi>i</mi></msub><mo>)</mo><mo>∗</mo><msub><mi>x</mi><mrow><mn>4</mn><mi>i</mi></mrow></msub></mrow><annotation encoding="application/x-tex">\text{max } \sum_{i\in n}g(c_i)*x_{1i} + \sum_{i\in n}g(d_i)*x_{2i} + \sum_{i\in n}g(e_i)*x_{3i} + \sum_{i\in n}g(f_i)*x_{4i}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:1.050005em"></span><span class="strut bottom" style="height:2.3550440000000004em;vertical-align:-1.305039em"></span><span class="base displaystyle textstyle uncramped"><span class="text mord displaystyle textstyle uncramped"><span class="mord mathrm">m</span><span class="mord mathrm">a</span><span class="mord mathrm">x</span><span class="mord mspace"> </span></span><span class="mop op-limits"><span class="vlist"><span style="top:1.177669em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mrel">∈</span><span class="mord mathit">n</span></span></span></span><span style="top:-.000005000000000032756em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span><span class="op-symbol large-op mop">∑</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mord mathit" style="margin-right:.03588em">g</span><span class="mopen">(</span><span class="mord"><span class="mord mathit">c</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathit">i</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mclose">)</span><span class="mbin">∗</span><span class="mord"><span class="mord mathit">x</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathrm">1</span><span class="mord mathit">i</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mbin">+</span><span class="mop op-limits"><span class="vlist"><span style="top:1.177669em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mrel">∈</span><span class="mord mathit">n</span></span></span></span><span style="top:-.000005000000000032756em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span><span class="op-symbol large-op mop">∑</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mord mathit" style="margin-right:.03588em">g</span><span class="mopen">(</span><span class="mord"><span class="mord mathit">d</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathit">i</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mclose">)</span><span class="mbin">∗</span><span class="mord"><span class="mord mathit">x</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathrm">2</span><span class="mord mathit">i</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mbin">+</span><span class="mop op-limits"><span class="vlist"><span style="top:1.177669em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mrel">∈</span><span class="mord mathit">n</span></span></span></span><span style="top:-.000005000000000032756em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span><span class="op-symbol large-op mop">∑</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mord mathit" style="margin-right:.03588em">g</span><span class="mopen">(</span><span class="mord"><span class="mord mathit">e</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathit">i</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mclose">)</span><span class="mbin">∗</span><span class="mord"><span class="mord mathit">x</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathrm">3</span><span class="mord mathit">i</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mbin">+</span><span class="mop op-limits"><span class="vlist"><span style="top:1.177669em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mrel">∈</span><span class="mord mathit">n</span></span></span></span><span style="top:-.000005000000000032756em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span><span class="op-symbol large-op mop">∑</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mord mathit" style="margin-right:.03588em">g</span><span class="mopen">(</span><span class="mord"><span class="mord mathit" style="margin-right:.10764em">f</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.10764em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathit">i</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mclose">)</span><span class="mbin">∗</span><span class="mord"><span class="mord mathit">x</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathrm">4</span><span class="mord mathit">i</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span></span></span></span></span></p><p><span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>c</mi><mo separator="true">,</mo><mi>d</mi><mo separator="true">,</mo><mi>e</mi><mo separator="true">,</mo><mi>f</mi><mo>∈</mo><msup><mrow><mi mathvariant="double-struck">S</mi></mrow><mrow><mi>n</mi><mtext><mi mathvariant="normal">x</mi></mtext><mn>4</mn></mrow></msup></mrow><annotation encoding="application/x-tex">c, d, e, f \in \mathbb{S}^{n\text{x}4}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:.8141079999999999em"></span><span class="strut bottom" style="height:1.008548em;vertical-align:-.19444em"></span><span class="base textstyle uncramped"><span class="mord mathit">c</span><span class="mpunct">,</span><span class="mord mathit">d</span><span class="mpunct">,</span><span class="mord mathit">e</span><span class="mpunct">,</span><span class="mord mathit" style="margin-right:.10764em">f</span><span class="mrel">∈</span><span><span class="mord textstyle uncramped"><span class="mord mathbb">S</span></span><span class="vlist"><span style="top:-.363em;margin-right:.05em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle uncramped"><span class="mord scriptstyle uncramped"><span class="mord mathit">n</span><span class="text mord scriptstyle uncramped"><span class="mord mathrm">x</span></span><span class="mord mathrm">4</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span></span></span></span><br><span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>x</mi><mn>1</mn></msub><mo separator="true">,</mo><msub><mi>x</mi><mn>2</mn></msub><mo separator="true">,</mo><msub><mi>x</mi><mn>3</mn></msub><mo separator="true">,</mo><msub><mi>x</mi><mn>4</mn></msub><mo>∈</mo><mo>{</mo><mn>0</mn><mo separator="true">,</mo><mn>1</mn><msup><mo>}</mo><mrow><mi>n</mi></mrow></msup></mrow><annotation encoding="application/x-tex">x_1, x_2, x_3, x_4 \in \{0,1\}^{n}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:.75em"></span><span class="strut bottom" style="height:1em;vertical-align:-.25em"></span><span class="base textstyle uncramped"><span class="mord"><span class="mord mathit">x</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">1</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mpunct">,</span><span class="mord"><span class="mord mathit">x</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">2</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mpunct">,</span><span class="mord"><span class="mord mathit">x</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">3</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mpunct">,</span><span class="mord"><span class="mord mathit">x</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">4</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mrel">∈</span><span class="mopen">{</span><span class="mord mathrm">0</span><span class="mpunct">,</span><span class="mord mathrm">1</span><span class="mclose"><span class="mclose">}</span><span class="vlist"><span style="top:-.363em;margin-right:.05em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle uncramped"><span class="mord scriptstyle uncramped"><span class="mord mathit">n</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span></span></span></span></p><p>subject to</p><p><span class="katex-display"><span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mo>∑</mo><mrow><mi>i</mi><mo>∈</mo><mi>n</mi></mrow></msub><mo>(</mo><msub><mi>c</mi><mrow><mi>i</mi><mo separator="true">,</mo><mn>4</mn></mrow></msub><mo>∗</mo><msub><mi>x</mi><mrow><mn>1</mn><mi>i</mi></mrow></msub><mo>)</mo><mo>+</mo><msub><mo>∑</mo><mrow><mi>i</mi><mo>∈</mo><mi>n</mi></mrow></msub><mo>(</mo><msub><mi>d</mi><mrow><mi>i</mi><mo separator="true">,</mo><mn>4</mn></mrow></msub><mo>∗</mo><msub><mi>x</mi><mrow><mn>2</mn><mi>i</mi></mrow></msub><mo>)</mo><mo>+</mo><msub><mo>∑</mo><mrow><mi>i</mi><mo>∈</mo><mi>n</mi></mrow></msub><mo>(</mo><msub><mi>e</mi><mrow><mi>i</mi><mo separator="true">,</mo><mn>4</mn></mrow></msub><mo>∗</mo><msub><mi>x</mi><mrow><mn>3</mn><mi>i</mi></mrow></msub><mo>)</mo><mo>+</mo><msub><mo>∑</mo><mrow><mi>i</mi><mo>∈</mo><mi>n</mi></mrow></msub><mo>(</mo><msub><mi>f</mi><mrow><mi>i</mi><mo separator="true">,</mo><mn>4</mn></mrow></msub><mo>∗</mo><msub><mi>x</mi><mrow><mn>4</mn><mi>i</mi></mrow></msub><mo>)</mo><mo>≤</mo><mi>b</mi><mtext><mi mathvariant="normal">,</mi><mtext> </mtext><mi mathvariant="normal">w</mi><mi mathvariant="normal">h</mi><mi mathvariant="normal">e</mi><mi mathvariant="normal">r</mi><mi mathvariant="normal">e</mi><mtext> </mtext></mtext><mi>b</mi><mo>∈</mo><msub><mi>R</mi><mrow><mo>+</mo><mo>+</mo></mrow></msub><mtext><mtext> </mtext><mi mathvariant="normal">i</mi><mi mathvariant="normal">s</mi><mtext> </mtext><mi mathvariant="normal">t</mi><mi mathvariant="normal">h</mi><mi mathvariant="normal">e</mi><mtext> </mtext><mi mathvariant="normal">b</mi><mi mathvariant="normal">u</mi><mi mathvariant="normal">d</mi><mi mathvariant="normal">g</mi><mi mathvariant="normal">e</mi><mi mathvariant="normal">t</mi></mtext></mrow><annotation encoding="application/x-tex">\sum_{i\in n}(c_{i,4}*x_{1i}) + \sum_{i\in n}(d_{i,4}*x_{2i}) + \sum_{i\in n}(e_{i,4}*x_{3i}) + \sum_{i\in n}(f_{i,4}*x_{4i}) \leq b \text{, where } b \in R_{++} \text{ is the budget}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:1.050005em"></span><span class="strut bottom" style="height:2.3550440000000004em;vertical-align:-1.305039em"></span><span class="base displaystyle textstyle uncramped"><span class="mop op-limits"><span class="vlist"><span style="top:1.177669em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mrel">∈</span><span class="mord mathit">n</span></span></span></span><span style="top:-.000005000000000032756em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span><span class="op-symbol large-op mop">∑</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathit">c</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mpunct">,</span><span class="mord mathrm">4</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mbin">∗</span><span class="mord"><span class="mord mathit">x</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathrm">1</span><span class="mord mathit">i</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mclose">)</span><span class="mbin">+</span><span class="mop op-limits"><span class="vlist"><span style="top:1.177669em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mrel">∈</span><span class="mord mathit">n</span></span></span></span><span style="top:-.000005000000000032756em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span><span class="op-symbol large-op mop">∑</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathit">d</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mpunct">,</span><span class="mord mathrm">4</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mbin">∗</span><span class="mord"><span class="mord mathit">x</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathrm">2</span><span class="mord mathit">i</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mclose">)</span><span class="mbin">+</span><span class="mop op-limits"><span class="vlist"><span style="top:1.177669em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mrel">∈</span><span class="mord mathit">n</span></span></span></span><span style="top:-.000005000000000032756em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span><span class="op-symbol large-op mop">∑</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathit">e</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mpunct">,</span><span class="mord mathrm">4</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mbin">∗</span><span class="mord"><span class="mord mathit">x</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathrm">3</span><span class="mord mathit">i</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mclose">)</span><span class="mbin">+</span><span class="mop op-limits"><span class="vlist"><span style="top:1.177669em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mrel">∈</span><span class="mord mathit">n</span></span></span></span><span style="top:-.000005000000000032756em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span><span class="op-symbol large-op mop">∑</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathit" style="margin-right:.10764em">f</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.10764em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mpunct">,</span><span class="mord mathrm">4</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mbin">∗</span><span class="mord"><span class="mord mathit">x</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathrm">4</span><span class="mord mathit">i</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mclose">)</span><span class="mrel">≤</span><span class="mord mathit">b</span><span class="text mord displaystyle textstyle uncramped"><span class="mord mathrm">,</span><span class="mord mspace"> </span><span class="mord mathrm" style="margin-right:.01389em">w</span><span class="mord mathrm">h</span><span class="mord mathrm">e</span><span class="mord mathrm">r</span><span class="mord mathrm">e</span><span class="mord mspace"> </span></span><span class="mord mathit">b</span><span class="mrel">∈</span><span class="mord"><span class="mord mathit" style="margin-right:.00773em">R</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.00773em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord">+</span><span class="mbin">+</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="text mord displaystyle textstyle uncramped"><span class="mord mspace"> </span><span class="mord mathrm">i</span><span class="mord mathrm">s</span><span class="mord mspace"> </span><span class="mord mathrm">t</span><span class="mord mathrm">h</span><span class="mord mathrm">e</span><span class="mord mspace"> </span><span class="mord mathrm">b</span><span class="mord mathrm">u</span><span class="mord mathrm">d</span><span class="mord mathrm" style="margin-right:.01389em">g</span><span class="mord mathrm">e</span><span class="mord mathrm">t</span></span></span></span></span></span></p>\textbf{1}^Tx_1=1 \text{, } \textbf{1}^Tx_2=1 \text{, } \textbf{1}^Tx_3=1 \text{, } \textbf{1}^Tx_4=1<h2 id="dual-formulations"><a class="markdownIt-Anchor" href="#dual-formulations"></a> Dual Formulations</h2><p>The Lagrangian function is $$\begin{split}<br>\mathcal{L}(x_1,x_2,x_3,x_4,\lambda,v_1,v_2,v_3,v_4)&amp;=<br>\sum_{i\in n}g(c_i)*x_{1i} + \sum_{i\in n}g(d_i)*x_{2i} + \sum_{i\in n}g(e_i)*x_{3i} + \sum_{i\in n}g(f_i)*x_{4i} \<br>&amp;+ \lambda (\sum_{i\in n}(c_{i,4}*x_{1i}) + \sum_{i\in n}(d_{i,4}*x_{2i}) + \sum_{i\in n}(e_{i,4}*x_{3i}) + \sum_{i\in n}(f_{i,4}*x_{4i}) - b) \<br>&amp;+ v_1(\textbf{1}^T x_{1} -1) + v_2(\textbf{1}^T x_{2} -1) + v_3( \textbf{1}^T x_{3} -1) + v_4(\textbf{1}^T x_{4} -1), \text{ where } \lambda \geq 0<br>\end{split}$$</p><p>To compute<br><span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>max</mi><mrow><msub><mi>x</mi><mn>1</mn></msub><mo separator="true">,</mo><msub><mi>x</mi><mn>2</mn></msub><mo separator="true">,</mo><msub><mi>x</mi><mn>3</mn></msub><mo separator="true">,</mo><msub><mi>x</mi><mn>4</mn></msub></mrow></msub><mrow><mi mathvariant="script">L</mi></mrow><mo>(</mo><msub><mi>x</mi><mn>1</mn></msub><mo separator="true">,</mo><msub><mi>x</mi><mn>2</mn></msub><mo separator="true">,</mo><msub><mi>x</mi><mn>3</mn></msub><mo separator="true">,</mo><msub><mi>x</mi><mn>4</mn></msub><mo separator="true">,</mo><mi>λ</mi><mo separator="true">,</mo><msub><mi>v</mi><mn>1</mn></msub><mo separator="true">,</mo><msub><mi>v</mi><mn>2</mn></msub><mo separator="true">,</mo><msub><mi>v</mi><mn>3</mn></msub><mo separator="true">,</mo><msub><mi>v</mi><mn>4</mn></msub><mo>)</mo></mrow><annotation encoding="application/x-tex">\max_{x_1,x_2,x_3,x_4} \mathcal{L}(x_1,x_2,x_3,x_4,\lambda,v_1,v_2,v_3,v_4)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:.75em"></span><span class="strut bottom" style="height:1.036108em;vertical-align:-.286108em"></span><span class="base textstyle uncramped"><span class="mop"><span class="mop">max</span><span class="vlist"><span style="top:.15em;margin-right:.05em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord"><span class="mord mathit">x</span><span class="vlist"><span style="top:.15em;margin-right:.07142857142857144em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-scriptstyle scriptscriptstyle cramped"><span class="mord mathrm">1</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mpunct">,</span><span class="mord"><span class="mord mathit">x</span><span class="vlist"><span style="top:.15em;margin-right:.07142857142857144em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-scriptstyle scriptscriptstyle cramped"><span class="mord mathrm">2</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mpunct">,</span><span class="mord"><span class="mord mathit">x</span><span class="vlist"><span style="top:.15em;margin-right:.07142857142857144em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-scriptstyle scriptscriptstyle cramped"><span class="mord mathrm">3</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mpunct">,</span><span class="mord"><span class="mord mathit">x</span><span class="vlist"><span style="top:.15em;margin-right:.07142857142857144em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-scriptstyle scriptscriptstyle cramped"><span class="mord mathrm">4</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mord textstyle uncramped"><span class="mord mathcal">L</span></span><span class="mopen">(</span><span class="mord"><span class="mord mathit">x</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">1</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mpunct">,</span><span class="mord"><span class="mord mathit">x</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">2</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mpunct">,</span><span class="mord"><span class="mord mathit">x</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">3</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mpunct">,</span><span class="mord"><span class="mord mathit">x</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">4</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mpunct">,</span><span class="mord mathit">λ</span><span class="mpunct">,</span><span class="mord"><span class="mord mathit" style="margin-right:.03588em">v</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.03588em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">1</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mpunct">,</span><span class="mord"><span class="mord mathit" style="margin-right:.03588em">v</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.03588em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">2</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mpunct">,</span><span class="mord"><span class="mord mathit" style="margin-right:.03588em">v</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.03588em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">3</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mpunct">,</span><span class="mord"><span class="mord mathit" style="margin-right:.03588em">v</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.03588em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">4</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mclose">)</span></span></span></span>,<br>let us take $$\begin{pmatrix}<br>\frac{\partial\mathcal{L}}{\partial x_1} \\<br>\frac{\partial\mathcal{L}}{\partial x_2} \\<br>\frac{\partial\mathcal{L}}{\partial x_3} \\<br>\frac{\partial\mathcal{L}}{\partial x_4}<br>\end{pmatrix} =<br>\begin{pmatrix}<br>0 \\ 0 \\ 0 \\ 0<br>\end{pmatrix} \implies<br>\begin{cases}<br>\sum_{i\in n}g(c_i) + \lambda \sum_{i\in n}c_{i,4} + v_{1}\textbf{1}^T = 0\\<br>\sum_{i\in n}g(d_i) + \lambda \sum_{i\in n}d_{i,4} + v_{2}\textbf{1}^T = 0\\<br>\sum_{i\in n}g(e_i) + \lambda \sum_{i\in n}e_{i,4} + v_{3}\textbf{1}^T = 0\\<br>\sum_{i\in n}g(f_i) + \lambda \sum_{i\in n}f_{i,4} + v_{4}\textbf{1}^T = 0<br>\end{cases}$$<br>When <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>λ</mi></mrow><annotation encoding="application/x-tex">\lambda</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:.69444em"></span><span class="strut bottom" style="height:.69444em;vertical-align:0"></span><span class="base textstyle uncramped"><span class="mord mathit">λ</span></span></span></span> and <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>v</mi><mn>1</mn></msub><mo separator="true">,</mo><msub><mi>v</mi><mn>2</mn></msub><mo separator="true">,</mo><msub><mi>v</mi><mn>3</mn></msub><mo separator="true">,</mo><msub><mi>v</mi><mn>4</mn></msub></mrow><annotation encoding="application/x-tex">v_1,v_2,v_3,v_4</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:.43056em"></span><span class="strut bottom" style="height:.625em;vertical-align:-.19444em"></span><span class="base textstyle uncramped"><span class="mord"><span class="mord mathit" style="margin-right:.03588em">v</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.03588em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">1</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mpunct">,</span><span class="mord"><span class="mord mathit" style="margin-right:.03588em">v</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.03588em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">2</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mpunct">,</span><span class="mord"><span class="mord mathit" style="margin-right:.03588em">v</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.03588em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">3</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mpunct">,</span><span class="mord"><span class="mord mathit" style="margin-right:.03588em">v</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.03588em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">4</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span></span></span></span> satisfy these four equations, we<br>get\</p>\begin{split} \text{max}_{x_1,x_2,x_3,x_4} \mathcal{L}(x_1,x_2,x_3,x_4,\lambda,v_1,v_2,v_3,v_4) = &\text{ }(\sum_{i\in n}g(c_i) + \lambda \sum_{i\in n}c_{i,4} + v_{1}\textbf{1}^T)x_1 + (\sum_{i\in n}g(d_i) + \lambda \sum_{i\in n}d_{i,4} + v_{2}\textbf{1}^T)x_2\\ & +(\sum_{i\in n}g(e_i) + \lambda \sum_{i\in n}e_{i,4} + v_{3}\textbf{1}^T)x_3 +(\sum_{i\in n}g(f_i) + \lambda \sum_{i\in n}f_{i,4} + v_{4}\textbf{1}^T)x_4\\ & -\lambda b - v_1 - v_2 - v_3 - v_4\\ & = 0x_1 + 0x_2 + 0x_3 + 0x_4 -\lambda b - v_1 - v_2 - v_3 - v_4\\ & = -\lambda b - v_1 - v_2 - v_3 - v_4 \end{split}<p>The Dual function is $$\begin{aligned}<br>\text{min } -\lambda b - v_1 - v_2 - v_3 - v_4\<br>\text{subject to }<br>\begin{pmatrix}<br>\sum_{i\in n}g(c_i) + \lambda \sum_{i\in n}c_{i,4} + v_{1}\textbf{1}^T = 0\<br>\sum_{i\in n}g(d_i) + \lambda \sum_{i\in n}d_{i,4} + v_{2}\textbf{1}^T = 0\<br>\sum_{i\in n}g(e_i) + \lambda \sum_{i\in n}e_{i,4} + v_{3}\textbf{1}^T = 0\<br>\sum_{i\in n}g(f_i) + \lambda \sum_{i\in n}f_{i,4} + v_{4}\textbf{1}^T = 0\<br>\lambda \geq 0<br>\end{pmatrix}<br>\end{aligned}<br>\text{ where } c, d, e, f \in \mathbb{S}^{n\text{x}4}$$</p><h2 id="kkt-conditions"><a class="markdownIt-Anchor" href="#kkt-conditions"></a> KKT Conditions</h2><h3 id="primal-constraints"><a class="markdownIt-Anchor" href="#primal-constraints"></a> Primal Constraints</h3><p>\textbf{1}^Tx_1 - 1=0<br>\textbf{1}^Tx_2 - 1=0<br>\textbf{1}^Tx_3 - 1=0<br>\textbf{1}^Tx_4 - 1=0<br><span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mo>∑</mo><mrow><mi>i</mi><mo>∈</mo><mi>n</mi></mrow></msub><mo>(</mo><msub><mi>c</mi><mrow><mi>i</mi><mo separator="true">,</mo><mn>4</mn></mrow></msub><mo>∗</mo><msub><mi>x</mi><mrow><mn>1</mn><mi>i</mi></mrow></msub><mo>)</mo><mo>+</mo><msub><mo>∑</mo><mrow><mi>i</mi><mo>∈</mo><mi>n</mi></mrow></msub><mo>(</mo><msub><mi>d</mi><mrow><mi>i</mi><mo separator="true">,</mo><mn>4</mn></mrow></msub><mo>∗</mo><msub><mi>x</mi><mrow><mn>2</mn><mi>i</mi></mrow></msub><mo>)</mo><mo>+</mo><msub><mo>∑</mo><mrow><mi>i</mi><mo>∈</mo><mi>n</mi></mrow></msub><mo>(</mo><msub><mi>e</mi><mrow><mi>i</mi><mo separator="true">,</mo><mn>4</mn></mrow></msub><mo>∗</mo><msub><mi>x</mi><mrow><mn>3</mn><mi>i</mi></mrow></msub><mo>)</mo><mo>+</mo><msub><mo>∑</mo><mrow><mi>i</mi><mo>∈</mo><mi>n</mi></mrow></msub><mo>(</mo><msub><mi>f</mi><mrow><mi>i</mi><mo separator="true">,</mo><mn>4</mn></mrow></msub><mo>∗</mo><msub><mi>x</mi><mrow><mn>4</mn><mi>i</mi></mrow></msub><mo>)</mo><mo>−</mo><mi>b</mi><mo>≤</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">\sum_{i\in n}(c_{i,4}*x_{1i}) + \sum_{i\in n}(d_{i,4}*x_{2i}) + \sum_{i\in n}(e_{i,4}*x_{3i}) + \sum_{i\in n}(f_{i,4}*x_{4i}) - b\leq 0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:.75em"></span><span class="strut bottom" style="height:1.07738em;vertical-align:-.32738em"></span><span class="base textstyle uncramped"><span class="mop"><span class="op-symbol small-op mop" style="top:-.0000050000000000050004em">∑</span><span class="vlist"><span style="top:.30001em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mrel">∈</span><span class="mord mathit">n</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathit">c</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mpunct">,</span><span class="mord mathrm">4</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mbin">∗</span><span class="mord"><span class="mord mathit">x</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathrm">1</span><span class="mord mathit">i</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mclose">)</span><span class="mbin">+</span><span class="mop"><span class="op-symbol small-op mop" style="top:-.0000050000000000050004em">∑</span><span class="vlist"><span style="top:.30001em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mrel">∈</span><span class="mord mathit">n</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathit">d</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mpunct">,</span><span class="mord mathrm">4</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mbin">∗</span><span class="mord"><span class="mord mathit">x</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathrm">2</span><span class="mord mathit">i</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mclose">)</span><span class="mbin">+</span><span class="mop"><span class="op-symbol small-op mop" style="top:-.0000050000000000050004em">∑</span><span class="vlist"><span style="top:.30001em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mrel">∈</span><span class="mord mathit">n</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathit">e</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mpunct">,</span><span class="mord mathrm">4</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mbin">∗</span><span class="mord"><span class="mord mathit">x</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathrm">3</span><span class="mord mathit">i</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mclose">)</span><span class="mbin">+</span><span class="mop"><span class="op-symbol small-op mop" style="top:-.0000050000000000050004em">∑</span><span class="vlist"><span style="top:.30001em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mrel">∈</span><span class="mord mathit">n</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathit" style="margin-right:.10764em">f</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.10764em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mpunct">,</span><span class="mord mathrm">4</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mbin">∗</span><span class="mord"><span class="mord mathit">x</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathrm">4</span><span class="mord mathit">i</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mclose">)</span><span class="mbin">−</span><span class="mord mathit">b</span><span class="mrel">≤</span><span class="mord mathrm">0</span></span></span></span></p><h3 id="dual-constraints"><a class="markdownIt-Anchor" href="#dual-constraints"></a> Dual Constraints</h3><p><span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>λ</mi><mo>≥</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">\lambda \geq 0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:.69444em"></span><span class="strut bottom" style="height:.83041em;vertical-align:-.13597em"></span><span class="base textstyle uncramped"><span class="mord mathit">λ</span><span class="mrel">≥</span><span class="mord mathrm">0</span></span></span></span></p><h3 id="complementary-slackness"><a class="markdownIt-Anchor" href="#complementary-slackness"></a> Complementary Slackness</h3><p><span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>λ</mi><mo>[</mo><msub><mo>∑</mo><mrow><mi>i</mi><mo>∈</mo><mi>n</mi></mrow></msub><mo>(</mo><msub><mi>c</mi><mrow><mi>i</mi><mo separator="true">,</mo><mn>4</mn></mrow></msub><mo>∗</mo><msub><mi>x</mi><mrow><mn>1</mn><mi>i</mi></mrow></msub><mo>)</mo><mo>+</mo><msub><mo>∑</mo><mrow><mi>i</mi><mo>∈</mo><mi>n</mi></mrow></msub><mo>(</mo><msub><mi>d</mi><mrow><mi>i</mi><mo separator="true">,</mo><mn>4</mn></mrow></msub><mo>∗</mo><msub><mi>x</mi><mrow><mn>2</mn><mi>i</mi></mrow></msub><mo>)</mo><mo>+</mo><msub><mo>∑</mo><mrow><mi>i</mi><mo>∈</mo><mi>n</mi></mrow></msub><mo>(</mo><msub><mi>e</mi><mrow><mi>i</mi><mo separator="true">,</mo><mn>4</mn></mrow></msub><mo>∗</mo><msub><mi>x</mi><mrow><mn>3</mn><mi>i</mi></mrow></msub><mo>)</mo><mo>+</mo><msub><mo>∑</mo><mrow><mi>i</mi><mo>∈</mo><mi>n</mi></mrow></msub><mo>(</mo><msub><mi>f</mi><mrow><mi>i</mi><mo separator="true">,</mo><mn>4</mn></mrow></msub><mo>∗</mo><msub><mi>x</mi><mrow><mn>4</mn><mi>i</mi></mrow></msub><mo>)</mo><mo>−</mo><mi>b</mi><mo>]</mo><mo>=</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">\lambda[\sum_{i\in n}(c_{i,4}*x_{1i}) + \sum_{i\in n}(d_{i,4}*x_{2i}) + \sum_{i\in n}(e_{i,4}*x_{3i}) + \sum_{i\in n}(f_{i,4}*x_{4i}) - b]=0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:.75em"></span><span class="strut bottom" style="height:1.07738em;vertical-align:-.32738em"></span><span class="base textstyle uncramped"><span class="mord mathit">λ</span><span class="mopen">[</span><span class="mop"><span class="op-symbol small-op mop" style="top:-.0000050000000000050004em">∑</span><span class="vlist"><span style="top:.30001em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mrel">∈</span><span class="mord mathit">n</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathit">c</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mpunct">,</span><span class="mord mathrm">4</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mbin">∗</span><span class="mord"><span class="mord mathit">x</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathrm">1</span><span class="mord mathit">i</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mclose">)</span><span class="mbin">+</span><span class="mop"><span class="op-symbol small-op mop" style="top:-.0000050000000000050004em">∑</span><span class="vlist"><span style="top:.30001em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mrel">∈</span><span class="mord mathit">n</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathit">d</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mpunct">,</span><span class="mord mathrm">4</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mbin">∗</span><span class="mord"><span class="mord mathit">x</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathrm">2</span><span class="mord mathit">i</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mclose">)</span><span class="mbin">+</span><span class="mop"><span class="op-symbol small-op mop" style="top:-.0000050000000000050004em">∑</span><span class="vlist"><span style="top:.30001em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mrel">∈</span><span class="mord mathit">n</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathit">e</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mpunct">,</span><span class="mord mathrm">4</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mbin">∗</span><span class="mord"><span class="mord mathit">x</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathrm">3</span><span class="mord mathit">i</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mclose">)</span><span class="mbin">+</span><span class="mop"><span class="op-symbol small-op mop" style="top:-.0000050000000000050004em">∑</span><span class="vlist"><span style="top:.30001em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mrel">∈</span><span class="mord mathit">n</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathit" style="margin-right:.10764em">f</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.10764em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mpunct">,</span><span class="mord mathrm">4</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mbin">∗</span><span class="mord"><span class="mord mathit">x</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathrm">4</span><span class="mord mathit">i</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mclose">)</span><span class="mbin">−</span><span class="mord mathit">b</span><span class="mclose">]</span><span class="mrel">=</span><span class="mord mathrm">0</span></span></span></span></p><h3 id="gradient-of-lagrangian-with-respect-to-x-variables"><a class="markdownIt-Anchor" href="#gradient-of-lagrangian-with-respect-to-x-variables"></a> Gradient of Lagrangian With Respect to x Variables</h3><p>\nabla_{x_1} = \sum_{i\in n}g(c_i)+\lambda\sum_{i\in n}c_{i,4}+v_1\textbf{1}^T=0<br>\nabla_{x_2} = \sum_{i\in n}g(d_i)+\lambda\sum_{i\in n}d_{i,4}+v_2\textbf{1}^T=0<br>\nabla_{x_3} = \sum_{i\in n}g(e_i)+\lambda\sum_{i\in n}e_{i,4}+v_3\textbf{1}^T=0<br>\nabla_{x_4} = \sum_{i\in n}g(f_i)+\lambda\sum_{i\in n}f_{i,4}+v_4\textbf{1}^T=0</p><h1 id="intended-approaches"><a class="markdownIt-Anchor" href="#intended-approaches"></a> Intended Approaches</h1><p>In the real world case, a user should be able to select the limitation B<br>value. In our run, we simply set the limitation of B as 2000. And<br>initially, we set all variables to be binary since one computer can only<br>have one components in each machine.</p><h2 id="quality-of-choice"><a class="markdownIt-Anchor" href="#quality-of-choice"></a> Quality of choice</h2><h4 id="why-you-make-choice"><a class="markdownIt-Anchor" href="#why-you-make-choice"></a> Why you make choice</h4><p>There are no previous academic works discussing how to optimally select<br>a computer component combination using linear programming algorithms. As<br>such, we selected to use the benchmark score, sample number, value<br>score, and price to craft what we felt was a reasonable objective<br>function. Our function could reflect the user’s perspective in taking<br>multiple pieces of data about a hardware component into account when<br>making a selection.</p><h4 id="why-this-is-good"><a class="markdownIt-Anchor" href="#why-this-is-good"></a> Why this is good</h4><p>Under normal conditions, we ran the linear programming models under<br>strict constraints, equation (4), of equal to 1 and binary variables. To<br>prove the tightness of relaxation of our solution, we relaxed these<br>constraints to <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mo>≤</mo></mrow><annotation encoding="application/x-tex">\leq</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:.63597em"></span><span class="strut bottom" style="height:.7719400000000001em;vertical-align:-.13597em"></span><span class="base textstyle uncramped"><span class="mrel">≤</span></span></span></span> to 1 and nonnegative variables. After rerunning<br>our experiment with these relaxed constraints and receiving the same<br>solution distribution (all solution vectors contained only zeros and<br>ones, i.e., are binary vectors), we can confidently declare that our<br>model solution is tight enough in our context.</p><p>Since our problem was a linear programming problem, there would always<br>exist an optimal solution as long as the feasible region exists. Because<br>we are always trying to maximum the objective function, which guarantee<br>us to find a valid solution under the given limitation B. We also tested<br>the optimality based on the KKT conditions described in the previous<br>section. We also tried several different B setup, we are able to find a<br>proven optimal solution in all cases. Which proves the optimality of our<br>model.</p><h2 id="novelty"><a class="markdownIt-Anchor" href="#novelty"></a> Novelty</h2><h4 id="difference-from-previous-work"><a class="markdownIt-Anchor" href="#difference-from-previous-work"></a> Difference from previous work</h4><p>There is no work in the previous discussing how to select a computer<br>using linear programming.</p><p>Consumers in the market have to use some search engine and compare each<br>product with days of work previously[@james2006buying]. Right now, we<br>introduced a new way of thinking what to purchase and how to organize<br>the computer in a more efficient way. User could simply run our script<br>with the latest data to get the recommendation with seconds of work. In<br>addition to a traditional scrapping using static web fetching, we also<br>introduced a way to automatically scrapping data from website by using<br>github action. The script is set to run once per three days. And a<br>contemporary way to scrapping website by simulating user behavior to<br>prevent blocking of IP address by using puppeteer. In this way, user is<br>always able to use the latest data to get the optimization result. See<br><a href="https://github.com/ShaokangJiang/CSE-203B-crapping" target="_blank" rel="noopener">here</a> for the auto<br>scrapping repository.</p><p>Our setup of combining the binary vector with the associate price also<br>improves computational time a lot comparing to some intuitive setup of<br>using each components price * each choice vector as the function when<br>calculating the limitation. This reduces the equations required to<br>handle from (Dimension of cpu * Dimension of gpu * Dimension of hdd *<br>Dimension of mem) to only one equation. In the actual experiment, this<br>could reduce computation time from many minutes to 0.016 seconds.</p><h2 id="computational-complexity"><a class="markdownIt-Anchor" href="#computational-complexity"></a> Computational complexity</h2><p>Since our problem was a linear programming problem, previous<br>studies[@karmarkar1984new] have shown that any linear programming is<br>able to run in polynomial-time, so our model should be able to run under<br>polynomial-time. But, since our model only have one dimension in each<br>equation, the actual runtime should be close to O(n). Nevertheless, it<br>is hard to scale the overhead if we have to use mixed integer solver to<br>solve the problem. Fortunately, our model is always able to be converted<br>to a problem using linear programming solver[@raidl2008combining], which<br>guarantees our model to run under O(n). However, it is hard and not<br>necessary to measure a runtime like this. In the real world usage case,<br>running a model like this would spent far more time on context switch<br>and read data from memory instead of doing the actual computation. This<br>could also provide a possible reason that our real tests always show a<br>runtime of 0.016 seconds even with more data and more dimensions.</p><p>The memory space complexity is also O(n) where n is calculated by sum of<br>Dimension of cpu and Dimension of gpu and Dimension of hdd and Dimension<br>of memory.</p><h1 id="conjectured-results-conclusion-and-future-works"><a class="markdownIt-Anchor" href="#conjectured-results-conclusion-and-future-works"></a> Conjectured Results, Conclusion, and Future Works</h1><h2 id="results"><a class="markdownIt-Anchor" href="#results"></a> Results</h2><p>All models are running on an old laptop, which has 2.5 GHz CPU and 8 GB<br>memory. In our setup of limitation as 2000, with the dataset from<br>auto-scrapping result from<br><a href="https://github.com/ShaokangJiang/CSE-203B-crapping" target="_blank" rel="noopener">here</a>. We could<br>reach the following result:</p><p>​ CPU GPU</p><hr><pre><code>          Intel Core i7-6700K                       Nvidia GTX 1060-3GB                                                            SSD                                       RAM</code></pre><p>Corsair Vengeance LPX DDR4 3000 C15 2x8GB Samsung 970 Evo Plus NVMe PCIe M.2 1TB</p><p>The time complexity of using mip solver in GAMS is 0.016 seconds. Time<br>complexity of using lp solvers on GAMS could reach the same result with<br>time complexity of 0.01 seconds. For python setup, the average time<br>consumed for 10 runs is 0.065 seconds.<br>In a run with a more meaningful result with limitation as 400, we could<br>reach the following result:</p><p>​ CPU GPU</p><hr><pre><code>         Intel Core i5-10600K                       Nvidia GTX 1060-3GB                                                            SSD                                       RAM</code></pre><p>Corsair Vengeance LPX DDR4 3000 C15 2x8GB Samsung 970 Evo Plus NVMe PCIe M.2 1TB</p><p>Time complexity stays the same as previous for GAMS. For python setup,<br>the average time consumed for 10 runs is 0.05 seconds.</p><p>By using our way, user is able to get the recommendation result in a<br>fraction of a second instead of manually comparing between various<br>components. We also observed the commercial solvers generally have a<br>better performance than open source solvers on python.</p><h2 id="conclusion"><a class="markdownIt-Anchor" href="#conclusion"></a> Conclusion</h2><p>In this work, we developed a novel and efficient way in finding the best<br>possible computer components pairs for a user to select under a certain<br>budget. By introducing the benchmark, popularity, valuable and price, we<br>formulate the problem as a convex optimization problem which maximizes a<br>customized objective function with the consideration of all four<br>factors. Through experiments under different settings, we show that the<br>proposed convex optimization algorithm could run fast and efficiently<br>generate a good result. Comparing to the previous situation where user<br>have to spent tons of hours in selecting and comparing components when<br>composing a new computer, our way is much more efficient and our model<br>is suitable to run on any computer.</p><h2 id="future-works"><a class="markdownIt-Anchor" href="#future-works"></a> Future Works</h2><p>Based on our current solution, possible future works may search for more<br>meaningful objective functions. This would require additional real world<br>analysis and people have to conduct some user studies to learn which<br>factors among price, benchmark, popularity, and value are most<br>important.</p><p>As part of improving this work, we would like to add more features for<br>improving user interaction experience. Considering the size of this<br>problem, another possible route is to build a static website by using<br>jsLPSolver and host it on GitHub. This would be a low cost way to make<br>general public get access to our study result and benefit a wider<br>audience.</p><p>As our current system automatically updates the data every three days,<br>we utilize the most up-to-date data when searching for the optimal<br>combination. That being said, using a more meaningful combination of<br>data from all up-to-date data may be in the user’s best interest as it<br>potentially allows for better and more meaningful combination results.</p><h1 id="references"><a class="markdownIt-Anchor" href="#references"></a> References</h1><p>[1] Gordon H Bradley. “Transformation of integer programs to knapsack problems”. In: Discrete mathematics 1.1 (1971), pp. 29–45.<br>[2] George B Dantzig. “Linear programming”. In: Operations research 50.1 (2002), pp. 42–47.<br>[3] Richard James. “Buying a computer?” In: ITNOW 48.3 (2006), pp. 24–24.<br>[4] Narendra Karmarkar. “A new polynomial-time algorithm for linear programming”. In: Proceedings of the sixteenth annual ACM symposium on Theory of computing. 1984, pp. 302–311.<br>[5] Nurul Farihan Mohamed et al. “An Integer Linear Programming Model For A Diet Problem Of Medonald’s Sets Menu In Malaysia”. In: 2021.<br>[6] Günther R Raidl and Jakob Puchinger. “Combining (integer) linear programming techniques and metaheuristics for combinatorial optimization”. In: Hybrid metaheuristics: An emerging approach to optimization (2008), pp. 31–62.<br>[7] Alan Sultan. Linear programming: An introduction with applications. Elsevier, 2014.</p><h1 id="original-gams-code"><a class="markdownIt-Anchor" href="#original-gams-code"></a> Original GAMS code</h1><figure class="highlight gams"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">option</span> limrow=<span class="number">0</span>, limcol=<span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">set</span> cpu_model,cpu_para,gpu_model,gpu_para,ssd_model,ssd_para,ram_model,ram_para;</span><br><span class="line"></span><br><span class="line"><span class="keyword">parameter</span></span><br><span class="line">    cpu(cpu_model,cpu_para),</span><br><span class="line">    gpu(gpu_model,gpu_para),</span><br><span class="line">    ssd(ssd_model,ssd_para),</span><br><span class="line">    ram(ram_model,ram_para);</span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line"><span class="meta"><span class="meta-keyword">$gdxin</span> data\cpu.gdx</span></span><br><span class="line"><span class="meta"><span class="meta-keyword">$load</span> cpu_model = Dim1</span></span><br><span class="line"><span class="meta"><span class="meta-keyword">$load</span> cpu_para = Dim2</span></span><br><span class="line"><span class="meta"><span class="meta-keyword">$load</span> cpu = d</span></span><br><span class="line"><span class="meta"><span class="meta-keyword">$gdxin</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta"><span class="meta-keyword">$gdxin</span> data\gpu.gdx</span></span><br><span class="line"><span class="meta"><span class="meta-keyword">$load</span> gpu_model = Dim1</span></span><br><span class="line"><span class="meta"><span class="meta-keyword">$load</span> gpu_para = Dim2</span></span><br><span class="line"><span class="meta"><span class="meta-keyword">$load</span> gpu = d</span></span><br><span class="line"><span class="meta"><span class="meta-keyword">$gdxin</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta"><span class="meta-keyword">$gdxin</span> data\ssd.gdx</span></span><br><span class="line"><span class="meta"><span class="meta-keyword">$load</span> ssd_model = Dim1</span></span><br><span class="line"><span class="meta"><span class="meta-keyword">$load</span> ssd_para = Dim2</span></span><br><span class="line"><span class="meta"><span class="meta-keyword">$load</span> ssd = d</span></span><br><span class="line"><span class="meta"><span class="meta-keyword">$gdxin</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta"><span class="meta-keyword">$gdxin</span> data\ram.gdx</span></span><br><span class="line"><span class="meta"><span class="meta-keyword">$load</span> ram_model = Dim1</span></span><br><span class="line"><span class="meta"><span class="meta-keyword">$load</span> ram_para = Dim2</span></span><br><span class="line"><span class="meta"><span class="meta-keyword">$load</span> ram = d</span></span><br><span class="line"><span class="meta"><span class="meta-keyword">$gdxin</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">scalar</span> B /<span class="number">400</span>/;</span><br><span class="line"><span class="keyword">binary</span> <span class="keyword">variables</span> cpu_i(cpu_model),gpu_i(gpu_model),ssd_i(ssd_model),ram_i(ram_model);</span><br><span class="line"><span class="keyword">variables</span> obj;</span><br><span class="line"></span><br><span class="line"><span class="keyword">equations</span> max, cpu_to1, gpu_to1, ram_to1, ssd_to1, limit;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">max</span></span>..</span><br><span class="line">obj <span class="symbol">=e=</span> <span class="keyword">sum</span>(cpu_model, (cpu_i(cpu_model)*cpu(cpu_model, <span class="string">"bench"</span>)*cpu(cpu_model, <span class="string">"sample"</span>)*cpu(cpu_model, <span class="string">"valuable"</span>))/cpu(cpu_model, <span class="string">"price"</span>))</span><br><span class="line">        +<span class="keyword">sum</span>(gpu_model, (gpu_i(gpu_model)*gpu(gpu_model, <span class="string">"bench"</span>)*gpu(gpu_model, <span class="string">"sample"</span>)*gpu(gpu_model, <span class="string">"valuable"</span>))/gpu(gpu_model, <span class="string">"price"</span>))</span><br><span class="line">        +<span class="keyword">sum</span>(ssd_model, (ssd_i(ssd_model)*ssd(ssd_model, <span class="string">"bench"</span>)*ssd(ssd_model, <span class="string">"sample"</span>)*ssd(ssd_model, <span class="string">"valuable"</span>))/ssd(ssd_model, <span class="string">"price"</span>))</span><br><span class="line">        +<span class="keyword">sum</span>(ram_model, (ram_i(ram_model)*ram(ram_model, <span class="string">"bench"</span>)*ram(ram_model, <span class="string">"sample"</span>)*ram(ram_model, <span class="string">"valuable"</span>))/ram(ram_model, <span class="string">"price"</span>));</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">limit</span></span>..</span><br><span class="line"><span class="keyword">sum</span>(cpu_model,cpu_i(cpu_model)*cpu(cpu_model, <span class="string">"price"</span>)) + <span class="keyword">sum</span>(gpu_model,gpu_i(gpu_model)*gpu(gpu_model, <span class="string">"price"</span>)) + <span class="keyword">sum</span>(ssd_model,ssd_i(ssd_model)*ssd(ssd_model, <span class="string">"price"</span>)) + <span class="keyword">sum</span>(ram_model,ram_i(ram_model)*ram(ram_model, <span class="string">"price"</span>)) <span class="symbol">=l=</span> B;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">cpu_to1</span></span>..</span><br><span class="line"><span class="keyword">sum</span>(cpu_model,cpu_i(cpu_model)) <span class="symbol">=e=</span> <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">gpu_to1</span></span>..</span><br><span class="line"><span class="keyword">sum</span>(gpu_model,gpu_i(gpu_model)) <span class="symbol">=e=</span> <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">ram_to1</span></span>..</span><br><span class="line"><span class="keyword">sum</span>(ram_model,ram_i(ram_model)) <span class="symbol">=e=</span> <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">ssd_to1</span></span>..</span><br><span class="line"><span class="keyword">sum</span>(ssd_model,ssd_i(ssd_model)) <span class="symbol">=e=</span> <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">model</span> hw1_1 /<span class="keyword">all</span>/;</span><br><span class="line"></span><br><span class="line"><span class="keyword">solve</span> hw1_1 <span class="keyword">using</span> mip <span class="keyword">maximizing</span> obj;</span><br><span class="line"><span class="keyword">display</span> cpu_i.l, gpu_i.l, ram_i.l, ssd_i.l, obj.l;</span><br></pre></td></tr></table></figure><h1 id="browser-scrapping-code"><a class="markdownIt-Anchor" href="#browser-scrapping-code"></a> Browser scrapping code</h1><p>A sample usage of puppeteer to scrap some simple information. It can avoid being blocked based on IP frequency.</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> puppeteer = <span class="built_in">require</span>(<span class="string">'puppeteer'</span>);</span><br><span class="line"><span class="keyword">const</span> urlencode = <span class="built_in">require</span>(<span class="string">'urlencode'</span>);</span><br><span class="line"><span class="keyword">const</span> HTMLParser = <span class="built_in">require</span>(<span class="string">'node-html-parser'</span>);</span><br><span class="line"><span class="keyword">const</span> core = <span class="built_in">require</span>(<span class="string">'@actions/core'</span>);</span><br><span class="line"><span class="keyword">const</span> UIDGenerator = <span class="built_in">require</span>(<span class="string">'uid-generator'</span>);</span><br><span class="line"><span class="keyword">const</span> uidgen = <span class="keyword">new</span> UIDGenerator();</span><br><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">'fs'</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> browser;</span><br><span class="line"><span class="keyword">var</span> url = <span class="literal">undefined</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">replaceAll</span>(<span class="params">originalString, find, replace</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> originalString.replace(<span class="keyword">new</span> <span class="built_in">RegExp</span>(find, <span class="string">'g'</span>), replace);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">mainFunction1</span>(<span class="params">name</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// use try catch without timeout at here</span></span><br><span class="line">    <span class="comment">// const browser = await puppeteer.launch(&#123; headless: true , args: [`--no-sandbox`, `--disable-setuid-sandbox`]&#125;);\</span></span><br><span class="line">    <span class="keyword">let</span> screenshot = <span class="literal">false</span>;</span><br><span class="line">    <span class="keyword">let</span> hrstart = process.hrtime();</span><br><span class="line">    browser = <span class="keyword">await</span> puppeteer.launch(&#123; <span class="attr">headless</span>: <span class="literal">true</span> &#125;);</span><br><span class="line">    <span class="keyword">const</span> page = <span class="keyword">await</span> browser.newPage();</span><br><span class="line">    <span class="comment">// await page.setDefaultNavigationTimeout(500000);</span></span><br><span class="line">    <span class="keyword">await</span> page.setViewport(&#123; <span class="attr">width</span>: <span class="number">1920</span>, <span class="attr">height</span>: <span class="number">1080</span> &#125;);</span><br><span class="line">    <span class="keyword">await</span> page.setRequestInterception(<span class="literal">true</span>);</span><br><span class="line"></span><br><span class="line">    page.on(<span class="string">'request'</span>, (req) =&gt; &#123;</span><br><span class="line">        <span class="keyword">if</span> (req.resourceType() === <span class="string">'image'</span> || req.resourceType() === <span class="string">'media'</span>) &#123;</span><br><span class="line">            req.abort();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> &#123;</span><br><span class="line">            req.continue();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> hrend = process.hrtime(hrstart);</span><br><span class="line"></span><br><span class="line">    core.info(<span class="string">"Start the first page, browser initialized in "</span> + hrend[<span class="number">0</span>] + <span class="string">"s"</span>)</span><br><span class="line"></span><br><span class="line">    hrstart = process.hrtime();</span><br><span class="line">    <span class="keyword">try</span> &#123;<span class="comment">// wait for 60 seconds</span></span><br><span class="line">        <span class="keyword">await</span> page.goto(<span class="string">'https://'</span> + name + <span class="string">'.userbenchmark.com/'</span>, &#123; <span class="attr">waitUntil</span>: <span class="string">'networkidle2'</span>, <span class="attr">timeout</span>: <span class="number">60000</span> &#125;); <span class="comment">// wait until page load</span></span><br><span class="line">    &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">        core.error(<span class="string">"Wait too long for login page, terminating the program"</span>)</span><br><span class="line">        <span class="keyword">await</span> browser.close();</span><br><span class="line">        core.setFailed(<span class="string">`Action failed with error <span class="subst">$&#123;e&#125;</span>`</span>);</span><br><span class="line">        process.exit(<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// await page.waitForTimeout(2000000);</span></span><br><span class="line">    hrend = process.hrtime(hrstart);</span><br><span class="line">    core.info(<span class="string">"Finish loading the first page, first page loaded in "</span> + hrend[<span class="number">0</span>] + <span class="string">"s"</span>)</span><br><span class="line">    core.info(<span class="string">"Start to get "</span> + name + <span class="string">" info"</span>);</span><br><span class="line">    <span class="keyword">let</span> message = <span class="keyword">await</span> page.evaluate(<span class="keyword">async</span> () =&gt; &#123;</span><br><span class="line">        <span class="function"><span class="keyword">function</span> <span class="title">handleNumber</span>(<span class="params">num</span>) </span>&#123;</span><br><span class="line">            <span class="keyword">if</span> (num.indexOf(<span class="string">"k"</span>) != <span class="number">-1</span>) &#123;</span><br><span class="line">                <span class="keyword">return</span> (<span class="built_in">parseFloat</span>(num) * <span class="number">1000</span>).toFixed(<span class="number">0</span>);</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (num.indexOf(<span class="string">"M"</span>) != <span class="number">-1</span>) &#123;</span><br><span class="line">                <span class="keyword">return</span> (<span class="built_in">parseFloat</span>(num) * <span class="number">1000</span> * <span class="number">1000</span>).toFixed(<span class="number">0</span>);</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">return</span> (<span class="built_in">parseFloat</span>(num)).toFixed(<span class="number">0</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">let</span> toRe = <span class="string">""</span>;</span><br><span class="line">        <span class="built_in">document</span>.querySelector(<span class="string">"[data-mhth='MC_PRICE']"</span>).click()</span><br><span class="line">        <span class="keyword">let</span> counter = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">while</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">            counter++;</span><br><span class="line">            <span class="keyword">if</span> (counter &gt;= <span class="number">60</span>) <span class="keyword">return</span> <span class="string">"Error"</span>;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">7</span>; i++) &#123;</span><br><span class="line">                <span class="keyword">await</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="params">resolve</span> =&gt;</span> setTimeout(resolve, <span class="number">1000</span> + <span class="built_in">Math</span>.random() * <span class="number">1500</span>));</span><br><span class="line">                <span class="built_in">window</span>.scrollTo(<span class="built_in">window</span>.scrollX, <span class="built_in">window</span>.scrollY + <span class="number">500</span> + <span class="built_in">Math</span>.random() * <span class="number">300</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> <span class="built_in">document</span>.getElementsByClassName(<span class="string">"hovertarget"</span>)) &#123;</span><br><span class="line">                <span class="keyword">let</span> lists = i.getElementsByTagName(<span class="string">"td"</span>);</span><br><span class="line">                <span class="keyword">let</span> tempStr = lists[<span class="number">1</span>].innerText.split(<span class="string">"\n"</span>);</span><br><span class="line">                <span class="comment">//name,price,sample,valuable,bench,bench_low,bench_high</span></span><br><span class="line">                <span class="keyword">if</span> (lists[lists.length - <span class="number">1</span>].innerText.trim().length == <span class="number">0</span>)</span><br><span class="line">                    <span class="keyword">return</span> toRe;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">if</span> (tempStr[<span class="number">1</span>].indexOf(<span class="string">"$"</span>) == <span class="number">-1</span>) &#123;</span><br><span class="line">                    toRe += tempStr[<span class="number">1</span>].trim()</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    toRe += tempStr[<span class="number">1</span>].substring(<span class="number">0</span>, tempStr[<span class="number">1</span>].indexOf(<span class="string">"$"</span>)).trim()</span><br><span class="line">                &#125;</span><br><span class="line">                toRe += <span class="string">","</span> + lists[lists.length - <span class="number">1</span>].innerText.split(<span class="string">"\n"</span>)[<span class="number">0</span>].replace(<span class="string">"$"</span>, <span class="string">""</span>).trim().replace(<span class="string">","</span>, <span class="string">""</span>) + <span class="string">","</span> + handleNumber(tempStr[<span class="number">2</span>].replace(<span class="string">"Samples"</span>, <span class="string">""</span>).trim()) + <span class="string">","</span> + lists[<span class="number">3</span>].innerText.split(<span class="string">"\n"</span>)[<span class="number">0</span>].trim();</span><br><span class="line">                tempStr = lists[<span class="number">4</span>].innerText.split(<span class="string">"\n"</span>);</span><br><span class="line">                toRe += <span class="string">","</span> + tempStr[<span class="number">0</span>] + <span class="string">","</span> + tempStr[<span class="number">1</span>].split(<span class="string">"-"</span>)[<span class="number">0</span>].trim() + <span class="string">","</span> + tempStr[<span class="number">1</span>].split(<span class="string">"-"</span>)[<span class="number">1</span>].trim() + <span class="string">"\n"</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="built_in">document</span>.getElementsByClassName(<span class="string">"pagination pagination-lg"</span>)[<span class="number">0</span>].lastElementChild.firstChild.click()</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="keyword">if</span> (message.localeCompare(<span class="string">"Error"</span>) == <span class="number">0</span>) <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">"Error happened"</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">await</span> browser.close();</span><br><span class="line">    <span class="keyword">return</span> message;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">main</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="keyword">let</span> hrstart = process.hrtime();</span><br><span class="line">        <span class="keyword">let</span> requests = [<span class="string">"cpu"</span>, <span class="string">"gpu"</span>, <span class="string">"ssd"</span>, <span class="string">"hdd"</span>, <span class="string">"ram"</span>];</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> requests) &#123;</span><br><span class="line">            <span class="keyword">let</span> mainMessage;</span><br><span class="line">            <span class="keyword">let</span> count = <span class="number">1</span>;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                mainMessage = <span class="keyword">await</span> mainFunction1(i);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">                core.error(<span class="string">"Error happened: "</span> + e + <span class="string">", try again"</span>);</span><br><span class="line">                count = count + <span class="number">1</span>;</span><br><span class="line">                <span class="keyword">await</span> browser.close();</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    mainMessage = <span class="keyword">await</span> mainFunction1(i);</span><br><span class="line">                &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">                    core.error(<span class="string">"Error happened: "</span> + e + <span class="string">", try again"</span>);</span><br><span class="line">                    count = count + <span class="number">1</span>;</span><br><span class="line">                    <span class="keyword">await</span> browser.close();</span><br><span class="line">                    mainMessage = <span class="keyword">await</span> mainFunction1(i);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">let</span> hrend = process.hrtime(hrstart);</span><br><span class="line">            core.info(<span class="string">"Done "</span> + i + <span class="string">" in "</span> + hrend)</span><br><span class="line">            <span class="comment">// console.log(mainMessage);</span></span><br><span class="line">            <span class="keyword">if</span> (!fs.existsSync(<span class="string">'./data'</span>)) &#123;</span><br><span class="line">                <span class="keyword">await</span> fs.mkdirSync(<span class="string">'./data'</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">await</span> fs.writeFile(<span class="string">"./data/"</span> + i + <span class="string">".csv"</span>, <span class="string">"name,price,sample,valuable,bench,bench_low,bench_high\n"</span> + mainMessage, <span class="function"><span class="keyword">function</span> (<span class="params">err</span>) </span>&#123;</span><br><span class="line">                <span class="keyword">if</span> (err) &#123;</span><br><span class="line">                    <span class="keyword">return</span> core.info(err);</span><br><span class="line">                &#125;</span><br><span class="line">                core.info(i + <span class="string">".csv was saved!"</span>);</span><br><span class="line">            &#125;);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">        <span class="keyword">await</span> browser.close();</span><br><span class="line">        core.setFailed(<span class="string">`Action failed with error <span class="subst">$&#123;e&#125;</span>`</span>);</span><br><span class="line">        process.exit(<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">main();</span><br></pre></td></tr></table></figure>]]></content:encoded>
      
      
      <category domain="https://shaokang.me/categories/optimization/">optimization</category>
      
      
      <category domain="https://shaokang.me/tags/GAMS/">GAMS</category>
      
      <category domain="https://shaokang.me/tags/LP/">LP</category>
      
      <category domain="https://shaokang.me/tags/NodeJs/">NodeJs</category>
      
      
      <comments>https://shaokang.me/2023/An-economical-computer/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Build VSCode extension</title>
      <link>https://shaokang.me/2022/Build-VSCode-extension/</link>
      <guid>https://shaokang.me/2022/Build-VSCode-extension/</guid>
      <pubDate>Tue, 27 Dec 2022 23:50:50 GMT</pubDate>
      
      <description>&lt;p&gt;To help people verify the correctness of their code in two of my research projects, I built a VSCode extension. Here is the script for adding a simple code lens to VSCode, making it clickable for people to check the correctness of their code. The result will be put in the terminal area. Participants were also able to click a fixed button or use a command prompt to test correctness by using this extension.&lt;/p&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p>To help people verify the correctness of their code in two of my research projects, I built a VSCode extension. Here is the script for adding a simple code lens to VSCode, making it clickable for people to check the correctness of their code. The result will be put in the terminal area. Participants were also able to click a fixed button or use a command prompt to test correctness by using this extension.<a id="more"></a></p><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// The module 'vscode' contains the VS Code extensibility API</span></span><br><span class="line"><span class="comment">// Import the module and reference it with the alias vscode in your code below</span></span><br><span class="line"><span class="keyword">import</span> &#123; ExtensionContext, languages, commands, Disposable, workspace, <span class="built_in">window</span> &#125; <span class="keyword">from</span> <span class="string">'vscode'</span>;</span><br><span class="line"><span class="keyword">import</span> * <span class="keyword">as</span> vscode <span class="keyword">from</span> <span class="string">'vscode'</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// this method is called when your extension is activated</span></span><br><span class="line"><span class="comment">// your extension is activated the very first time the command is executed</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> disposables: Disposable[] = [];</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> CodelensProvider <span class="keyword">implements</span> vscode.CodeLensProvider &#123;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span> _onDidChangeCodeLenses: vscode.EventEmitter&lt;<span class="built_in">void</span>&gt; = <span class="keyword">new</span> vscode.EventEmitter&lt;<span class="built_in">void</span>&gt;();</span><br><span class="line"><span class="keyword">public</span> readonly onDidChangeCodeLenses: vscode.Event&lt;<span class="built_in">void</span>&gt; = <span class="keyword">this</span>._onDidChangeCodeLenses.event;</span><br><span class="line"></span><br><span class="line"><span class="keyword">constructor</span>(<span class="params"></span>) &#123;</span><br><span class="line">vscode.workspace.onDidChangeConfiguration(<span class="function">(<span class="params">_</span>) =&gt;</span> &#123;</span><br><span class="line"><span class="keyword">this</span>._onDidChangeCodeLenses.fire();</span><br><span class="line">&#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> provideCodeLenses(<span class="built_in">document</span>: vscode.TextDocument, token: vscode.CancellationToken): vscode.CodeLens[] | Thenable&lt;vscode.CodeLens[]&gt; &#123;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (vscode.workspace.getConfiguration(<span class="string">"survey-helper"</span>).get(<span class="string">"enableCodeLens"</span>, <span class="literal">true</span>)) &#123;</span><br><span class="line"><span class="keyword">let</span> lines = <span class="built_in">document</span>.getText().split(<span class="string">"\n"</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> line = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; lines.length; i++) &#123;</span><br><span class="line"><span class="keyword">if</span> (lines[i].startsWith(<span class="string">"class Solution:"</span>)) &#123; line = i; &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Define what command we want to trigger when activating the CodeLens</span></span><br><span class="line"><span class="keyword">let</span> test: vscode.Command = &#123;</span><br><span class="line">command: <span class="string">"survey-helper.test"</span>,</span><br><span class="line">title: <span class="string">"Test"</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> submit: vscode.Command = &#123;</span><br><span class="line">command: <span class="string">"survey-helper.submit"</span>,</span><br><span class="line">title: <span class="string">"Submit"</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> codeLens = <span class="keyword">new</span> vscode.CodeLens(<span class="keyword">new</span> vscode.Range(<span class="keyword">new</span> vscode.Position(line, <span class="number">0</span>), <span class="keyword">new</span> vscode.Position(line, <span class="number">5</span>)), test);</span><br><span class="line"><span class="keyword">let</span> codeLens1 = <span class="keyword">new</span> vscode.CodeLens(<span class="keyword">new</span> vscode.Range(<span class="keyword">new</span> vscode.Position(line, <span class="number">6</span>), <span class="keyword">new</span> vscode.Position(line, <span class="number">11</span>)), submit);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> [codeLens, codeLens1];</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> [];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> resolveCodeLens(codeLens: vscode.CodeLens, token: vscode.CancellationToken) &#123;</span><br><span class="line"><span class="keyword">if</span> (vscode.workspace.getConfiguration(<span class="string">"survey-helper"</span>).get(<span class="string">"enableCodeLens"</span>, <span class="literal">true</span>)) &#123;</span><br><span class="line"><span class="keyword">return</span> codeLens;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">activate</span>(<span class="params">context: ExtensionContext</span>) </span>&#123;</span><br><span class="line"><span class="keyword">const</span> codelensProvider = <span class="keyword">new</span> CodelensProvider();</span><br><span class="line"></span><br><span class="line">languages.registerCodeLensProvider(<span class="string">"*"</span>, codelensProvider);</span><br><span class="line"></span><br><span class="line">commands.registerCommand(<span class="string">"survey-helper.enableCodeLens"</span>, <span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">workspace.getConfiguration(<span class="string">"survey-helper"</span>).update(<span class="string">"enableCodeLens"</span>, <span class="literal">true</span>, <span class="literal">true</span>);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">commands.registerCommand(<span class="string">"survey-helper.disableCodeLens"</span>, <span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">workspace.getConfiguration(<span class="string">"survey-helper"</span>).update(<span class="string">"enableCodeLens"</span>, <span class="literal">false</span>, <span class="literal">true</span>);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Use the console to output diagnostic information (console.log) and errors (console.error)</span></span><br><span class="line"><span class="comment">// This line of code will only be executed once when your extension is activated</span></span><br><span class="line"><span class="comment">// console.log('Congratulations, your extension "survey-helper" is now active in the web extension host!');</span></span><br><span class="line"><span class="comment">//Create output channel</span></span><br><span class="line"><span class="keyword">let</span> survey = vscode.window.createOutputChannel(<span class="string">"survey-helper"</span>);</span><br><span class="line"><span class="comment">//Write to output.</span></span><br><span class="line">survey.appendLine(<span class="string">"Start services"</span>);</span><br><span class="line"><span class="comment">// The command has been defined in the package.json file</span></span><br><span class="line"><span class="comment">// Now provide the implementation of the command with registerCommand</span></span><br><span class="line"><span class="comment">// The commandId parameter must match the command field in package.json</span></span><br><span class="line"><span class="keyword">let</span> disposable = vscode.commands.registerCommand(<span class="string">'survey-helper.test'</span>, <span class="keyword">async</span> () =&gt; &#123;</span><br><span class="line"><span class="comment">// The code you place here will be executed every time your command is executed</span></span><br><span class="line"><span class="keyword">const</span> editor = vscode.window.activeTextEditor;</span><br><span class="line"><span class="keyword">if</span> (editor) &#123;</span><br><span class="line"><span class="keyword">let</span> <span class="built_in">document</span> = editor.document;</span><br><span class="line"><span class="comment">// Get the document text</span></span><br><span class="line"><span class="keyword">let</span> documentText = <span class="built_in">document</span>.getText();</span><br><span class="line"><span class="keyword">await</span> <span class="built_in">document</span>.save();</span><br><span class="line"><span class="keyword">if</span> (vscode.workspace.getConfiguration(<span class="string">'survey-helper'</span>).get(<span class="string">"endpoint"</span>) !== <span class="string">"null"</span>) &#123;</span><br><span class="line"><span class="keyword">let</span> response: Response = <span class="keyword">await</span> fetch(<span class="built_in">String</span>(vscode.workspace.getConfiguration(<span class="string">'survey-helper'</span>).get(<span class="string">"endpoint"</span>)) + <span class="string">"/test?problem_id="</span> + <span class="built_in">document</span>.fileName.replace(<span class="regexp">/^.*[\\\/]/</span>, <span class="string">''</span>).charAt(<span class="number">0</span>), &#123; method: <span class="string">'GET'</span> &#125;);</span><br><span class="line"><span class="keyword">let</span> testResult = <span class="keyword">await</span> response.json();</span><br><span class="line"><span class="keyword">let</span> dateOb = <span class="keyword">new</span> <span class="built_in">Date</span>();</span><br><span class="line"><span class="comment">// current hours</span></span><br><span class="line"><span class="keyword">let</span> hours = dateOb.getHours();</span><br><span class="line"><span class="comment">// current minutes</span></span><br><span class="line"><span class="keyword">let</span> minutes = dateOb.getMinutes();</span><br><span class="line"><span class="comment">// current seconds</span></span><br><span class="line"><span class="keyword">let</span> seconds = dateOb.getSeconds();</span><br><span class="line"><span class="comment">// prints date &amp; time in YYYY-MM-DD HH:MM:SS format</span></span><br><span class="line">survey.appendLine(<span class="string">"["</span> + hours + <span class="string">":"</span> + minutes + <span class="string">":"</span> + seconds + <span class="string">"] Test output:\nTime elapsed: "</span> + testResult[<span class="string">"time_elapsed"</span>] + <span class="string">"\nResult:\n"</span> + testResult[<span class="string">"msg"</span>]);</span><br><span class="line">survey.show();</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line"><span class="comment">// Display a message box to the user</span></span><br><span class="line">vscode.window.showInformationMessage(<span class="string">'Please configure endpoint before run'</span>);</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;);</span><br><span class="line">context.subscriptions.push(disposable);</span><br><span class="line"></span><br><span class="line">disposable = vscode.commands.registerCommand(<span class="string">'survey-helper.submit'</span>, <span class="keyword">async</span> () =&gt; &#123;</span><br><span class="line"><span class="comment">// The code you place here will be executed every time your command is executed</span></span><br><span class="line"><span class="keyword">if</span> (vscode.workspace.getConfiguration(<span class="string">'survey-helper'</span>).get(<span class="string">"endpoint"</span>) !== <span class="string">"null"</span>) &#123;</span><br><span class="line"><span class="keyword">const</span> editor = vscode.window.activeTextEditor;</span><br><span class="line"><span class="keyword">if</span> (editor) &#123;</span><br><span class="line"><span class="keyword">let</span> <span class="built_in">document</span> = editor.document;</span><br><span class="line"><span class="comment">// Get the document text</span></span><br><span class="line"><span class="keyword">let</span> documentText = <span class="built_in">document</span>.getText();</span><br><span class="line"><span class="keyword">await</span> <span class="built_in">document</span>.save();</span><br><span class="line"><span class="keyword">let</span> response: Response = <span class="keyword">await</span> fetch(<span class="built_in">String</span>(vscode.workspace.getConfiguration(<span class="string">'survey-helper'</span>).get(<span class="string">"endpoint"</span>)) + <span class="string">"/submit?problem_id="</span> + <span class="built_in">document</span>.fileName.replace(<span class="regexp">/^.*[\\\/]/</span>, <span class="string">''</span>).charAt(<span class="number">0</span>), &#123; method: <span class="string">'GET'</span> &#125;);</span><br><span class="line"><span class="keyword">let</span> testResult = <span class="keyword">await</span> response.json();</span><br><span class="line"><span class="keyword">let</span> dateOb = <span class="keyword">new</span> <span class="built_in">Date</span>();</span><br><span class="line"><span class="comment">// current hours</span></span><br><span class="line"><span class="keyword">let</span> hours = dateOb.getHours();</span><br><span class="line"><span class="comment">// current minutes</span></span><br><span class="line"><span class="keyword">let</span> minutes = dateOb.getMinutes();</span><br><span class="line"><span class="comment">// current seconds</span></span><br><span class="line"><span class="keyword">let</span> seconds = dateOb.getSeconds();</span><br><span class="line"><span class="comment">// prints date &amp; time in YYYY-MM-DD HH:MM:SS format</span></span><br><span class="line">survey.appendLine(<span class="string">"["</span> + hours + <span class="string">":"</span> + minutes + <span class="string">":"</span> + seconds + <span class="string">"] Submission Result:\nTime elapsed: "</span> + testResult[<span class="string">"time_elapsed"</span>] + <span class="string">"\nResult:\n"</span> + testResult[<span class="string">"msg"</span>]);</span><br><span class="line">survey.show();</span><br><span class="line">&#125;</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line"><span class="comment">// Display a message box to the user</span></span><br><span class="line">vscode.window.showInformationMessage(<span class="string">'Please configure endpoint before run'</span>);</span><br><span class="line">&#125;</span><br><span class="line">&#125;);</span><br><span class="line">context.subscriptions.push(disposable);</span><br><span class="line"></span><br><span class="line">disposable = vscode.commands.registerCommand(<span class="string">'survey-helper.hello'</span>, <span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line"><span class="comment">// The code you place here will be executed every time your command is executed</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Display a message box to the user</span></span><br><span class="line"></span><br><span class="line">vscode.window.showInformationMessage(<span class="string">'Hello World from survey_helper in a web extension host!'</span>);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">context.subscriptions.push(disposable);</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// this method is called when your extension is deactivated</span></span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">deactivate</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line"><span class="keyword">if</span> (disposables) &#123;</span><br><span class="line">disposables.forEach(<span class="function"><span class="params">item</span> =&gt;</span> item.dispose());</span><br><span class="line">&#125;</span><br><span class="line">disposables = [];</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content:encoded>
      
      
      <category domain="https://shaokang.me/categories/NodeJs/">NodeJs</category>
      
      
      
      <comments>https://shaokang.me/2022/Build-VSCode-extension/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Python type hint in Competitive Programming</title>
      <link>https://shaokang.me/2022/Whether-Python-Type-Hints-are-helpful-for-competitive-programmers-CP/</link>
      <guid>https://shaokang.me/2022/Whether-Python-Type-Hints-are-helpful-for-competitive-programmers-CP/</guid>
      <pubDate>Fri, 23 Dec 2022 09:38:49 GMT</pubDate>
      
      <description>&lt;p&gt;&lt;em&gt;Are Python Type Hints helpful in competitive programming?&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Abstract&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Type hinting, which is a way to statically indicate the type of a value in the code, was introduced in Python 3.5. Before Python 3.5, python was a dynamic language in which variable type can only be inferred during runtime. Competitive programmers(CP) are a neglected group of people who need to solve algorithm challenges as fast as possible. In this project, we are trying to assess if using Type Hints is helpful for competitive programmers. We conducted a pilot study with 5 programmers from different backgrounds, 1 of them only provided interview data. We found that type hints may not be useful for CP in Python, and autocomplete suggestions are often not good enough to be accepted. The survey indicates that People also dislike type hints in Python for CP tasks. &lt;em&gt;Keywords:&lt;/em&gt; Type hint. Competitive programmer. Python. Autocomplete.&lt;/p&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p><em>Are Python Type Hints helpful in competitive programming?</em></p><p><strong>Abstract</strong></p><p>Type hinting, which is a way to statically indicate the type of a value in the code, was introduced in Python 3.5. Before Python 3.5, python was a dynamic language in which variable type can only be inferred during runtime. Competitive programmers(CP) are a neglected group of people who need to solve algorithm challenges as fast as possible. In this project, we are trying to assess if using Type Hints is helpful for competitive programmers. We conducted a pilot study with 5 programmers from different backgrounds, 1 of them only provided interview data. We found that type hints may not be useful for CP in Python, and autocomplete suggestions are often not good enough to be accepted. The survey indicates that People also dislike type hints in Python for CP tasks. <em>Keywords:</em> Type hint. Competitive programmer. Python. Autocomplete.<a id="more"></a></p><p>Original PDF:</p><div class="row"><embed src="main.pdf" width="100%" height="550" type="application/pdf"></div><p>Rendered pure text:</p><p>Introduction<br>Competitive programming (CP) is the sport of solving algorithmic puzzles. The International<br>Collegiate Programming Contest (ICPC) is a global CP contest for college students. ICPC has been<br>around since 1977 and its world finals is highly competitive. Successful contestants must possess<br>different kinds of ability to be able to succeed in CP competitions. On one hand, participants have<br>know a wide variety of algorithms and tricks, so that the program written solves the task correctly<br>and executes within the given time and space bound.On the other hand, the participants must be<br>able to implement programs fast, as they are competing against each other in real time.<br>Coding interviews questions are often an easier version of CP puzzles, tech companies use these<br>questions to evaluate software developer applicants’ proficiency in algorithms and programming. Although<br>it is not competitive, interviewees are still required to be able to come up with a correct<br>algorithm, and produce bug-free code in a short amount of time.<br>Historically, Python is not used or taught as a competitive programming language. Python is an<br>interpreted langauge, and is slower in execution compared to compiled programming langauges such as<br>C++ and Java. For this reason, Python is often ignored when it comes to competitive programming,<br>where execution time and space is limited. The appearance of the JIT compiler pypy reduced the<br>execution time of Python scripts by 5 time compared to CPython [1], which makes doing competitive<br>programming in python a possibility. We observed some advanced competitive programmers switching<br>to Python for easier problems for its expressive syntax and easy to use library.<br>Another difference between C++ and Python is the type system. While C++ is statically typed,<br>Python is a dynamically typed. In Python version 3.5, type hints are introduced for Python. Programmers<br>can annotate variables and functions with type information. Some tools, including the Pylance<br>extension in VSCode, are able to utilize type hints to provide type checker support and generate more<br>comprehensive autocomplete suggestions, effectively making Python statically typed [2].</p><p>a : int = 0<br>def isLower(a : str) -&gt; list[bool]:<br>return [c.islower() for c in a]<br>There is a lot of resource on the different algorithms used in programming contests and interviews,<br>including online judge Codeforces [3], interview preparation site LeetCode [4] etc… There are also<br>research about how to effectively teach these algorithms [5] [6]. However, the topic of implementation<br>speed is rarely talked about. In this paper, we focus on how Python type hints affect the speed in<br>which competitive programmers implement algorithms.<br>In this paper, we conducted a study on the research question:<br>RQ Is Python Type Hint helpful in competitive programming?</p><p>Based on this research question, we are specifically interested in the following sub questions:<br>RQ1 Does type hint help contenstants complete problems faster in CP?<br>RQ2 Does type hint help contenstants do first-time implementation faster in CP?<br>RQ3 Does type hint help contenstants debug faster in CP?<br>RQ4 Do autocomplete suggestions help when type hints were added in CP?<br>RQ5 What is the sentiment towards using type hints, type checker, and autocomplete suggestions in<br>CP?<br>We designed and conducted a 2-by-2 pilot experiment with four participants. Then, we observed<br>the effect of different aspects of typing in Python on the programmer.<br>Section 2 will introduce the method of the experiment. Section 3 will present the results from the<br>pilot experiments. Section 4 will mention the limitation and threats to validity of our experiements.<br>Section 5 will discuss and interpret the results in detail.</p><p>Method<br>This section will breifly talking about structure of the study and the working environment of our<br>study. A sample material, contains all paper material for one participant, is available at sample study<br>material. The algorithm challenge question statement and strater code is available at question list<br>2.1 Recruitment process<br>As a pilot study and limited by the time scope, we didn’t do a formal recruit process. But we<br>still try to find people who meet our traits below: a) Collegestudents/recent graduates. b) Have a<br>Codeforcesrating of 1200 to 1500 or ”equivalent” Leetcoderating per problem count. c) Did algorithm<br>challenge (Leetcode/Codeforces/etc) in Python before. d) familiar with python. e) Have not used<br>python type hint before. f) The current primary language is python. This study is designed to send<br>pre-study questionair and recruit from Codeforces/Leetcodeplatform, ICPC Clubs, LeetcodePractice<br>groups.<br>To assure participants meet the requirement, we provide a pre-study questionair, which includes<br>some python coding questions, like correct python codes, generate expected output. And some<br>questions asking about their experience with python.<br>2.2 Study Procedure<br>Entire procedure at a glance Fig. 1 shows the basic procedure for the entire study. An experiement<br>is a 15 minute algorithm challenge and participants need to finish it on our provided platform. They<br>are able to read question and understand algorithm before they click start. At the very beginning<br>of the study, participants are required to 1) Install Zoom, Chromium based browser, Tampermonkey<br>extension for Chrome 2) Install survey-helper Tampermonkey extension 3) Join the provided link. 4)<br>Install the survey_helper VSCode extension and configure the submission endpoint in settings.<br>Training Problem A training problem will be provided in this part to help participants get familiar<br>with our study environment, which is built on top of VScode, refer to Fig. 2 for more info.</p><p>Condition 1 experiement An experiement where using type hints<br>is not permitted. Any function related to type hints will be turned<br>off. We are going to provide a strater code which doesn’t have<br>any type hints as well. Pylance type checking mode will be set to<br>”basic”.<br>Type Hints Training In this part, we teach what is the type hints<br>and how to use the desired features. We also provide one warm-up<br>questions at the end for participants to practice before the formal<br>start.<br>Condition 2 experiement An experiement where using type hints<br>is permitted. We are going to provide a strater code which type<br>hints. And Pylance type checking mode will be set to ”basic”. And<br>participants are required to resolve all type checking warnings<br>In the actual study, condition1 and condition2 might be swapped<br>to reduce learning effect.<br>Semi-structured interview This interview contains around 10 questions<br>to let participants talk about their experience and feelings.<br>The detailed questions list can be checked from our sample study<br>material.</p><p>Workspace Fig. 2 shows a sample participant screen. When participants are ready, they can click<br>the start button. During the study, they need to press test/submit button in multiple places to send<br>their code to our server and judge. The server result will be printed in the ”survey-helper” output<br>channel in their working space. Participants will receive notifications when there are 5 minutes left<br>and 10 minutes left.<br>Once 15 minutes time countdown finished, workspace will do a final submission and workspace will<br>be closed automatically. A new window will pop out for participants to download the recorded data<br>from their local browser. And we will kindly ask participants to send data back to us. Participants<br>always have the right to check the recorded data before sending to us.</p><p>Questions selection and arrangement As a competitive programming challenging, algorithm challengings<br>are the core. For all problems, we follow icpc problem format and select simple (600 1000<br>CF rating) but require non-trivial work (e.g.use special data structure) to complete. We will provide<br>enough challenges that the participants won’t be able to finish in the 15-mins time window. Because<br>we are assessing type hints’ usage instead of really challenging participants, we also provide tutorials<br>for each question, which might include text/pseudocode. So participants won’t get stuck if they don’t<br>know the answer. In order to make sure participants want to finish as much question as possible, we<br>provide incentive for each successfully completed challenge.<br>In terms of question arrangement, We gave each participant a different question configuration to<br>reduce the problem difficulty effect. We also reordered the questions to avoid learning effect. Table.<br>1 shows the actual question order participants was doing.</p><p>Function signature In the experiment, we want to assess a situation where people need to manually<br>type type hints to reach functionality related to type hints. The intuition of doing this is that we are<br>kindly considering whether type hint is useful under a worst case scenario, where participants need to<br>manually type it. In most cases in the real world, people have the ability to reach some intelligent<br>tools, such as pylance, which will infer some types automatically in the background. Sample provided<br>function signature’s different is shown in Fig. 3.<br>In order to enforce participants not using any type hints in condition1 and using type hints in<br>condition2, we provide different function header for each part for the same question. For condition1,<br>we want to simulate an environment with the minimal intelligent typeinference. We observed that<br>removing type hints in the function signature greatly reduces Pylance’s ability to infer types. By using<br>this way, we minimize variable-relevant autocomplete. In part2, by adding type hints in the function<br>signature and permit participant to use type hints, we can observe if type hints is useful.<br>class Solution:<br>def arrayMedium(self, arr):</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">arrayMedium</span><span class="params">(self, arr)</span>:</span></span><br><span class="line">        <span class="comment"># Write your solution here</span></span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line">    <span class="class"><span class="keyword">class</span> <span class="title">Solution</span>:</span></span><br><span class="line">        <span class="function"><span class="keyword">def</span> <span class="title">arrayMedium</span><span class="params">(self, arr: list[int])</span> -&gt; float:</span></span><br><span class="line">            <span class="comment"># Write your solution here</span></span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span></span><br></pre></td></tr></table></figure><p>Figure 3. upper: method signature for condition1 (without type hints) lower: method signature for condition2<br>(with type hints)</p><p>Data Collection<br>Fig 4 shows the data collection flowchart of our study. During the study, participants need to connect<br>to our provided judge server to test and submit their code and the judge server will record test<br>and submit actions and the corresponding results. Zoom will do a video record to record the entire<br>study. The locally tampermonkey extension will record keystrokes, clicks and autocomplete suggestion<br>status. In terms of the recorded keystrokes, we are most interested in the keypress in Table. 2 with<br>autocomplte observed.</p><p>Data analysis<br>Quantitative : The majority of quantitative data comes from the recorded data during the experiments,<br>we also consult video recording when we find abnormal events. We use java, python, excel to<br>categorize, analyze, and plot the recorded data.<br>Qualitative : The majority of qualitative data comes from the semi-structured interview conducted<br>at the end of the entire experiment, we also consult video recording when needed. This study is<br>designed to be using semantic analysis by first generating codes from participants’ transcription. And<br>then categorize, summarize over all codes. Due to time constraints, we generate codes and themes<br>mainly from notes we took during piloting and look at the transcription when needed. Transcription<br>is generated by Zoom, Microsoft Service, and iflytek. We corrected some errors in transcription using<br>video recording.</p><p>Results<br>Since we only have 4 participants, none of the quantitative results are statistically significant. But we<br>can still see trends from them and infer potential next steps.<br>3.1 Participants<br>We recruited 5 participants for the experiment. Their experience background information is shown<br>in Table 3. P0 did the experiement before we implemented the data collection mechanism, so the<br>experiement results will be discarded for P0, we will only use the interview results from P0. We<br>collected quantitative data from P1, P2, P3, and P4, which will be presented later.<br>It is unfortunate that we did not recruit competitive programmers who mains in Python. Instead,<br>P1 and P2 are both competitive programmers who mains in C++, while P0, P3 and P4 have less<br>experience in algorithm puzzles, but more experience in Python.</p><p>Quantitative Result<br>Figure 5 shows the timeline of observed activities from the experiments. The top half is result from<br>Condition 1. The bottom half is result from Condition 2. The horizontal coordinate is the time of the<br>experiement. The vertical coordinate is the 4 participants. Background color signifies the problem<br>they are working on. Vertical lines are test and submit actions, and color represent the judge verdict.<br>Markers in the middle on the center lines are instances of autocomplete suggestions, where different<br>marker represent if participant reject, accept, or ignored the suggestions. Using the result, we tries to<br>answer the following research questions:<br>RQ1 Does type hint help contenstants complete problems faster in CP?<br>RQ2 Does type hint help contenstants do first-time implementation faster in CP?<br>RQ3 Does type hint help contenstants debug faster in CP?<br>RQ4 Do autocomplete suggestions help when type hints were added in CP?<br>Given the research qeustions, we gathered corresponding information from the raw data and<br>presented in Figure 6.<br>A Completion time<br>Completion time is the total time used to implement the algorithm correctly. It is represented by<br>the total amount of time taken to receiving an “accepted” verdict. Figure 6b shows the completion<br>time. Data suggests that Condition 1 has faster completion time.<br>B First-pass implementation time<br>We hope to see if type hint influence how fast a programmer write their first version of code.<br>First-pass implementation time is the time to program the initial version of the solution. We used<br>two quantities to approximate the first-pass implementation time: the first test time, and the first<br>submit time. Both of them are presented side-by-side in Figure 6c. As we can see, the first pass<br>time is generally higher for Condition 2 than Condition 1.<br>C Debugging time<br>Debugging time is the time used on debugging. We used the time from first meaningful test to<br>problem completion to approximate the debugging time. The first meaningful test is determined<br>by looking at the code they tested. If it is very clear that an early test is on an incomplete code,<br>then we discard this test and consider the next test as first meaningful test. Figure 6d shows the<br>debugging time. The result is inconclusive. It seems that for problem B, Condition 1 has higher<br>debugging time. And for problem G, Condition 2 has higher debugging time.<br>D Autocomplete acceptance ratio<br>We want to study the usefulness of autocomplete suggestions. Autocomplete acceptance ratio is<br>the ratio of the count of accepted suggestions to the count of all given suggestions. Data is shown<br>in Figure 6a. The acceptance rate is generally low. The highest acceptance rate is 17.07% from<br>P1 in Condition 2. The acceptance ratio is also generally higher for Condition 2 than Condition 1.<br>3.3 Qualitative result<br>This section contains the result from the post-study interview. We answer the research question:<br>RQ5 What is the sentiment towards using type hints, type checker, and autocomplete suggestions in<br>CP?<br>We summarize codes from notes taken from the interview, and refer back to the video recording of<br>the interview when needed. The following are some common topics we found.<br>A Autocomplete Suggestions are sometimes annoying<br>P2 suggests autocomplete is distracting, “When you are thinking about complex problems, [autocomplete<br>suggestion box] popping up may disrupt your thinking.”<br>P2 also suggested that autocomplete boxes interfere with the action of inputting end-of-line character.<br>Usually, one would press enter to get a new line. However, when autocomplete is up,<br>pressing enter will accept the autocomplete, instead of giving you a new line. You’ll need to either<br>reject the suggestions beforehand, or erase the extra characters that autocomplete give you.<br>P0 and P4 suggest there is no impact of having autocomplete or not.<br>From the recording, we know that P4 is the only person using arrow key to select elements. In</p><p>Figure 5. Timeline of observed activities legends as below:<br>Background color: aliceblue as Problem A, lavender as Problem B, lavenderblush as Problem G,<br>Test/submit actions: vertical dashed line as test, vertical solid line as submit, vertical green line as Accept,<br>vertical orange line as Wrong answer, vertical red line as Runtime error,vertical yellow line as Crash,<br>autocomplete status: Yellow triangle as Ignored, Green dot as Accept Red cross as Reject</p><p>condition 2, they used arrow key 3 times but ignored or cancelled at last.<br>B Autocomplete Suggestions is useful for completing variable names<br>P1, P2 and P3 all suggested that the suggestions to complete variable names are good. However,<br>P2 pointed out that for short variable names, the autocomplete suggestion won’t show up, an thus<br>autocomplete is useless in this case. They also pointed out that a lot of people write short variable<br>names in CP contests, which seems true from a quick scan over a few Codeforces submissions<br>from high-rated contestants.<br>Based on our video observations, most of autocomplete acceptance also happens at completing<br>variable name.<br>P1 and P3 gave a positive feedback for autocomplete. But data showed that only P1 have a high<br>acceptance rate. P1 tends to have longer variable name than P2. And P1 seems not familiar with<br>python syntax, as in our notes.<br>Even though P3 suggests autocomplete is useful during interview, considering the relatively low<br>acceptance rate, 2.85% in condition 1 and 7.21% in condition 2, their feeling might not accurate.<br>P4 and P0 says autocomplete has no impact.<br>C Writing type hints wastes time<br>P4 suggests Type hint syntax is weird: “So to tell the truth, the only thing I feel uncomfortable<br>about is that its syntax is very strange.” They say it’s different from the typing syntax in C++<br>and Java, which are their main langauges at work.<br>P3 suggests that typing Type hint is a waste of time.<br>P2 didn’t need to use any type hints during the experiement.<br>P1 also thinks type hints wastes time. “But during the competition, you may not want to use type<br>hints. If you spent time on writing types, you may lose your time advantage [in using Python].”<br>P0 suggest writing type is okay but changing type is boring and time-consuming: ”If you are just<br>writing this type [for once], it’s OK. It’s not a waste of time.” and ”But I think, especially just<br>now, for example, if I want to change [the definition of] one [variable], […], I have to change its<br>type hint again when I come back. This is very troublesome.”<br>D Investigating type error wastes time<br>P4 suggest that using type checker in a limited time condition is wasting time.<br>P2 suggest that they only use the type checker when they are finding the specific position of<br>some bugs, “OK, but for type checker, […] If there is a compilation error, you can enable [type<br>checker] and take a look at it. However, I usually disable it when writing code.” He give the reason<br>that investigating an error is time-consuming and maybe not worth it, “For example, if [the type<br>checker] gives a warning, I will be drived to read it. After reading it, I find that it is actually is a<br>false alarm. This wastes time.”<br>P0 suggest when using Pylance, type checking with ”basic” mode might be better than ”strict”<br>mode. And ”basic” mode is better than no type inferrence at all.<br>E Being “Pythonic” is important<br>P3 suggests type hints feature for python is not meaningful compared with other programming<br>languages, ”Python plus Type Hint is a strictly worse than using a statically typed language like<br>C++.”<br>P4 recommends ”Python is just used for scripting and rapid prototyping.”. He also suggests that<br>Python is a scripting language instead of a “formal” one. So, people shouldn’t make it strictly<br>typed.<br>F Project scale affect whether type hints are useful<br>P3 suggest debugging in this length of codes may not appeal the fancy part of type hints, saying<br>”Small tasks can be debugged with repeated test runs instead of typing. ”<br>P0 argues that people are able to remember the detailed information of each variable easily for<br>a task we provided, ”I can remember all the type information for tasks of size [similar to these<br>algorithm puzzles].”<br>Upon review of the interview recording, all of the participants, in one way or another, mentioned<br>that type hints might be useful for larger projects.</p><p>Computer resource limitation<br>An interesting point brought by P2 is that their own laptop is not fast enough for type checkers<br>to respond in real time. The delayed messages and suggestions are annoying and interrupt his<br>thinking, so he turns these features off while coding on the said laptop.<br>4 Limitations<br>Every study has limitations. Describe any threats to validity in your study. This section may be brief;<br>perhaps just a paragraph.<br>Except small sample size, we identify several other threats to internal validity of the study.<br>Participant Background We wish to recruit competitive programmers with similar experience (preferrably about Codeforces<br>rating 1700) competitive programmers who mains in Python. However, we cannot find such a<br>person. Thus, the results might be bias due to participants lower familiarity with algorithms or<br>Python. In fact, in Figure 7, we categorize participant in terms of their algorithm proficiency, we<br>see that the competitive programmers are much faster in completing the tasks.<br>Even if we could find Python competitive programmers, they still need to learn to use Python Type<br>Hints. Since experience is an important factor, we would ideally want to perform the experiments<br>with participants who are very familiar with type hints. We can achieve this through a more<br>long-term experiment.<br>Task Selection We selected relative easy problems compared to real CP contest tasks. Thus, our results cannot<br>be generalized to more complex problems.<br>Environment Setup Our environment setup is quite different from the one used in CP or interview. Participants often<br>use different editors and tools, but we only provided VSCode and Pylance.<br>Compared to CP contests, we handle input/output differently. CP contests require contestants<br>to read input from stdin and write outputs to stdout, adding two layers of text manipulation.<br>Compared to interviews, as P1 and P3 suggested, we are giving participants access to tools that is<br>normally absent in coding interviews, like autocomplete and type checker. P3 purposefully turns<br>off autocomplete and type checker when practicing coding interview to simulate real interview<br>environment.<br>Variety of Bugs We gave participants an entire algorithm puzzle to do. It is unpredictable what kind of bugs will<br>be introduced. Even though we required the parcipant to understand the solution algorithm before<br>starting the timer, they might still waste time on logical errors that is unrelated to typing. We<br>might be able to reduce the threat by choosing debugging tasks. However, CP is a comprehensive<br>process. Debugging other’s code might be very different from debugging the code that one wrote<br>5 minutes ago. We kept the monolithic task structure to keep it true to the nature of CP. Other<br>methods need to be taken to reduce this validity threat.<br>Ignored Suggestions Most of the autocomplete suggestions are ignored instead of rejected by pressing the escape button.<br>However, we treated ignored suggestions the same as rejected suggestions. P1 suggested that<br>autocomplete suggestions have a guidance effect. While they might not press enter to accept a<br>suggestion, they would look at the suggestions and type-copy what he thought was the correct<br>token to use. It is not known if other participants are doing the same without noticing.<br>5 Discussion<br>Interpret your results. Why do you think you found what you did? Were there any surprises?<br>The quantitative result is not so convincing due to the nature of the small pilot study. We don’t<br>have a statistically significant sample size to say things for sure. We also lost some data since our<br>judge server crashed on the experiement given to P4. If we ignore the limited sample size, we can<br>infer the following about the research questions:<br>RQ1 Type hint does not help reduce the overall coding time in CP.<br>RQ2 People wastes time on using type hints even before debugging.<br>RQ3 The result about effect of type hint on debugging time is inconclusive.<br>RQ4 Autocomplete is often ignored. But its usage is higher when used with type hints than without.<br>From the interview results, we can infer the answer to the fifths research question:</p><p>RQ5 Contestants dislikes type hint and the type checker during competitive programming. They have<br>mixed feeing towards the autocomplete feature.<br>It is interesting to see that type hints are not helping people in CP problems.<br>We originally assumed that people would take longer to program in the first pass since they need<br>to figure out the type of hard-to-infer types and type it out. We also expect programmers to easily<br>find and fix some bugs related to types as they were coding the first time since the type checker give<br>red underline to parts that doesn’t type check. This is confirmed by our experiement.<br>We also thought that it would take less time for programmers to fix their program after testing their<br>program, since the bugs related to types were eliminated in the first-pass. However, our experiement<br>result neither support nor deny the claim. Upon closer look at the submission data, we found that P2<br>did not encounter a bug when coding problem B in condition 2. Participants all encountered bugs in<br>one way or another in other cases. P2 is one of the ICPC-NAC participatns, who is very familiar with<br>B’s algorithm. It is not suprising for him to not have a logical error in this case. If participant B were<br>to encounter a logical error in problem B, his debugging time will increase and our result might be<br>different. We might conclude that “Type hint does not help with debugging time.” This is suprising<br>to us. But at the same time, none of the participants are familiar with python type hints, so maybe<br>the cause is not type hints itself, but the experience with it.<br>The result for autocomplete shows that the VSCode feature has a lot to improve. It is not giving<br>the wanted suggestion at the right time. Some participants expressed negative opinion towards it<br>later in the interview, because of its intrusive property.<br>The interview results largely confirmed the results from the qualitative data, that it is not advantages<br>to use Python type hints in competitive programming.</p><p>Future Work<br>We have to discuss what is actually worth studying before we dive deeper into the field of CP. In lower<br>levels, people benefit from learning some basic data structure and algorithms. Higher level CP might<br>just be a niche sport that might not be so beneficial to optimize for. It might not be completely worth<br>it to study the tools and programming languages just to improve the efficiency by a bit. We have<br>to evaluate the benefit of doing such studies. As discussed in limitation, we might need to perform<br>long-term experiements to fully determine the affect of programming langauge or tools on CP so that<br>the participants have enough experience with the tools they are assigned to. Long-term experiements<br>costs more and should be weighted more carefully.<br>To continue studying about tools and programming languages for CP. Firstly, one could improve<br>this experiment and by considering the limitation described in the previous section, find ways to reduce<br>the threats, and apply it to other scenarios.<br>As we observed before, the ratio of autocomplete suggestions being accepted is very low. One<br>might carry out additional studies about the tool to investigate what kinds of suggestions have a<br>positive impact on competitive programmer’s efficiency.</p><p>Although we studied type hints in Python, it is not clear at all if people should use Python in CP.<br>Additional study on topic of “programming language choice for CP” can be done before we dig deeper<br>into Python.<br>7 Conclusion<br>Summarize what you learned.<br>In this paper, we designed an experiment to verify the research question<br>• Is Python Type Hint helpful in competitive programming?<br>We pilotted our experiment with four participants, and found that<br>• Python Type Hint might not be useful in competitive programming.<br>• Programmer dislike type hints when doing competitive programming tasks.<br>We also found some potential issues of the VSCode editor and Pylance extension:<br>• Autocomplete suggestions are not accurate and often ignored.<br>• Autocomplete suggestions is sometimes counter-productive.<br>Lastly, we identified the limitations of our work and suggested some directions of future work<br>about tools and programming langauge use in competitive programming.<br>References<br>[1] A. Rigo and S. Pedroni, “Pypy’s approach to virtual machine construction,” in Companion to the 21st<br>ACM SIGPLAN symposium on Object-oriented programming systems, languages, and applications, 2006,<br>pp. 944–953.<br>[2] Static Typing with Python — typing documentation, <a href="https://typing.readthedocs.io/en/latest/" target="_blank" rel="noopener">https://typing.readthedocs.io/en/latest/</a>, [Online;<br>accessed 2022-12-01], 2022.<br>[3] M. MIRZAYANOV, O. PAVLOVA, P. MAVRIN, et al., “Codeforces as an educational platform for learning<br>programming in digitalization,” Olympiads in Informatics, vol. 14, pp. 133–142, 2020.<br>[4] The world’s leading online programming learning platform. [Online]. Available: <a href="http://www.leetcode" target="_blank" rel="noopener">http://www.leetcode</a>.<br>com/.<br>[5] T. Di Mascio, L. Laura, and M. Temperini, “A framework for personalized competitive programming<br>training,” in 2018 17th International Conference on Information Technology Based Higher Education<br>and Training (ITHET), 2018, pp. 1–8. doi: 10.1109/ITHET.2018.8424620.<br>[6] W. Di Luigi, P. Fantozzi, L. Laura, et al., “Learning analytics in competitive programming training<br>systems,” in 2018 22nd International Conference Information Visualisation (IV), 2018, pp. 321–325. doi:<br>10.1109/iV.2018.00061.</p>]]></content:encoded>
      
      
      <category domain="https://shaokang.me/categories/research/">research</category>
      
      
      <category domain="https://shaokang.me/tags/research/">research</category>
      
      
      <comments>https://shaokang.me/2022/Whether-Python-Type-Hints-are-helpful-for-competitive-programmers-CP/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Wise grader</title>
      <link>https://shaokang.me/2022/Wise-grader/</link>
      <guid>https://shaokang.me/2022/Wise-grader/</guid>
      <pubDate>Wed, 23 Feb 2022 09:41:20 GMT</pubDate>
      
      <description>&lt;p&gt;A user script designed to be injected into &lt;a href=&quot;http://itestcloud.unipus.cn&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;itestcloud.unipus.cn&lt;/a&gt;, helping individuals grade in their preferred, customized way by utilizing &lt;a href=&quot;https://www.tensorflow.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;TensorFlow&lt;/a&gt; and bi-gram to simplify the grading process.&lt;/p&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p>A user script designed to be injected into <a href="http://itestcloud.unipus.cn" target="_blank" rel="noopener">itestcloud.unipus.cn</a>, helping individuals grade in their preferred, customized way by utilizing <a href="https://www.tensorflow.org/" target="_blank" rel="noopener">TensorFlow</a> and bi-gram to simplify the grading process.<a id="more"></a> The original project is intended to help my mom grade assignments more quickly and alleviate her stress in grading students’ assignments. The project uses Bi-gram and <a href="https://www.tensorflow.org/api_docs/python/tf/keras/losses/CosineSimilarity" target="_blank" rel="noopener">tf.keras.losses.CosineSimilarity of TensorFlow v2.14.0</a> to calculate similarity, taking into account word counts, and it reports the recommendation score. Users can choose to accept or adjust the recommended score.</p><p>Original script:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// ==UserScript==</span></span><br><span class="line"><span class="comment">// @name         New Userscript</span></span><br><span class="line"><span class="comment">// @namespace    http://tampermonkey.net/</span></span><br><span class="line"><span class="comment">// @version      0.1</span></span><br><span class="line"><span class="comment">// @description  try to take over the world!</span></span><br><span class="line"><span class="comment">// @author       You</span></span><br><span class="line"><span class="comment">// @match        https://itestcloud.unipus.cn/utest/itest/biz/kaoshi/rate?*</span></span><br><span class="line"><span class="comment">// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==</span></span><br><span class="line"><span class="comment">// @grant        none</span></span><br><span class="line"><span class="comment">// @require      https://cdn.jsdelivr.net/npm/@tensorflow/tfjs</span></span><br><span class="line"><span class="comment">// @require      https://cdn.jsdelivr.net/npm/@tensorflow-models/universal-sentence-encoder</span></span><br><span class="line"><span class="comment">// ==/UserScript==</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line"><span class="meta">    'use strict'</span>;</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">compareTwoStrings</span>(<span class="params">first, second</span>) </span>&#123;</span><br><span class="line">        first = first.replace(<span class="regexp">/\s+/g</span>, <span class="string">''</span>)</span><br><span class="line">        second = second.replace(<span class="regexp">/\s+/g</span>, <span class="string">''</span>)</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (first === second) <span class="keyword">return</span> <span class="number">1</span>; <span class="comment">// identical or empty</span></span><br><span class="line">        <span class="keyword">if</span> (first.length &lt; <span class="number">2</span> || second.length &lt; <span class="number">2</span>) <span class="keyword">return</span> <span class="number">0</span>; <span class="comment">// if either is a 0-letter or 1-letter string</span></span><br><span class="line"></span><br><span class="line">        <span class="keyword">let</span> firstBigrams = <span class="keyword">new</span> <span class="built_in">Map</span>();</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; first.length - <span class="number">1</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">const</span> bigram = first.substring(i, i + <span class="number">2</span>);</span><br><span class="line">            <span class="keyword">const</span> count = firstBigrams.has(bigram)</span><br><span class="line">            ? firstBigrams.get(bigram) + <span class="number">1</span></span><br><span class="line">            : <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">            firstBigrams.set(bigram, count);</span><br><span class="line">        &#125;;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">let</span> intersectionSize = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; second.length - <span class="number">1</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">const</span> bigram = second.substring(i, i + <span class="number">2</span>);</span><br><span class="line">            <span class="keyword">const</span> count = firstBigrams.has(bigram)</span><br><span class="line">            ? firstBigrams.get(bigram)</span><br><span class="line">            : <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (count &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                firstBigrams.set(bigram, count - <span class="number">1</span>);</span><br><span class="line">                intersectionSize++;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> (<span class="number">2.0</span> * intersectionSize) / (first.length + second.length - <span class="number">2</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">word</span>(<span class="params">sentence</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">var</span> length = sentence.length;</span><br><span class="line"></span><br><span class="line">            <span class="comment">//去掉字符串前面的空格</span></span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">var</span> i=<span class="number">0</span>;i&lt;length;i++) &#123;</span><br><span class="line">            <span class="keyword">if</span>(sentence[i]!=<span class="string">' '</span>) &#123;</span><br><span class="line">                sentence = sentence.substring(i,length);</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//去掉字符串前面空格的字符串长度</span></span><br><span class="line">        length=sentence.length;</span><br><span class="line">        <span class="comment">//去掉字符串后面的空格</span></span><br><span class="line">        <span class="keyword">for</span>(i=length<span class="number">-1</span>;i&gt;=<span class="number">0</span>;i--) &#123;</span><br><span class="line">            <span class="keyword">if</span>(sentence[i]!=<span class="string">' '</span>) &#123;</span><br><span class="line">                sentence = sentence.substring(<span class="number">0</span>,i+<span class="number">1</span>);</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        length=sentence.length;</span><br><span class="line">        <span class="comment">//去掉字符串中间的空格</span></span><br><span class="line">        <span class="keyword">for</span>(i=<span class="number">0</span>;i&lt;length;i++) &#123;</span><br><span class="line">            <span class="keyword">if</span>(sentence[i]==<span class="string">' '</span>) &#123;</span><br><span class="line">                <span class="keyword">if</span>(sentence[i+<span class="number">1</span>]==<span class="string">' '</span>) &#123;</span><br><span class="line">                    <span class="keyword">var</span> buffer1 = sentence.substring(<span class="number">0</span>,i);</span><br><span class="line">                    <span class="keyword">var</span> buffer2 = sentence.substring(i+<span class="number">1</span>,sentence.length);</span><br><span class="line">                    sentence = buffer1+buffer2;</span><br><span class="line">                    i--;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> sentence;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">CountWord</span>(<span class="params">sentence</span>) </span>&#123;</span><br><span class="line">        <span class="keyword">let</span> s = sentence;</span><br><span class="line">        s = s.replace(<span class="regexp">/(^\s*)|(\s*$)/gi</span>,<span class="string">""</span>);</span><br><span class="line">        s = s.replace(<span class="regexp">/[ ]&#123;2,&#125;/gi</span>,<span class="string">" "</span>);</span><br><span class="line">        s = s.replace(<span class="regexp">/\n /</span>,<span class="string">"\n"</span>);</span><br><span class="line">        <span class="keyword">return</span> s.split(<span class="string">' '</span>).length;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> stu = word(<span class="built_in">document</span>.getElementsByTagName(<span class="string">"pre"</span>)[<span class="number">2</span>].innerText);</span><br><span class="line">    <span class="keyword">let</span> ans = <span class="built_in">document</span>.getElementsByTagName(<span class="string">"pre"</span>)[<span class="number">3</span>].innerText;</span><br><span class="line">    <span class="built_in">console</span>.log(stu);</span><br><span class="line">    <span class="built_in">console</span>.log(ans);</span><br><span class="line">    <span class="keyword">let</span> wordbyword = compareTwoStrings(stu,ans);</span><br><span class="line">    <span class="comment">// Your code here...</span></span><br><span class="line">    <span class="keyword">let</span> similarity = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">let</span> stuword = <span class="built_in">parseInt</span>(<span class="built_in">document</span>.getElementsByClassName(<span class="string">"rateScoreInput unknown"</span>)[<span class="number">1</span>].parentElement.nextElementSibling.nextElementSibling.innerText);</span><br><span class="line">    <span class="keyword">let</span> wordScore = stuword/CountWord(ans);</span><br><span class="line">    <span class="keyword">if</span>(wordScore&gt;<span class="number">1</span>) wordScore = <span class="number">1</span>;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">"word score: "</span>+wordScore);</span><br><span class="line">    <span class="keyword">if</span>(wordScore&lt;<span class="number">0.5</span>) alert(<span class="string">"F文章字数少："</span>+(wordScore*<span class="number">100</span>).toFixed(<span class="number">2</span>));</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">"wordbyword: "</span> + wordbyword);</span><br><span class="line">    <span class="keyword">if</span>(wordbyword&lt;<span class="number">0.5</span>) alert(<span class="string">"F文章逐字少："</span>+(wordbyword*<span class="number">100</span>).toFixed(<span class="number">2</span>));</span><br><span class="line">    (<span class="keyword">async</span>() =&gt; &#123;</span><br><span class="line">        <span class="keyword">const</span> model = <span class="keyword">await</span> use.load();</span><br><span class="line">        <span class="keyword">const</span> embeddings = (<span class="keyword">await</span> model.embed([ans, stu])).unstack()</span><br><span class="line">        <span class="built_in">console</span>.log(embeddings[<span class="number">0</span>])</span><br><span class="line">        similarity = (<span class="number">1</span>-<span class="built_in">parseFloat</span>((<span class="keyword">await</span> tf.losses.cosineDistance(embeddings[<span class="number">0</span>], embeddings[<span class="number">1</span>], <span class="number">0</span>).data()).toString()));</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">"Tensorflow Similarity: "</span>+ similarity);</span><br><span class="line">        <span class="keyword">let</span> finalGrade1 = (wordScore*<span class="number">0.75</span> + wordbyword*<span class="number">0.05</span> + similarity*<span class="number">0.2</span>)*<span class="number">20</span>;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">"Final F: "</span> + finalGrade1);</span><br><span class="line">        <span class="keyword">if</span>(similarity&lt;<span class="number">0.8</span>) alert(<span class="string">"F文章similarity低："</span>+(similarity*<span class="number">100</span>).toFixed(<span class="number">2</span>));</span><br><span class="line">        finalGrade1 = <span class="built_in">Math</span>.floor(finalGrade1);</span><br><span class="line">        <span class="built_in">document</span>.getElementsByClassName(<span class="string">"rateScoreInput unknown"</span>)[<span class="number">1</span>].value = finalGrade1;</span><br><span class="line">        <span class="built_in">document</span>.getElementsByClassName(<span class="string">"rateScoreInput unknown"</span>)[<span class="number">1</span>].parentElement.nextElementSibling.nextElementSibling.innerText += <span class="string">"\n字数："</span> + stuword + <span class="string">"/"</span> + CountWord(ans) + <span class="string">"="</span> + (wordScore*<span class="number">100</span>).toFixed(<span class="number">2</span>) + <span class="string">"\n逐字："</span> +(wordbyword*<span class="number">100</span>).toFixed(<span class="number">2</span>)+ <span class="string">"\nTensorFlow："</span> +(similarity*<span class="number">100</span>).toFixed(<span class="number">2</span>)+<span class="string">"\nFinal："</span>+finalGrade1;</span><br><span class="line">    &#125;)()</span><br><span class="line">    <span class="keyword">let</span> a = <span class="built_in">document</span>.createElement(<span class="string">"div"</span>);</span><br><span class="line">   a.innerHTML =  <span class="string">`&lt;input type='button' value='Add One' onclick='document.getElementsByClassName("rateScoreInput unknown")[1].value = parseInt(document.getElementsByClassName("rateScoreInput unknown")[1].value) + 1'&gt;&lt;input type='button' value='Dec One' onclick='document.getElementsByClassName("rateScoreInput unknown")[1].value = parseInt(document.getElementsByClassName("rateScoreInput unknown")[1].value) - 1'&gt;`</span></span><br><span class="line"><span class="built_in">document</span>.getElementsByClassName(<span class="string">"rateScoreInput unknown"</span>)[<span class="number">1</span>].parentElement.appendChild(a)</span><br><span class="line">&#125;)();</span><br><span class="line"><span class="comment">// document.getElementsByClassName("rateScoreInput unknown")[0].parentElement.appendChild()</span></span><br><span class="line"><span class="comment">//字数50%</span></span><br></pre></td></tr></table></figure>]]></content:encoded>
      
      
      <category domain="https://shaokang.me/categories/website/">website</category>
      
      <category domain="https://shaokang.me/categories/website/JS/">JS</category>
      
      
      <category domain="https://shaokang.me/tags/JS/">JS</category>
      
      
      <comments>https://shaokang.me/2022/Wise-grader/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Scrap and report covid info</title>
      <link>https://shaokang.me/2021/Scrap-and-report-covid-info/</link>
      <guid>https://shaokang.me/2021/Scrap-and-report-covid-info/</guid>
      <pubDate>Sat, 27 Mar 2021 20:35:06 GMT</pubDate>
      
        
        
      <description>&lt;p&gt;This is a tool built to automatically scrape information from government websites using Puppeteer and provide updates to the WeChat platf</description>
        
      
      
      
      <content:encoded><![CDATA[<p>This is a tool built to automatically scrape information from government websites using Puppeteer and provide updates to the WeChat platform using wxpusher. The source code is available at <a href="https://github.com/ShaokangJiang/daily-report" target="_blank" rel="noopener">ShaokangJiang/daily-report (github.com)</a>. Additionally, it contains several wrapped functions, including translation, nature language understanding, and interaction with Cloudflare Worker to save and interpret daily case data. Puppeteer is capable of simulating real user behavior and avoiding being blocked by too frequent requests. This project has been run for over 6 months.</p>]]></content:encoded>
      
      
      <category domain="https://shaokang.me/categories/NodeJs/">NodeJs</category>
      
      
      <category domain="https://shaokang.me/tags/NodeJs/">NodeJs</category>
      
      <category domain="https://shaokang.me/tags/Javascript/">Javascript</category>
      
      
      <comments>https://shaokang.me/2021/Scrap-and-report-covid-info/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>AES Encrypt and Decrypt on Cloudflare worker</title>
      <link>https://shaokang.me/2021/AES-Encrypt-and-Decrypt-on-Cloudflare-worker/</link>
      <guid>https://shaokang.me/2021/AES-Encrypt-and-Decrypt-on-Cloudflare-worker/</guid>
      <pubDate>Fri, 15 Jan 2021 07:41:29 GMT</pubDate>
      
      <description>&lt;p&gt;In the real situation, information security is important and we may want to send encrypted text to user for their credential. It is good for validation and it can prevent some attack from user. &lt;code&gt;Cloudflare worker&lt;/code&gt; has an implemented encode and decode feature, so it is possible to encrypt and deliver message to user via a constraint distributed system. The pointing system of &lt;code&gt;https://capitaltwo.ga&lt;/code&gt; is built based on this. More details come below:&lt;/p&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p>In the real situation, information security is important and we may want to send encrypted text to user for their credential. It is good for validation and it can prevent some attack from user. <code>Cloudflare worker</code> has an implemented encode and decode feature, so it is possible to encrypt and deliver message to user via a constraint distributed system. The pointing system of <code>https://capitaltwo.ga</code> is built based on this. More details come below:</p><a id="more"></a><blockquote><p>Details about different possible configuration could check official website at <a href="https://developers.cloudflare.com/workers/runtime-apis/web-crypto" target="_blank" rel="noopener">Web Crypto</a></p></blockquote><h3 id="encode"><a class="markdownIt-Anchor" href="#encode"></a> Encode</h3><p>Code as below, comment is the description of purpose of each line:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">encode</span>(<span class="params">text, password</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> iv = <span class="keyword">await</span> crypto.getRandomValues(<span class="keyword">new</span> <span class="built_in">Uint8Array</span>(<span class="number">12</span>)); <span class="comment">//get a unique iv to encrypt</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> myText = <span class="keyword">new</span> TextEncoder().encode(text) <span class="comment">// need TextEncoder to encode to buffer</span></span><br><span class="line">  <span class="keyword">const</span> key = <span class="keyword">await</span> crypto.subtle.importKey(<span class="string">"raw"</span>, <span class="keyword">new</span> TextEncoder().encode(password), <span class="string">"AES-GCM"</span>, <span class="literal">false</span>, [<span class="string">"encrypt"</span>, <span class="string">"decrypt"</span>]); <span class="comment">//generate key, more details about configuration could be found on cloudflare worker official site </span></span><br><span class="line">  <span class="keyword">const</span> myDigest = <span class="keyword">await</span> crypto.subtle.encrypt(</span><br><span class="line">    &#123;</span><br><span class="line">      name: <span class="string">"AES-GCM"</span>,</span><br><span class="line">      iv: iv</span><br><span class="line">    &#125;,</span><br><span class="line">    key,</span><br><span class="line">    myText</span><br><span class="line">  )<span class="comment">//the method to encrypt</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> a = &#123;</span><br><span class="line">    <span class="string">"iv"</span>: buffer2base(iv),<span class="comment">//iv could be packaged and pass to user, they do not influence security</span></span><br><span class="line">    <span class="string">"text"</span>: buffer2base(myDigest)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> btoa(<span class="built_in">JSON</span>.stringify(a));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>In order to coded to a thing that could be delivered and saved in a normal text environment (in the last seven lines of the above coded), we can convert <code>ArrayBuffer</code> to <code>Uint8Array</code> and then use <code>JSON.stringify</code> to parse it. Like:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * @param &#123;arraybuffer object&#125; buffer </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">buffer2base</span>(<span class="params">buffer</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> btoa(<span class="built_in">JSON</span>.stringify(<span class="keyword">new</span> <span class="built_in">Uint8Array</span>(buffer)))</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p>The encryption process is a Promise and should be handled with <code>await</code></p></blockquote><h3 id="decode"><a class="markdownIt-Anchor" href="#decode"></a> Decode</h3><p>In order to decode, we need to recover generated base64 encoded text to normal buffer at first, like this:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * @param &#123;base64 object&#125; code </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">base2buffer</span>(<span class="params">code</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">Uint8Array</span>.from(<span class="built_in">Object</span>.values(<span class="built_in">JSON</span>.parse(atob(code)))).buffer</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Other codes as below, comment is the description of purpose of each line:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * @param &#123;Text want to encrypt&#125; text</span></span><br><span class="line"><span class="comment"> * @param &#123;password to decode&#125; password</span></span><br><span class="line"><span class="comment"> * @returns &#123;decoded text&#125; </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">decode</span>(<span class="params">encodeText, password</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">let</span> a = <span class="built_in">JSON</span>.parse(atob(encodeText)) <span class="comment">//parse to get iv and the encoded text</span></span><br><span class="line">  <span class="keyword">const</span> key = <span class="keyword">await</span> crypto.subtle.importKey(<span class="string">"raw"</span>, <span class="keyword">new</span> TextEncoder().encode(password), <span class="string">"AES-GCM"</span>, <span class="literal">false</span>, [<span class="string">"encrypt"</span>, <span class="string">"decrypt"</span>]);<span class="comment">//generate correct key buffer</span></span><br><span class="line">  <span class="keyword">const</span> result = <span class="keyword">await</span> crypto.subtle.decrypt(</span><br><span class="line">    &#123;</span><br><span class="line">      name: <span class="string">"AES-GCM"</span>,</span><br><span class="line">      iv: base2buffer(a.iv)</span><br><span class="line">    &#125;,</span><br><span class="line">    key,</span><br><span class="line">    base2buffer(a.text)</span><br><span class="line">  )<span class="comment">//decode to get result, detailed configuration could check cloudflare website. </span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> TextDecoder().decode(result);<span class="comment">//Use TextDecoder to decode text to normal readable format.</span></span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="compare-arraybuffer"><a class="markdownIt-Anchor" href="#compare-arraybuffer"></a> Compare <code>ArrayBuffer</code></h3><p>The easiest way to compare is through compare the digit one by one, here is a sample:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">equal</span>(<span class="params">buf1, buf2</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (buf1.byteLength != buf2.byteLength) <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">  <span class="keyword">var</span> dv1 = <span class="keyword">new</span> <span class="built_in">Int8Array</span>(buf1);</span><br><span class="line">  <span class="keyword">var</span> dv2 = <span class="keyword">new</span> <span class="built_in">Int8Array</span>(buf2);</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i != buf1.byteLength; i++) &#123;</span><br><span class="line">    <span class="keyword">if</span> (dv1[i] != dv2[i]) <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content:encoded>
      
      
      <category domain="https://shaokang.me/categories/website/">website</category>
      
      <category domain="https://shaokang.me/categories/website/Cloudflare-Worker/">Cloudflare Worker</category>
      
      
      <category domain="https://shaokang.me/tags/AES/">AES</category>
      
      
      <comments>https://shaokang.me/2021/AES-Encrypt-and-Decrypt-on-Cloudflare-worker/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Additional Work</title>
      <link>https://shaokang.me/2021/projects/Additional-Work/</link>
      <guid>https://shaokang.me/2021/projects/Additional-Work/</guid>
      <pubDate>Wed, 13 Jan 2021 03:36:27 GMT</pubDate>
      
      <description>&lt;p&gt;This post contains course related projects, forked projects with added functionality, modified projects. Some of them are big, some of them are small. All other projects in project tab are designed, coded, solved on my own and most of them are not required by a course. Click read more to read my course related projects, added function, modified projects.&lt;/p&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p>This post contains course related projects, forked projects with added functionality, modified projects. Some of them are big, some of them are small. All other projects in project tab are designed, coded, solved on my own and most of them are not required by a course. Click read more to read my course related projects, added function, modified projects.</p><a id="more"></a><h2 id="course-related-projects"><a class="markdownIt-Anchor" href="#course-related-projects"></a> Course related projects</h2><blockquote><p>For course-related program, most of them have a short description and source code might be inappropriate to provide at here. Contact me if anyone wants to see. Programs represented at here are big project, like final project. So it is intended to be big and they are not HWs.</p></blockquote><h3 id="intro-to-the-profession"><a class="markdownIt-Anchor" href="#intro-to-the-profession"></a> Intro to the Profession</h3><ul><li>HateFate Website (HTML/Jsp/SQL, 2017)</li></ul><p>Led group of 4 people to make a website back as SQL database and robust verification contain basic functions, e.g. login, signup with email verification, find password, pairing different people</p><p>This one is far beyond course requirement and more complex than a short text, see more at <a href="https://shaokangjiang.github.io/2017/projects/Website%20for%20CS100%20project/" target="_blank" rel="noopener">Website for CS100 project</a>.</p><h3 id="object-oriented-programming-i"><a class="markdownIt-Anchor" href="#object-oriented-programming-i"></a> Object-Oriented Programming I</h3><ul><li>CS115Competition2 (Java Swing, 2017)</li></ul><p>Original questions: Input some students’ grade and get a standard output with average grade.</p><p><strong>Repo:</strong> <a href="https://github.com/ShaokangJiang/CS115Competition2" target="_blank" rel="noopener">CS115Competition2</a></p><p>This small project contains a simple Java GUI through Java Swing, like this,</p><img src="/2021/projects/Additional-Work/1.png"><p>It will ask user for multiple inputs and then user could select to save the result file to local as a txt file. It also has appropriate wrong message handler to handle wrong stuff. Example of exported file:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -</span><br><span class="line">A number First name Last name Math Science History Physics Average</span><br><span class="line">- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -</span><br><span class="line">A52525252 A52 A52 52 52 52 52 52.0</span><br><span class="line">A85858585 A85 A85 85 85 85 85 85.0</span><br></pre></td></tr></table></figure><div id="LibraryManagementSoftware"></div><ul><li>CS115Activity2 - Library Management Software (Java/Java Swing, 2017)</li></ul><p><strong>Repo:</strong> <a href="https://github.com/ShaokangJiang/CS115Activity2" target="_blank" rel="noopener">CS115Activity2</a></p><p><strong>Original question</strong>:</p><p>The libraries of SmallTownX need a new electronic rental system, and it is up to you to build it. SmallTownX has two libraries. Each library offers many books to rent. Customers can print the list of available books, borrow, and return books.</p><p>A Java GUI program to pull and upload book data from ftp and manage them, including demoed feature in the below chart.</p><blockquote><p>This program require communication with an ftp server, my original testing one is not working right now. If an error of “no server, check connection” happen, this is the reason.</p></blockquote><p><strong>The design of the system</strong>:</p><p><img src="https://raw.githubusercontent.com/ShaokangJiang/CS115Activity2/master/(java%20activity2)The%20work.jpeg" alt></p><p><strong>Sample running</strong>:</p><img src="/2021/projects/Additional-Work/08.jpg"><ul><li>Date detection and extraction and testing valid</li></ul><p>A Java program that is able to detect date based on some pre-configured sequence.</p><ul><li>Simple Encryption/Description</li></ul><p>A program to encrypt and decrypt ascii text based on specific configuration, like by shifting phase with n places.</p><h3 id="object-oriented-programming-ii"><a class="markdownIt-Anchor" href="#object-oriented-programming-ii"></a> Object-Oriented Programming II</h3><ul><li>A Road Traffic Simulator (Java, 2018)</li></ul><p>A simulator to simulate cars flow on a simple cross road and managing traffic light. Input source is a file. Output is the simulation result.</p><ul><li>Library books management</li></ul><p>Manage book, rent book, search for a book in a command line Java interface with appropriate testing methods.</p><h3 id="cmptr-orgasmbly-lang-prgmmg"><a class="markdownIt-Anchor" href="#cmptr-orgasmbly-lang-prgmmg"></a> Cmptr Org&amp;Asmbly Lang Prgmmg</h3><ul><li>LC-3 Simulator (C, 2018)</li></ul><p>A C99 program to simulate running of LC-3 assembly code with assembly file as input source.</p><h3 id="systems-programming"><a class="markdownIt-Anchor" href="#systems-programming"></a> Systems Programming</h3><ul><li>Dynamic memory allocator</li></ul><p>I write a dynamic storage allocator for C programs, i.e., my own version of the malloc and free routines, including functions of <code>mm_init</code>, <code>mm_malloc</code>, <code>mm_free</code>, <code>mm_realloc</code>.</p><ul><li>Cache simulation and optimization</li></ul><p>This project has two parts, in the first part, simulates the behavior of a cache memory. In the second part, optimize a small matrix transpose function, with the goal of minimizing the number of cache misses.</p><ul><li>a shell program</li></ul><p>In this project, I</p><ol><li>Create and manage UNIX processes with fork, exec, and wait</li><li>Write signals handlers that handle exceptional control flow</li><li>Implement a functional UNIX shell</li></ol><h3 id="database-organization"><a class="markdownIt-Anchor" href="#database-organization"></a> Database Organization</h3><ul><li>Reservation System Website (Azure/Jsp/SQL, 2019)</li></ul><p>A website to manage reservations for different roles, including admin, patient, scheduler, and see an accumulative report.</p><p>This one is far beyond course requirement and more complex than a short text, see more at <a href="https://shaokangjiang.github.io/2019/projects/Website%20for%20CS425%20project/" target="_blank" rel="noopener">Website for CS425 project</a>.</p><h3 id="introduction-to-optimization"><a class="markdownIt-Anchor" href="#introduction-to-optimization"></a> Introduction to Optimization</h3><ul><li>Seat Arrangement Problem (GAMS/Cplex, 2019)</li></ul><p>Decision-making script that solves a problem about how to arrange seats in an imaginary library</p><p>This one is far beyond those and more complex than a short text, see more at <a href="https://shaokangjiang.github.io/2019/projects/College-library-optimization-problem/" target="_blank" rel="noopener">College library optimization problem</a>.</p><h3 id="programming-iii"><a class="markdownIt-Anchor" href="#programming-iii"></a> Programming III</h3><ul><li>A JavaFx program (Java, 2020)</li></ul><p>A Java GUI program to manage and lookup some data among different farm</p><p>This one is far beyond those and more complex than a short text, see more at <a href="http://localhost:4000/2020/projects/A-JavaFx-project/" target="_blank" rel="noopener">A JavaFx project</a>.</p><h3 id="intro-to-comp-learning-theory"><a class="markdownIt-Anchor" href="#intro-to-comp-learning-theory"></a> Intro to Comp Learning Theory</h3><ul><li>Final project of reading</li></ul><p>In the final project of this course, I tried to focus on finding the correct product rating without golden set and read different papers. This one is far beyond those and more complex than a short text, see more at <a href="https://shaokangjiang.github.io/2020/projects/639-project/" target="_blank" rel="noopener">639 project</a>.</p><h3 id="building-user-interfaces"><a class="markdownIt-Anchor" href="#building-user-interfaces"></a> Building User Interfaces</h3><ul><li>Shopping Assistant (DialogFlow/REST API, 2020)</li></ul><p>Voice interaction application to perform actions on website, including filtering, adding and removing to cart, login.</p><ul><li>Course Selection and Enroll Website (React/REST API, 2020)</li></ul><p>To select course in a website contains basic functions including filtering, adding to cart, auto correct. And it could recommend course based on the course user has taken so far.</p><ul><li>Fitness App (React Native/Expo, 2020)</li></ul><p>Manage personal fitness, track workout in a day and manage dining in a day. User can set the goal and see if they achieve them or not.</p><h2 id="added-function-projects"><a class="markdownIt-Anchor" href="#added-function-projects"></a> Added function projects</h2><ul><li>Modified Traffic simulator</li></ul><p>A modified project to enable exporting running and result data into csv file at <a href="https://shaokangjiang.github.io/2020/projects/Modified-simulator/" target="_blank" rel="noopener">Modified traffic simulator</a>.</p><ul><li>Modified echart-countries-js</li></ul><p>Its program can not detect some english input sometime, fixed this error and serve on my own. Repo at <a href="https://github.com/ShaokangJiang/echarts-countries-js" target="_blank" rel="noopener">echarts-countries-js</a>.</p>]]></content:encoded>
      
      
      
      
      <comments>https://shaokang.me/2021/projects/Additional-Work/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Financial organization phone app - stage 2</title>
      <link>https://shaokang.me/2021/projects/Financial-organization-phone-app-stage-2/</link>
      <guid>https://shaokang.me/2021/projects/Financial-organization-phone-app-stage-2/</guid>
      <pubDate>Mon, 11 Jan 2021 20:46:07 GMT</pubDate>
      
      <description>&lt;p&gt;In addition to &lt;a href=&quot;https://shaokangjiang.github.io/2020/Financial-organization-phone-application/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Stage 1 of this app&lt;/a&gt;, Stage 2 is a voice interaction app based on locally trained natural language processing model by using &lt;a href=&quot;https://github.com/axa-group/nlp.js/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Nlp.js&lt;/a&gt;, which detects and analyze phrases based on machine learning, and voice recognition by using ibm waston cloud. Due to compatibility, limitation in testing, privacy issue, the published version only contain chat feature using which user is able to add items to their lists. Chat robot will communicate with user in multiple rounds and extract related information to add to the existed lists. This app is built on Expo managed workflow and thus has cross-platform support. The future published version will integrate Tensorflow and using &lt;code&gt;float32array&lt;/code&gt; to run locally train and run voice recognition. Dark and light theme is following user’s system default. This app is done solely on me. More details come below:&lt;/p&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p>In addition to <a href="https://shaokangjiang.github.io/2020/Financial-organization-phone-application/" target="_blank" rel="noopener">Stage 1 of this app</a>, Stage 2 is a voice interaction app based on locally trained natural language processing model by using <a href="https://github.com/axa-group/nlp.js/" target="_blank" rel="noopener">Nlp.js</a>, which detects and analyze phrases based on machine learning, and voice recognition by using ibm waston cloud. Due to compatibility, limitation in testing, privacy issue, the published version only contain chat feature using which user is able to add items to their lists. Chat robot will communicate with user in multiple rounds and extract related information to add to the existed lists. This app is built on Expo managed workflow and thus has cross-platform support. The future published version will integrate Tensorflow and using <code>float32array</code> to run locally train and run voice recognition. Dark and light theme is following user’s system default. This app is done solely on me. More details come below:</p><a id="more"></a><h3 id="usage"><a class="markdownIt-Anchor" href="#usage"></a> Usage</h3><p>In addition to <a href="https://shaokangjiang.github.io/2020/Financial-organization-phone-application/" target="_blank" rel="noopener">Stage 1 of this app</a>, just click add float button and select the mic sign. After waiting a moment, the interface will be poped out. See an example of the released app at the end of this passage.</p><h3 id="running"><a class="markdownIt-Anchor" href="#running"></a> Running</h3><p>Click <a href="https://github.com/ShaokangJiang/CapitalTwo-Financial" target="_blank" rel="noopener">here</a> for source code.</p><p>Click <a href="https://expo.io/@huangsk100/projects/CapitalTwo-Financial" target="_blank" rel="noopener">here</a> for an expo runable version</p><p>Android and ios package is ready but Github has the limitation to prevent me of uploading. User could always built their own through <code>expo build:ios</code> or <code>expo build:android -t apk</code></p><h3 id="compile-from-source"><a class="markdownIt-Anchor" href="#compile-from-source"></a> Compile from source</h3><p>To compile and run locally:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> https://github.com/ShaokangJiang/CapitalTwo-Financial.git</span><br><span class="line"><span class="built_in">cd</span> CapitalTwo-Financial</span><br><span class="line">npm install</span><br><span class="line">expo install</span><br><span class="line">expo start</span><br></pre></td></tr></table></figure><p>And use our phone to scan the QR code on screen.</p><h3 id="entity-extraction"><a class="markdownIt-Anchor" href="#entity-extraction"></a> Entity extraction</h3><blockquote><p>Details about using entity and entity extraction steps could refer to <a href="https://shaokangjiang.github.io/2021/Nlp-js-in-Expo-usage/" target="_blank" rel="noopener">Nlp.js in Expo usage</a>, which contains more details, including sample codes.</p></blockquote><p>Entity information, like amount, title, etc, are extracted from the communication between you and the machine. The description will be the chat between you and robot. Because of the benefit of locally trained model, the specific spending and expense categories are added as enum and thus able to be extracted as well. User just need to answer questions machine asked, and everything would be on set. Detailed syntax could check the repo at <a href="https://github.com/ShaokangJiang/CapitalTwo-Financial" target="_blank" rel="noopener">here</a></p><p>Future version might contain store name extraction based on context. To do this, current plan is to check the sentence structure, like detecting “at XXX”, and double check by using the intent matching through Nlp.js. Then extract them using regular expression.</p><h3 id="future-work"><a class="markdownIt-Anchor" href="#future-work"></a> Future work</h3><ol><li>Optimize the performance - including update the state only necessary, retrain the model only when necessary.</li><li>Use locale voice recognition that will be compatible with Expo platform through Tensorflow local training to make the version works on both android and ios with no privacy risk. Some possible projects using is the <a href="https://github.com/tensorflow/tfjs-models/tree/master/speech-commands" target="_blank" rel="noopener">speech-command</a>. And I will possibly build my own training dataset for each specific function. Current plan for this one is to convert original audio to <code>float32array</code> and then using thee locally trained Tensorflow model to detect and generate result.</li><li>Location recognition in the conversation based on the context. Possible way is through checking the sentence structure, like detecting “at XXX”, and double check by using the intent matching through Nlp.js. Then extract them using regular expression.</li></ol><h3 id="sample-running"><a class="markdownIt-Anchor" href="#sample-running"></a> Sample running</h3><p>Here is a sample running of the released version. This is in dark theme.</p><img src="/2021/projects/Financial-organization-phone-app-stage-2/Screenshot.jpg">]]></content:encoded>
      
      
      <category domain="https://shaokang.me/categories/Expo/">Expo</category>
      
      
      <category domain="https://shaokang.me/tags/Expo/">Expo</category>
      
      <category domain="https://shaokang.me/tags/Nlp-js/">Nlp.js</category>
      
      
      <comments>https://shaokang.me/2021/projects/Financial-organization-phone-app-stage-2/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Simple Chat App</title>
      <link>https://shaokang.me/2021/projects/Simple-Chat-App/</link>
      <guid>https://shaokang.me/2021/projects/Simple-Chat-App/</guid>
      <pubDate>Mon, 11 Jan 2021 14:47:38 GMT</pubDate>
      
      <description>&lt;p&gt;This is an robot chat app based on locally trained natural language processing model by using &lt;a href=&quot;https://github.com/axa-group/nlp.js/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Nlp.js&lt;/a&gt;. It could answer questions in different situations and is able to run and answer questions based on context totally locally. Due to the limitation of the local dataset, it can only understand a limited number of phrase. It is still a good app to chat with. In each run, you can also choose to save history chat or not and choose to extract entity information or not. So, it is also a good app to see what a phrase will happen in react native version of Nlp.js in expo. Dark and light theme is following user’s system default. This app is done solely by me.&lt;/p&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p>This is an robot chat app based on locally trained natural language processing model by using <a href="https://github.com/axa-group/nlp.js/" target="_blank" rel="noopener">Nlp.js</a>. It could answer questions in different situations and is able to run and answer questions based on context totally locally. Due to the limitation of the local dataset, it can only understand a limited number of phrase. It is still a good app to chat with. In each run, you can also choose to save history chat or not and choose to extract entity information or not. So, it is also a good app to see what a phrase will happen in react native version of Nlp.js in expo. Dark and light theme is following user’s system default. This app is done solely by me.</p><a id="more"></a><h3 id="usage"><a class="markdownIt-Anchor" href="#usage"></a> Usage</h3><p>This is a simple example of using Nlp.js on Expo with chat interface. It is trained with some general chatting phrases. Turn on the switcher to enable and show the extracted information, Press save button to save communication, which will be loaded by app in your next initiation. See an example of the released app at the end of this passage.</p><h3 id="running"><a class="markdownIt-Anchor" href="#running"></a> Running</h3><p>Click <a href="https://github.com/ShaokangJiang/Chat-Interface" target="_blank" rel="noopener">here</a> for source code.</p><p>Click <a href="https://expo.io/@huangsk100/projects/Chat-Interface" target="_blank" rel="noopener">here</a> for an expo runable version.</p><p><a href="https://github.com/ShaokangJiang/Chat-Interface/releases/download/0.1/Chat-Interface.apk" target="_blank" rel="noopener">Download Apk for android</a></p><p><a href="https://github.com/ShaokangJiang/Chat-Interface/releases/download/0.1/Chat-Interface.tar.gz" target="_blank" rel="noopener">Download for ios</a></p><h3 id="compile-from-source"><a class="markdownIt-Anchor" href="#compile-from-source"></a> Compile from source</h3><p>To compile and run locally:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> https://github.com/ShaokangJiang/Chat-Interface.git</span><br><span class="line"><span class="built_in">cd</span> CapitalTwo-Financial</span><br><span class="line">npm install</span><br><span class="line">expo install</span><br><span class="line">expo start</span><br></pre></td></tr></table></figure><p>And use our phone to scan the QR code on screen.</p><h3 id="information-extract"><a class="markdownIt-Anchor" href="#information-extract"></a> Information Extract</h3><p>Entity information, like amount, title, etc, are extracted from the communication between you and the machine. Because of the benefit of locally trained model, the specific spending and expense categories are added as enum and thus able to be extracted as well. User just need to answer questions machine asked, and everything would be on set. Detailed syntax could check the repo.</p><p>This app is good to know what will be extracted by turning on the <code>Info?</code> on the upper corner.</p><h3 id="sample-running"><a class="markdownIt-Anchor" href="#sample-running"></a> Sample running</h3><p>Here is a sample running of the released version. This is in dark theme. This is a demo app, so only part function is shown.</p><img src="/2021/projects/Simple-Chat-App/Screenshot.jpg">]]></content:encoded>
      
      
      <category domain="https://shaokang.me/categories/Expo/">Expo</category>
      
      
      <category domain="https://shaokang.me/tags/Expo/">Expo</category>
      
      <category domain="https://shaokang.me/tags/Nlp-js/">Nlp.js</category>
      
      
      <comments>https://shaokang.me/2021/projects/Simple-Chat-App/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Nlp.js in Expo usage</title>
      <link>https://shaokang.me/2021/Nlp-js-in-Expo-usage/</link>
      <guid>https://shaokang.me/2021/Nlp-js-in-Expo-usage/</guid>
      <pubDate>Sun, 10 Jan 2021 20:48:49 GMT</pubDate>
      
      <description>&lt;p&gt;Even though the official repo of &lt;a href=&quot;https://github.com/axa-group/nlp.js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Nlp.js&lt;/a&gt; has a description about using in &lt;code&gt;React Native&lt;/code&gt;. Running directly on Expo might have some problems. Due to some limitation on the web version of &lt;code&gt;@nlpjs/core @nlpjs/lang-en-min @nlpjs/nlp&lt;/code&gt;, like no entity extraction and can not customize entity, using &lt;code&gt;node-nlp-rn&lt;/code&gt; is a good choice. More details on implementing in below:&lt;/p&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p>Even though the official repo of <a href="https://github.com/axa-group/nlp.js" target="_blank" rel="noopener">Nlp.js</a> has a description about using in <code>React Native</code>. Running directly on Expo might have some problems. Due to some limitation on the web version of <code>@nlpjs/core @nlpjs/lang-en-min @nlpjs/nlp</code>, like no entity extraction and can not customize entity, using <code>node-nlp-rn</code> is a good choice. More details on implementing in below:</p><a id="more"></a><h3 id="installation"><a class="markdownIt-Anchor" href="#installation"></a> Installation:</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install node-nlp-rn</span><br></pre></td></tr></table></figure><h3 id="processhrtime-error"><a class="markdownIt-Anchor" href="#processhrtime-error"></a> process.hrtime() error</h3><p>A common error I met was <code>process.hrtime()</code> is not a function. Because expo is not a total <code>Node.js</code> environment, this function wouldn’t exist. By checking the place that is using this function at <a href="https://github.com/axa-group/nlp.js/search?q=process.hrtime&amp;type=code" target="_blank" rel="noopener">Github</a>, it is just used to measure the performance of the Nlp.js. So, a good and reasonable way to overcome this is to block this function by defining a global function using <code>window</code>, like:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">window.process.hrtime = function () &#123; return 0 &#125;</span><br></pre></td></tr></table></figure><blockquote><p>This is the key in my case to make Nlp.js run</p></blockquote><h3 id="remaining"><a class="markdownIt-Anchor" href="#remaining"></a> Remaining:</h3><p>By solving the previous issue, everything is on set and just do not use any saving function. Other functions are the same as <code>node-nlp</code></p><p>A sample could be:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line">import React, &#123; Component &#125; from &apos;react&apos;;</span><br><span class="line">window.process.hrtime = function () &#123; return 0&#125;</span><br><span class="line"></span><br><span class="line">import &#123;NlpManager&#125; from &apos;node-nlp-rn&apos;;</span><br><span class="line">class MainScreen extends Component &#123;</span><br><span class="line"></span><br><span class="line">  async componentDidMount() &#123;</span><br><span class="line">    const manager = new NlpManager(&#123; languages: [&apos;en&apos;], forceNER: true &#125;);</span><br><span class="line">    // Adds the utterances and intents for the NLP</span><br><span class="line">    manager.addDocument(&apos;en&apos;, &apos;goodbye for now&apos;, &apos;greetings.bye&apos;);</span><br><span class="line">    manager.addDocument(&apos;en&apos;, &apos;bye bye take care&apos;, &apos;greetings.bye&apos;);</span><br><span class="line">    manager.addDocument(&apos;en&apos;, &apos;okay see you later&apos;, &apos;greetings.bye&apos;);</span><br><span class="line">    manager.addDocument(&apos;en&apos;, &apos;bye for now&apos;, &apos;greetings.bye&apos;);</span><br><span class="line">    manager.addDocument(&apos;en&apos;, &apos;i must go&apos;, &apos;greetings.bye&apos;);</span><br><span class="line">    manager.addDocument(&apos;en&apos;, &apos;hello&apos;, &apos;greetings.hello&apos;);</span><br><span class="line">    manager.addDocument(&apos;en&apos;, &apos;hi&apos;, &apos;greetings.hello&apos;);</span><br><span class="line">    manager.addDocument(&apos;en&apos;, &apos;howdy&apos;, &apos;greetings.hello&apos;);</span><br><span class="line"></span><br><span class="line">    // Train also the NLG</span><br><span class="line">    manager.addAnswer(&apos;en&apos;, &apos;greetings.bye&apos;, &apos;Till next time&apos;);</span><br><span class="line">    manager.addAnswer(&apos;en&apos;, &apos;greetings.bye&apos;, &apos;see you soon!&apos;);</span><br><span class="line">    manager.addAnswer(&apos;en&apos;, &apos;greetings.hello&apos;, &apos;Hey there!&apos;);</span><br><span class="line">    manager.addAnswer(&apos;en&apos;, &apos;greetings.hello&apos;, &apos;Greetings!&apos;);</span><br><span class="line"></span><br><span class="line">    // Train and save the model.</span><br><span class="line"></span><br><span class="line">    await manager.train();</span><br><span class="line">    const response = await manager.process(&apos;en&apos;, &apos;I should go now&apos;);</span><br><span class="line">    console.log(response);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">  &#125;</span><br><span class="line">    render() &#123;</span><br><span class="line">        return (</span><br><span class="line">        &lt;View&gt;&lt;/View&gt;</span><br><span class="line">      );</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>And some info will be shown in the console.</p><h3 id="advanced-step"><a class="markdownIt-Anchor" href="#advanced-step"></a> Advanced step</h3><p>The benefit of using Nlp.js is that it is able to define our own entity, called enum entity. Unlike dialogflow, it always contains the exact matching option which will tell developer which one is detected. To use this, just add some definition like below:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">const manager = new NlpManager(&#123; languages: [&apos;en&apos;], forceNER: true &#125;);</span><br><span class="line">manager.addNamedEntityText(</span><br><span class="line">    &apos;categoryIncome&apos;,//name of entity</span><br><span class="line">    i,//entity option</span><br><span class="line">    [lang],//language config</span><br><span class="line">    [i, i.toLowerCase()],//possible match, this one will be automatically expanded to know other cases via different methods. </span><br><span class="line">);</span><br></pre></td></tr></table></figure><h3 id="entity-information-extraction"><a class="markdownIt-Anchor" href="#entity-information-extraction"></a> Entity information extraction</h3><p>With <code>forceNER: true</code>, the entity recognition will be turned on automatically. Each object would have different returning syntax, but a general case is <code>value</code> would contain the information extracted. A sample code to extract key information as follow:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">  generateRelationship(SourceObj) &#123;</span><br><span class="line">    <span class="keyword">switch</span> (SourceObj.entity) &#123;</span><br><span class="line">      <span class="keyword">case</span> <span class="string">"number"</span>:</span><br><span class="line">        <span class="keyword">return</span> SourceObj.resolution.subtype + <span class="string">";"</span> + SourceObj.resolution.value</span><br><span class="line">      <span class="keyword">case</span> <span class="string">"ip"</span>:</span><br><span class="line">        <span class="keyword">return</span> SourceObj.resolution.value + <span class="string">";"</span> + SourceObj.resolution.type</span><br><span class="line">      <span class="keyword">case</span> <span class="string">"percentage"</span>:</span><br><span class="line">        <span class="keyword">return</span> SourceObj.resolution.strValue</span><br><span class="line">      <span class="keyword">case</span> <span class="string">"dimension"</span>:</span><br><span class="line">      <span class="keyword">case</span> <span class="string">"age"</span>:</span><br><span class="line">      <span class="keyword">case</span> <span class="string">"currency"</span>:</span><br><span class="line">        <span class="keyword">return</span> SourceObj.resolution.value + <span class="string">" "</span> + SourceObj.resolution.localeUnit</span><br><span class="line">      <span class="keyword">case</span> <span class="string">"date"</span>:</span><br><span class="line">        <span class="keyword">switch</span> (SourceObj.resolution.type) &#123;</span><br><span class="line">          <span class="keyword">case</span> <span class="string">"date"</span>:</span><br><span class="line"><span class="keyword">return</span> SourceObj.resolution.strValue</span><br><span class="line">          <span class="keyword">default</span>:</span><br><span class="line"><span class="keyword">return</span> SourceObj.resolution.timex</span><br><span class="line">        &#125;</span><br><span class="line">      <span class="keyword">case</span> <span class="string">"duration"</span>:</span><br><span class="line">        <span class="keyword">return</span> SourceObj.resolution.values[<span class="number">0</span>].timex + <span class="string">":"</span> + SourceObj.resolution.values[<span class="number">0</span>].value + <span class="string">" Seconds"</span></span><br><span class="line">      <span class="keyword">case</span> <span class="string">"datetime"</span>:</span><br><span class="line">        <span class="keyword">return</span> SourceObj.resolution.values[<span class="number">0</span>].value</span><br><span class="line"></span><br><span class="line">      <span class="keyword">default</span>:</span><br><span class="line">        <span class="keyword">return</span> SourceObj.resolution.value</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>]]></content:encoded>
      
      
      <category domain="https://shaokang.me/categories/Expo/">Expo</category>
      
      
      <category domain="https://shaokang.me/tags/Expo/">Expo</category>
      
      <category domain="https://shaokang.me/tags/Nlp-js/">Nlp.js</category>
      
      
      <comments>https://shaokang.me/2021/Nlp-js-in-Expo-usage/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Publication for Financial website</title>
      <link>https://shaokang.me/2020/projects/Publication-of-Financial-website/</link>
      <guid>https://shaokang.me/2020/projects/Publication-of-Financial-website/</guid>
      <pubDate>Fri, 11 Dec 2020 20:47:06 GMT</pubDate>
      
      <description>&lt;p&gt;This is a serverless web application. By utilizing &lt;a href=&quot;https://workers.cloudflare.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Cloudflare worker&lt;/a&gt;, similar to edge computing, and personal effort, a constraint distributed structure with fast response time and availability is produced. The making of Financial website is actually led by me. The core part, including design, connection between different components, Devop structures, lots of coding, ARIA, are done by me. Other people’s attribution, including contribution on knowledge passage content, useful tools, quiz generation and verification, are also important. We follow up the Business Agility and use JIRA to do weekly jobs and finish this product in 8 weeks. This is the product being produced based on &lt;a href=&quot;https://shaokangjiang.github.io/2020/Capstone-prooject-design-specification-v0-1/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Design specification by me&lt;/a&gt;, most parts stay the same as design. This website designed by me contains knowledge from cross area and utilize knowledge including data representation, prediction, interactive design, interacting with phone app and much more. More details regarding to benefits and incomparable feature could be saw below:&lt;/p&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p>This is a serverless web application. By utilizing <a href="https://workers.cloudflare.com/" target="_blank" rel="noopener">Cloudflare worker</a>, similar to edge computing, and personal effort, a constraint distributed structure with fast response time and availability is produced. The making of Financial website is actually led by me. The core part, including design, connection between different components, Devop structures, lots of coding, ARIA, are done by me. Other people’s attribution, including contribution on knowledge passage content, useful tools, quiz generation and verification, are also important. We follow up the Business Agility and use JIRA to do weekly jobs and finish this product in 8 weeks. This is the product being produced based on <a href="https://shaokangjiang.github.io/2020/Capstone-prooject-design-specification-v0-1/" target="_blank" rel="noopener">Design specification by me</a>, most parts stay the same as design. This website designed by me contains knowledge from cross area and utilize knowledge including data representation, prediction, interactive design, interacting with phone app and much more. More details regarding to benefits and incomparable feature could be saw below:</p><a id="more"></a><h3 id="key-sites"><a class="markdownIt-Anchor" href="#key-sites"></a> Key Sites</h3><p>Wiki Page - It contains the development process and different stage in Business Agile - <a href="https://wiki.capitaltwo.ga/" target="_blank" rel="noopener">https://wiki.capitaltwo.ga/</a></p><p>Main - The site for all components - <a href="https://capitaltwo.ga/" target="_blank" rel="noopener">https://capitaltwo.ga/</a></p><p>Sub product - Financial organization app - Download at <a href="https://capitaltwo.ga/download.html" target="_blank" rel="noopener">https://capitaltwo.ga/download.html</a></p><h3 id="incomparable-features"><a class="markdownIt-Anchor" href="#incomparable-features"></a> Incomparable Features</h3><p>Only the part I am doing is mentioned in the following subsections.</p><h4 id="seo"><a class="markdownIt-Anchor" href="#seo"></a> SEO</h4><h5 id="indexedcrawled"><a class="markdownIt-Anchor" href="#indexedcrawled"></a> Indexed/Crawled</h5><p>Google, Baidu, Yandex, Bing has crawled it.</p><h5 id="sitemaps"><a class="markdownIt-Anchor" href="#sitemaps"></a> Sitemaps</h5><p>Majority of sitemaps will update automatically for search engine to crawl. Major sitemaps are as follows:</p><p><a href="https://capitaltwo.ga/sitemap.xml" target="_blank" rel="noopener">https://capitaltwo.ga/sitemap.xml</a></p><p><a href="https://knowledge.capitaltwo.ga/sitemap.xml" target="_blank" rel="noopener">https://knowledge.capitaltwo.ga/sitemap.xml</a></p><p><a href="https://wiki.capitaltwo.ga/sitemap.xml" target="_blank" rel="noopener">https://wiki.capitaltwo.ga/sitemap.xml</a></p><p>I also push to Bing, Google manually.</p><h5 id="points"><a class="markdownIt-Anchor" href="#points"></a> Points</h5><ul><li>With different search keywords, sitemap, tags</li><li>Site is actually pushed to google search console.</li><li>Also optimize the delivery process. Site is being auto compressed.</li><li>All static is also good in delivery process.</li></ul><h4 id="security"><a class="markdownIt-Anchor" href="#security"></a> Security</h4><h5 id="http3-https"><a class="markdownIt-Anchor" href="#http3-https"></a> Http/3 &amp; Https</h5><p>Http/3 and Https protocols are enabled by default from user to server.</p><h5 id="additional"><a class="markdownIt-Anchor" href="#additional"></a> Additional</h5><p>In addition to the security provided by Https, normal communication, including communication between Cloudflare worker and user, and between different pages is encrypted by AES. And the credential saved to localestorage is also encrypted by AES.</p><h5 id="prevent-misuse"><a class="markdownIt-Anchor" href="#prevent-misuse"></a> Prevent misuse</h5><p>Anything that need to be hidden is encrypted by using AES encryption method.</p><h4 id="user-experience"><a class="markdownIt-Anchor" href="#user-experience"></a> User Experience</h4><h5 id="user-friendly"><a class="markdownIt-Anchor" href="#user-friendly"></a> User friendly</h5><p>All devices have the same experience via web browser. (Such as mobile and tablet, on top of computer support)</p><p>Function page as sample</p><img src="/2020/projects/Publication-of-Financial-website/userF.png"><p>Pages also have a good looking and interactive data representation, like: (taken yearly budgeting tool implemented by me as an example)</p><img src="/2020/projects/Publication-of-Financial-website/uF.png"><h5 id="fast-accessing-speed"><a class="markdownIt-Anchor" href="#fast-accessing-speed"></a> Fast accessing speed</h5><p>With doing a serious jobs, including minification, compression, configuring appropriately, using distributed delivery structure, the site has a good delivery speed in most places around the world.</p><p>Statistic about compression:</p><ul><li><p>Minification</p><ul><li>Main page: 13.44 kb -&gt; 8.35 kb Ratio: 37.82%</li><li>Some pages in wiki and knowledge passage: ratio: around 40-60%</li></ul></li><li><p>60%-70% overall additional compression rate</p><ul><li><p>Main page: 6044 bytes -&gt; 2119 bytes Ratio: 64.94%</p></li><li><p>Wiki and knowledge page: 20561 bytes -&gt; 4311 bytes Ratio: 79.03%</p></li></ul></li><li><p>Speed to access the site: Median - 741ms Average - 460ms</p></li></ul><h5 id="integrate-to-mobile"><a class="markdownIt-Anchor" href="#integrate-to-mobile"></a> Integrate to mobile</h5><p>I realize it is hard to input everything in one time in yearly budgeting tool. So I also made an app to help you organize daily spending. This app is still in developing. See <a href="https://shaokangjiang.github.io/2020/Financial-organization-phone-application/" target="_blank" rel="noopener">stage one</a> and <a href="https://shaokangjiang.github.io/2021/projects/Financial-organization-phone-app-stage-2/" target="_blank" rel="noopener">two</a> by clicking the links.</p><img src="/2020/projects/Publication-of-Financial-website/phone.jpg"><h5 id="privacy-encryption"><a class="markdownIt-Anchor" href="#privacy-encryption"></a> Privacy &amp; Encryption</h5><p>Data will only be saved in user side. User have control over all data. And no personal identification data is used in this process. Any sensitive and non-sensitive data pass to user is encrypted by using AES-GCM, see more details at <a href="https://shaokangjiang.github.io/2021/AES-Encrypt-and-Decrypt-on-Cloudflare-worker/" target="_blank" rel="noopener">AES Encrypt and Decrypt on Cloudflare worker</a></p><p>For people really care about privacy, this site is well configured to allow people from Onion network through Tor visiting the site without exiting the last endpoint. See this image for the detail, this is a feature for cloudflare, I just configured it appropriately.</p><img src="/2020/projects/Publication-of-Financial-website/tor.png"><h5 id="accessibility"><a class="markdownIt-Anchor" href="#accessibility"></a> Accessibility</h5><p>The major page has accessibility feature. Most parts, including main site, knowledge site, wiki page, contain the accessibility feature by using ARIA technology.</p><p>The book version of all knowledge passage could also provide more convenience. And I do also provide multiple format, including epub, mobi, pdf, docx in the <a href="https://capitaltwo.ga/download.html" target="_blank" rel="noopener">download site</a></p><h3 id="design-thoughts-walkthrough"><a class="markdownIt-Anchor" href="#design-thoughts-walkthrough"></a> Design thoughts &amp; walkthrough</h3><p>Only the part I am doing is mentioned in the following subsections.</p><p>And those are other thoughts or final product walkthrough in addition to the previous <a href="https://shaokangjiang.github.io/2020/Capstone-prooject-design-specification-v0-1/" target="_blank" rel="noopener">Design specification by me</a></p><h4 id="components-walkthrough"><a class="markdownIt-Anchor" href="#components-walkthrough"></a> Components walkthrough</h4><p>Only parts related to running of thee site is represented, this could be thought as a supplement and detailed implementation of <a href="https://shaokangjiang.github.io/2020/Capstone-prooject-design-specification-v0-1/" target="_blank" rel="noopener">Design specification</a>.</p><h5 id="core"><a class="markdownIt-Anchor" href="#core"></a> Core</h5><img src="/2020/projects/Publication-of-Financial-website/glance.png"><h5 id="quiz"><a class="markdownIt-Anchor" href="#quiz"></a> Quiz</h5><p>A quizecode, like 65HquZ8, will be required when user is accessing the <a href="https://capitaltwo.ga/quiz/index.html" target="_blank" rel="noopener">quiz site</a>. Each passage will correspond to one code and the <code>take quiz</code> button in each essay will automatically generate and direct you to the correct page. Quiz is generated by random selection among a huge set of questions. Based on the design, the collision rate is <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>R</mi><mrow><mi>e</mi><mi>v</mi><mi>e</mi><mi>r</mi><mi>y</mi></mrow></msub><mo>=</mo><mfrac><mrow><mn>1</mn></mrow><mrow><msubsup><mi>C</mi><mrow><mn>1</mn><mn>0</mn></mrow><mrow><mn>6</mn><mn>0</mn></mrow></msubsup></mrow></mfrac><mo>=</mo><mfrac><mrow><mn>1</mn></mrow><mrow><mn>7</mn><mn>5</mn><mo separator="true">,</mo><mn>3</mn><mn>9</mn><mn>4</mn><mo separator="true">,</mo><mn>0</mn><mn>2</mn><mn>7</mn><mo separator="true">,</mo><mn>5</mn><mn>6</mn><mn>6</mn></mrow></mfrac></mrow><annotation encoding="application/x-tex">R_{every}=\frac{1}{C^{60}_{10}}=\frac{1}{75,394,027,566}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:.845108em"></span><span class="strut bottom" style="height:1.411548em;vertical-align:-.56644em"></span><span class="base textstyle uncramped"><span class="mord"><span class="mord mathit" style="margin-right:.00773em">R</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.00773em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">e</span><span class="mord mathit" style="margin-right:.03588em">v</span><span class="mord mathit">e</span><span class="mord mathit" style="margin-right:.02778em">r</span><span class="mord mathit" style="margin-right:.03588em">y</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mrel">=</span><span class="mord reset-textstyle textstyle uncramped"><span class="sizing reset-size5 size5 reset-textstyle textstyle uncramped nulldelimiter"></span><span class="mfrac"><span class="vlist"><span style="top:.37358em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord"><span class="mord mathit" style="margin-right:.07153em">C</span><span class="vlist"><span style="top:.27551428571428577em;margin-left:-.07153em;margin-right:.07142857142857144em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-scriptstyle scriptscriptstyle cramped"><span class="mord scriptscriptstyle cramped"><span class="mord mathrm">1</span><span class="mord mathrm">0</span></span></span></span><span style="top:-.34480000000000005em;margin-right:.07142857142857144em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-scriptstyle scriptscriptstyle cramped"><span class="mord scriptscriptstyle cramped"><span class="mord mathrm">6</span><span class="mord mathrm">0</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span></span></span></span><span style="top:-.22999999999999998em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle textstyle uncramped frac-line"></span></span><span style="top:-.394em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle uncramped"><span class="mord scriptstyle uncramped"><span class="mord mathrm">1</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="sizing reset-size5 size5 reset-textstyle textstyle uncramped nulldelimiter"></span></span><span class="mrel">=</span><span class="mord reset-textstyle textstyle uncramped"><span class="sizing reset-size5 size5 reset-textstyle textstyle uncramped nulldelimiter"></span><span class="mfrac"><span class="vlist"><span style="top:.345em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathrm">7</span><span class="mord mathrm">5</span><span class="mpunct">,</span><span class="mord mathrm">3</span><span class="mord mathrm">9</span><span class="mord mathrm">4</span><span class="mpunct">,</span><span class="mord mathrm">0</span><span class="mord mathrm">2</span><span class="mord mathrm">7</span><span class="mpunct">,</span><span class="mord mathrm">5</span><span class="mord mathrm">6</span><span class="mord mathrm">6</span></span></span></span><span style="top:-.22999999999999998em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle textstyle uncramped frac-line"></span></span><span style="top:-.394em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle uncramped"><span class="mord scriptstyle uncramped"><span class="mord mathrm">1</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="sizing reset-size5 size5 reset-textstyle textstyle uncramped nulldelimiter"></span></span></span></span></span>, which is super low.</p><p>The running and basic verification process could be saw below:</p><img src="/2020/projects/Publication-of-Financial-website/quiz.png"><h5 id="pointing-system"><a class="markdownIt-Anchor" href="#pointing-system"></a> Pointing system</h5><p>The design and running of the pointing system, like you get to finish one task before accessing the next one. Verification is done by passing a information that doesn’t contain any privacy information to cloudflare worker. And all information is encrypted by using a 256-bit keygen with AES-GCM</p><img src="/2020/projects/Publication-of-Financial-website/point.png"><h4 id="developing-procedure"><a class="markdownIt-Anchor" href="#developing-procedure"></a> Developing procedure</h4><h5 id="cicd"><a class="markdownIt-Anchor" href="#cicd"></a> CI/CD</h5><p>Most of this is done by using github actions and it make the website and the financial organization app always available to user. And different channels could provide people with stable or preview version. The detailed tools used are:</p><p><strong>Financial organization app:</strong> Expo + Github action + Expo page</p><p><strong>Passages&amp;Wiki:</strong> Hexo + bash + Github actions</p><p><strong>Cloudflare worker/Serverless server:</strong> Wrangler + Github actions</p><h5 id="devops-version-control"><a class="markdownIt-Anchor" href="#devops-version-control"></a> Devops &amp; version control</h5><p>I realize the entire process is actually following the Devops toolchain and most of steps are auto. By using those features, the website is always available to the public. The tool chain I designed and using was:</p><img src="/2020/projects/Publication-of-Financial-website/Devops.jpg"><p>In the later, more tools, like expo, gitbook, are added. But they are a little bit away of the main part of the site.</p><p>For each part, a strict version control is also implemented by using github so that any wrong stuff will be published only when it is well tested.</p><img src="/2020/projects/Publication-of-Financial-website/versionControl.jpg"><h5 id="easy-to-maintain"><a class="markdownIt-Anchor" href="#easy-to-maintain"></a> Easy to maintain</h5><p>A lot of stuff are generated automatically, this provides other people a chance to focus more on the content instead of the site. For example, here is the script to generate passages site and the published knowledge passage book.</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">hexo clean</span><br><span class="line"><span class="built_in">cd</span> <span class="built_in">source</span>/_posts/</span><br><span class="line">git pull</span><br><span class="line">book sm</span><br><span class="line">git commit -am <span class="string">"update"</span></span><br><span class="line">git push</span><br><span class="line"><span class="built_in">cd</span> ../../</span><br><span class="line">gitbook epub ./<span class="built_in">source</span>/_posts ./<span class="built_in">source</span>/book.epub</span><br><span class="line">gitbook mobi ./<span class="built_in">source</span>/_posts ./<span class="built_in">source</span>/book.mobi</span><br><span class="line">pandoc ./<span class="built_in">source</span>/book.epub -o ./<span class="built_in">source</span>/book.pdf --pdf-engine=xelatex -V CJKmainfont=<span class="string">"AR PL UKai CN"</span> -V geometry:margin=1in -V fontsize=18pt</span><br><span class="line">pandoc ./<span class="built_in">source</span>/book.epub -o ./<span class="built_in">source</span>/book.docx</span><br><span class="line">hexo generate</span><br><span class="line">hexo d</span><br></pre></td></tr></table></figure><h3 id="my-additional-role"><a class="markdownIt-Anchor" href="#my-additional-role"></a> My additional role</h3><p>In addition to the previous mentioned works. I adjust the schedule, arrange everyone’s working and send out recommended work weekly. Provide personal support via one on one chats. Actually, it is to manage the entire work and ensure the workload of each person each week is less than 6 hours, which equals to 2 credits.</p><h3 id="further-direction"><a class="markdownIt-Anchor" href="#further-direction"></a> Further direction</h3><ol><li>Connect with certain publication, the book reader could have a different quiz and user is able to scan the QR code to take it.</li><li>Increase validation &amp; security level to reduce possibility of being attacked</li></ol><h3 id="credits"><a class="markdownIt-Anchor" href="#credits"></a> Credits</h3><div style="overflow-x:auto"><table width="253"><tbody><tr><td width="107">Professor</td><td width="146">Amber Field</td></tr><tr><td width="107">&nbsp;</td><td width="146">&nbsp;</td></tr><tr><td rowspan="3" width="107">Product Owner (Random order)</td><td width="146">Caroline Clancy</td></tr><tr><td width="146">Madeline Janick</td></tr><tr><td width="146">Mayank Katwal</td></tr><tr><td width="107">&nbsp;</td><td width="146">&nbsp;</td></tr><tr><td rowspan="4" width="107">Developers (Random order)</td><td width="146">Shaokang Jiang</td></tr><tr><td width="146">Sai Teja Chokkarapu</td></tr><tr><td width="146">Ritika Mittal</td></tr><tr><td width="146">Peter Daly</td></tr><tr><td width="107">&nbsp;</td><td width="146">&nbsp;</td></tr><tr><td width="107">Scrum Master</td><td width="146">Shaokang Jiang</td></tr><tr><td width="107">&nbsp;</td><td width="146">&nbsp;</td></tr><tr><td width="107">Product Proxy</td><td width="146">Ritika Mittal</td></tr><tr><td width="107">&nbsp;</td><td width="146">&nbsp;</td></tr><tr><td width="107">Designers</td><td width="146">Shaokang Jiang</td></tr><tr><td colspan="2" width="253">Part of slides come from online source.</td></tr><tr><td colspan="2" width="253">All source code is granted based on MIT License. And source code is available on Github</td></tr><tr><td colspan="2" width="253">This slide is designed for non-commercial use</td></tr></tbody></table></div>> Even though only the work of me is mentioned, other people's work are important and valuable as well.]]></content:encoded>
      
      
      <category domain="https://shaokang.me/categories/website/">website</category>
      
      
      <category domain="https://shaokang.me/tags/MIP/">MIP</category>
      
      <category domain="https://shaokang.me/tags/Expo/">Expo</category>
      
      <category domain="https://shaokang.me/tags/Nlp-js/">Nlp.js</category>
      
      <category domain="https://shaokang.me/tags/Website/">Website</category>
      
      <category domain="https://shaokang.me/tags/JS/">JS</category>
      
      <category domain="https://shaokang.me/tags/ejs/">ejs</category>
      
      <category domain="https://shaokang.me/tags/HTML/">HTML</category>
      
      
      <comments>https://shaokang.me/2020/projects/Publication-of-Financial-website/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>A dialog flow app</title>
      <link>https://shaokang.me/2020/a-dialog-flow-app/</link>
      <guid>https://shaokang.me/2020/a-dialog-flow-app/</guid>
      <pubDate>Mon, 07 Dec 2020 12:57:08 GMT</pubDate>
      
      <description>&lt;p&gt;Dialogflow provided a easy to configured way to integrate the voice interaction with your application. By using their sample code, it is easy to implement and deploy to multiple different platform. But it also have problems such that wrong information matching, can not define intent/entity on the go, privacy issue, and etc. This is a course assignment done solely by me. More details in below:&lt;/p&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p>Dialogflow provided a easy to configured way to integrate the voice interaction with your application. By using their sample code, it is easy to implement and deploy to multiple different platform. But it also have problems such that wrong information matching, can not define intent/entity on the go, privacy issue, and etc. This is a course assignment done solely by me. More details in below:</p><a id="more"></a><p>This one requires the creation of dialogflow project on their official site by creating intent and entities. And in the local side, just create a locale server and enable webhook on the dialogflow website.</p><h3 id="key-terms"><a class="markdownIt-Anchor" href="#key-terms"></a> Key terms:</h3><p><code>agent</code> This is a nearly global variable, which contains the information user could get and will send to the server. It needs to be initialized in the beginning of the setting:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">app.post(<span class="string">'/'</span>, express.json(), (req, res) =&gt; &#123;</span><br><span class="line">  <span class="keyword">const</span> agent = <span class="keyword">new</span> WebhookClient(&#123; <span class="attr">request</span>: req, <span class="attr">response</span>: res &#125;)</span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> intentMap = <span class="keyword">new</span> <span class="built_in">Map</span>() <span class="comment">//and using an intentMap to match the intent and function to execute. like below: </span></span><br><span class="line">  intentMap.set(<span class="string">'Default Welcome Intent'</span>, <span class="function"><span class="keyword">function</span> (<span class="params"></span>) =&gt; </span>&#123;&#125;)<span class="comment">//Default Welcome Intent is the name</span></span><br><span class="line">  agent.handleRequest(intentMap)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>agent.add(message)</code> method to add return information.</p><blockquote><p><strong>Caution:</strong> In this method, multiple times of calling will concat information instead of random choosing and replying.</p></blockquote><p><code>agent.parameters.paraName</code> get access to the detected entity (named as <code>paraName</code>).</p><blockquote><p><strong>Caution:</strong> <code>paraName</code> might return a string that is totally not in your defined entity list. This one provides convenience but also loss the precise. So, be sure to have a good program that is able to handle those stuff correctly</p><p>In my case, there is a entity list defined as [cloth, dress, hat, …] (no this) and dialogflow detect the parameter with <code>this</code> as the value.</p></blockquote><p><code>agent.query</code> the entire sentence user said</p><p>There are other advanced stuff like <code>addContext()</code>, etc… Those four are enough to build an application.</p><h3 id="a-complete-simple-sample"><a class="markdownIt-Anchor" href="#a-complete-simple-sample"></a> A complete simple sample:</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">app.post(<span class="string">'/'</span>, express.json(), (req, res) =&gt; &#123;</span><br><span class="line">  <span class="keyword">const</span> agent = <span class="keyword">new</span> WebhookClient(&#123; <span class="attr">request</span>: req, <span class="attr">response</span>: res &#125;)</span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> intentMap = <span class="keyword">new</span> <span class="built_in">Map</span>() <span class="comment">//and using an intentMap to match the intent and function to execute. like below: </span></span><br><span class="line">  intentMap.set(<span class="string">'Default Welcome Intent'</span>, <span class="function"><span class="keyword">function</span> (<span class="params"></span>) =&gt; </span>&#123;</span><br><span class="line">                agent.add(<span class="string">"aaa"</span> + <span class="string">":user words:"</span> + agent.query)</span><br><span class="line">                &#125;)<span class="comment">//Default Welcome Intent is the name</span></span><br><span class="line">  agent.handleRequest(intentMap)</span><br><span class="line">&#125;</span><br><span class="line">app.listen(process.env.PORT || <span class="number">8080</span>)</span><br></pre></td></tr></table></figure><h3 id="discussion"><a class="markdownIt-Anchor" href="#discussion"></a> Discussion</h3><h4 id="pros"><a class="markdownIt-Anchor" href="#pros"></a> Pros:</h4><ol><li>Super easy to use, a two hour learning is enough to build an application</li><li>Have a lot of sample</li><li>Have a more powerful training platform.</li><li>Can easily integrate into platforms and deliver to user.</li></ol><h4 id="cons"><a class="markdownIt-Anchor" href="#cons"></a> Cons:</h4><ol><li>Dialogflow provided a easy to configured way to integrate the voice interaction with most applications. But their compatibility focuses on google platform. Platform like <code>Expo</code> gets to eject to integrate with it.</li><li>Dialogflow will time out after 5 seconds, which means the server need to run everything super fast. But this is hard in some cases, when network are not good, or in some network limited area.</li><li>Entity extraction might match wrong and really broad keyword that backend do not know how to prevent, like match <code>this</code> with <code>dress</code>, personally thinking <code>Nlp.js</code> is a better tool, refer to <a href="https://shaokangjiang.github.io/2021/Nlp-js-in-Expo-usage/" target="_blank" rel="noopener">Nlp.js in Expo usage</a> to see more about implementing on it.</li><li>Possible privacy issue.</li><li>It is impossible to define intent/entity based on user needs. Even though one model could work for majority people, personalization could make user feel much more comfortable to certain people. And this could eliminate training phrases as well.</li></ol><h3 id="entire-source-code"><a class="markdownIt-Anchor" href="#entire-source-code"></a> Entire source code:</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br><span class="line">399</span><br><span class="line">400</span><br><span class="line">401</span><br><span class="line">402</span><br><span class="line">403</span><br><span class="line">404</span><br><span class="line">405</span><br><span class="line">406</span><br><span class="line">407</span><br><span class="line">408</span><br><span class="line">409</span><br><span class="line">410</span><br><span class="line">411</span><br><span class="line">412</span><br><span class="line">413</span><br><span class="line">414</span><br><span class="line">415</span><br><span class="line">416</span><br><span class="line">417</span><br><span class="line">418</span><br><span class="line">419</span><br><span class="line">420</span><br><span class="line">421</span><br><span class="line">422</span><br><span class="line">423</span><br><span class="line">424</span><br><span class="line">425</span><br><span class="line">426</span><br><span class="line">427</span><br><span class="line">428</span><br><span class="line">429</span><br><span class="line">430</span><br><span class="line">431</span><br><span class="line">432</span><br><span class="line">433</span><br><span class="line">434</span><br><span class="line">435</span><br><span class="line">436</span><br><span class="line">437</span><br><span class="line">438</span><br><span class="line">439</span><br><span class="line">440</span><br><span class="line">441</span><br><span class="line">442</span><br><span class="line">443</span><br><span class="line">444</span><br><span class="line">445</span><br><span class="line">446</span><br><span class="line">447</span><br><span class="line">448</span><br><span class="line">449</span><br><span class="line">450</span><br><span class="line">451</span><br><span class="line">452</span><br><span class="line">453</span><br><span class="line">454</span><br><span class="line">455</span><br><span class="line">456</span><br><span class="line">457</span><br><span class="line">458</span><br><span class="line">459</span><br><span class="line">460</span><br><span class="line">461</span><br><span class="line">462</span><br><span class="line">463</span><br><span class="line">464</span><br><span class="line">465</span><br><span class="line">466</span><br><span class="line">467</span><br><span class="line">468</span><br><span class="line">469</span><br><span class="line">470</span><br><span class="line">471</span><br><span class="line">472</span><br><span class="line">473</span><br><span class="line">474</span><br><span class="line">475</span><br><span class="line">476</span><br><span class="line">477</span><br><span class="line">478</span><br><span class="line">479</span><br><span class="line">480</span><br><span class="line">481</span><br><span class="line">482</span><br><span class="line">483</span><br><span class="line">484</span><br><span class="line">485</span><br><span class="line">486</span><br><span class="line">487</span><br><span class="line">488</span><br><span class="line">489</span><br><span class="line">490</span><br><span class="line">491</span><br><span class="line">492</span><br><span class="line">493</span><br><span class="line">494</span><br><span class="line">495</span><br><span class="line">496</span><br><span class="line">497</span><br><span class="line">498</span><br><span class="line">499</span><br><span class="line">500</span><br><span class="line">501</span><br><span class="line">502</span><br><span class="line">503</span><br><span class="line">504</span><br><span class="line">505</span><br><span class="line">506</span><br><span class="line">507</span><br><span class="line">508</span><br><span class="line">509</span><br><span class="line">510</span><br><span class="line">511</span><br><span class="line">512</span><br><span class="line">513</span><br><span class="line">514</span><br><span class="line">515</span><br><span class="line">516</span><br><span class="line">517</span><br><span class="line">518</span><br><span class="line">519</span><br><span class="line">520</span><br><span class="line">521</span><br><span class="line">522</span><br><span class="line">523</span><br><span class="line">524</span><br><span class="line">525</span><br><span class="line">526</span><br><span class="line">527</span><br><span class="line">528</span><br><span class="line">529</span><br><span class="line">530</span><br><span class="line">531</span><br><span class="line">532</span><br><span class="line">533</span><br><span class="line">534</span><br><span class="line">535</span><br><span class="line">536</span><br><span class="line">537</span><br><span class="line">538</span><br><span class="line">539</span><br><span class="line">540</span><br><span class="line">541</span><br><span class="line">542</span><br><span class="line">543</span><br><span class="line">544</span><br><span class="line">545</span><br><span class="line">546</span><br><span class="line">547</span><br><span class="line">548</span><br><span class="line">549</span><br><span class="line">550</span><br><span class="line">551</span><br><span class="line">552</span><br><span class="line">553</span><br><span class="line">554</span><br><span class="line">555</span><br><span class="line">556</span><br><span class="line">557</span><br><span class="line">558</span><br><span class="line">559</span><br><span class="line">560</span><br><span class="line">561</span><br><span class="line">562</span><br><span class="line">563</span><br><span class="line">564</span><br><span class="line">565</span><br><span class="line">566</span><br><span class="line">567</span><br><span class="line">568</span><br><span class="line">569</span><br><span class="line">570</span><br><span class="line">571</span><br><span class="line">572</span><br><span class="line">573</span><br><span class="line">574</span><br><span class="line">575</span><br><span class="line">576</span><br><span class="line">577</span><br><span class="line">578</span><br><span class="line">579</span><br><span class="line">580</span><br><span class="line">581</span><br><span class="line">582</span><br><span class="line">583</span><br><span class="line">584</span><br><span class="line">585</span><br><span class="line">586</span><br><span class="line">587</span><br><span class="line">588</span><br><span class="line">589</span><br><span class="line">590</span><br><span class="line">591</span><br><span class="line">592</span><br><span class="line">593</span><br><span class="line">594</span><br><span class="line">595</span><br><span class="line">596</span><br><span class="line">597</span><br><span class="line">598</span><br><span class="line">599</span><br><span class="line">600</span><br><span class="line">601</span><br><span class="line">602</span><br><span class="line">603</span><br><span class="line">604</span><br><span class="line">605</span><br><span class="line">606</span><br><span class="line">607</span><br><span class="line">608</span><br><span class="line">609</span><br><span class="line">610</span><br><span class="line">611</span><br><span class="line">612</span><br><span class="line">613</span><br><span class="line">614</span><br><span class="line">615</span><br><span class="line">616</span><br><span class="line">617</span><br><span class="line">618</span><br><span class="line">619</span><br><span class="line">620</span><br><span class="line">621</span><br><span class="line">622</span><br><span class="line">623</span><br><span class="line">624</span><br><span class="line">625</span><br><span class="line">626</span><br><span class="line">627</span><br><span class="line">628</span><br><span class="line">629</span><br><span class="line">630</span><br><span class="line">631</span><br><span class="line">632</span><br><span class="line">633</span><br><span class="line">634</span><br><span class="line">635</span><br><span class="line">636</span><br><span class="line">637</span><br><span class="line">638</span><br><span class="line">639</span><br><span class="line">640</span><br><span class="line">641</span><br><span class="line">642</span><br><span class="line">643</span><br><span class="line">644</span><br><span class="line">645</span><br><span class="line">646</span><br><span class="line">647</span><br><span class="line">648</span><br><span class="line">649</span><br><span class="line">650</span><br><span class="line">651</span><br><span class="line">652</span><br><span class="line">653</span><br><span class="line">654</span><br><span class="line">655</span><br><span class="line">656</span><br><span class="line">657</span><br><span class="line">658</span><br><span class="line">659</span><br><span class="line">660</span><br><span class="line">661</span><br><span class="line">662</span><br><span class="line">663</span><br><span class="line">664</span><br><span class="line">665</span><br><span class="line">666</span><br><span class="line">667</span><br><span class="line">668</span><br><span class="line">669</span><br><span class="line">670</span><br><span class="line">671</span><br><span class="line">672</span><br><span class="line">673</span><br><span class="line">674</span><br><span class="line">675</span><br><span class="line">676</span><br><span class="line">677</span><br><span class="line">678</span><br><span class="line">679</span><br><span class="line">680</span><br><span class="line">681</span><br><span class="line">682</span><br><span class="line">683</span><br><span class="line">684</span><br><span class="line">685</span><br><span class="line">686</span><br><span class="line">687</span><br><span class="line">688</span><br><span class="line">689</span><br><span class="line">690</span><br><span class="line">691</span><br><span class="line">692</span><br><span class="line">693</span><br><span class="line">694</span><br><span class="line">695</span><br><span class="line">696</span><br><span class="line">697</span><br><span class="line">698</span><br><span class="line">699</span><br><span class="line">700</span><br><span class="line">701</span><br><span class="line">702</span><br><span class="line">703</span><br><span class="line">704</span><br><span class="line">705</span><br><span class="line">706</span><br><span class="line">707</span><br><span class="line">708</span><br><span class="line">709</span><br><span class="line">710</span><br><span class="line">711</span><br><span class="line">712</span><br><span class="line">713</span><br><span class="line">714</span><br><span class="line">715</span><br><span class="line">716</span><br><span class="line">717</span><br><span class="line">718</span><br><span class="line">719</span><br><span class="line">720</span><br><span class="line">721</span><br><span class="line">722</span><br><span class="line">723</span><br><span class="line">724</span><br><span class="line">725</span><br><span class="line">726</span><br><span class="line">727</span><br><span class="line">728</span><br><span class="line">729</span><br><span class="line">730</span><br><span class="line">731</span><br><span class="line">732</span><br><span class="line">733</span><br><span class="line">734</span><br><span class="line">735</span><br><span class="line">736</span><br><span class="line">737</span><br><span class="line">738</span><br><span class="line">739</span><br><span class="line">740</span><br><span class="line">741</span><br><span class="line">742</span><br><span class="line">743</span><br><span class="line">744</span><br><span class="line">745</span><br><span class="line">746</span><br><span class="line">747</span><br><span class="line">748</span><br><span class="line">749</span><br><span class="line">750</span><br><span class="line">751</span><br><span class="line">752</span><br><span class="line">753</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">'express'</span>)</span><br><span class="line"><span class="keyword">const</span> &#123; WebhookClient &#125; = <span class="built_in">require</span>(<span class="string">'dialogflow-fulfillment'</span>)</span><br><span class="line"><span class="keyword">const</span> app = express()</span><br><span class="line"><span class="keyword">const</span> fetch = <span class="built_in">require</span>(<span class="string">'node-fetch'</span>)</span><br><span class="line"><span class="keyword">const</span> base64 = <span class="built_in">require</span>(<span class="string">'base-64'</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> username = <span class="string">""</span>;</span><br><span class="line"><span class="keyword">let</span> password = <span class="string">""</span>;</span><br><span class="line"><span class="keyword">let</span> token = <span class="string">""</span>;</span><br><span class="line"><span class="keyword">let</span> products;</span><br><span class="line"><span class="keyword">let</span> filtered;</span><br><span class="line"></span><br><span class="line">USE_LOCAL_ENDPOINT = <span class="literal">false</span>;</span><br><span class="line"><span class="comment">// set this flag to true if you want to use a local endpoint</span></span><br><span class="line"><span class="comment">// set this flag to false if you want to use the online endpoint</span></span><br><span class="line">ENDPOINT_URL = <span class="string">""</span></span><br><span class="line"><span class="keyword">if</span> (USE_LOCAL_ENDPOINT) &#123;</span><br><span class="line">  ENDPOINT_URL = <span class="string">"http://127.0.0.1:5000"</span></span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">  ENDPOINT_URL = <span class="string">"XXX"</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">fetch(ENDPOINT_URL + <span class="string">'/products'</span>).then(<span class="function"><span class="params">res</span> =&gt;</span> res.json()).then(<span class="function"><span class="params">data</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> data.products) &#123;</span><br><span class="line">    fetch(ENDPOINT_URL + <span class="string">'/products/'</span> + i.id + <span class="string">"/tags"</span>).then(<span class="function"><span class="params">res</span> =&gt;</span> res.json()).then(<span class="function"><span class="params">data1</span> =&gt;</span> &#123;</span><br><span class="line">      i[<span class="string">"tags"</span>] = data1.tags;</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">  products = data</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">navigation</span>(<span class="params">back, dialogflow, page</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">let</span> request;</span><br><span class="line">  <span class="keyword">if</span> (page === <span class="literal">null</span>) &#123;</span><br><span class="line">    request = &#123;</span><br><span class="line">      method: <span class="string">'PUT'</span>,</span><br><span class="line">      headers: &#123;</span><br><span class="line">        <span class="string">'Content-Type'</span>: <span class="string">'application/json'</span>,</span><br><span class="line">        <span class="string">'x-access-token'</span>: token</span><br><span class="line">      &#125;,</span><br><span class="line">      body: <span class="built_in">JSON</span>.stringify(&#123;</span><br><span class="line">        <span class="string">"back"</span>: back,</span><br><span class="line">        <span class="string">"dialogflowUpdated"</span>: dialogflow</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    request = &#123;</span><br><span class="line">      method: <span class="string">'PUT'</span>,</span><br><span class="line">      headers: &#123;</span><br><span class="line">        <span class="string">'Content-Type'</span>: <span class="string">'application/json'</span>,</span><br><span class="line">        <span class="string">'x-access-token'</span>: token</span><br><span class="line">      &#125;,</span><br><span class="line">      body: <span class="built_in">JSON</span>.stringify(&#123;</span><br><span class="line">        <span class="string">"back"</span>: back,</span><br><span class="line">        <span class="string">"dialogflowUpdated"</span>: dialogflow,</span><br><span class="line">        <span class="string">"page"</span>: <span class="string">"/"</span> + page</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> serverReturn1 = <span class="keyword">await</span> fetch(ENDPOINT_URL + <span class="string">'/application'</span>, request)</span><br><span class="line">  <span class="keyword">const</span> serverResponse1 = <span class="keyword">await</span> serverReturn1.json()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">getToken</span>(<span class="params">message</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">let</span> request = &#123;</span><br><span class="line">    method: <span class="string">'GET'</span>,</span><br><span class="line">    headers: &#123;</span><br><span class="line">      <span class="string">'Content-Type'</span>: <span class="string">'application/json'</span>,</span><br><span class="line">      <span class="string">'Authorization'</span>: <span class="string">'Basic '</span> + base64.encode(username + <span class="string">':'</span> + password)</span><br><span class="line">    &#125;,</span><br><span class="line">    redirect: <span class="string">'follow'</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> serverReturn = <span class="keyword">await</span> fetch(ENDPOINT_URL + <span class="string">'/login'</span>, request)</span><br><span class="line">  <span class="keyword">if</span> (serverReturn.ok) &#123;</span><br><span class="line">    <span class="keyword">const</span> serverResponse = <span class="keyword">await</span> serverReturn.json()</span><br><span class="line">    token = serverResponse.token</span><br><span class="line"></span><br><span class="line">    request = &#123;</span><br><span class="line">      method: <span class="string">'PUT'</span>,</span><br><span class="line">      headers: &#123;</span><br><span class="line">        <span class="string">'Content-Type'</span>: <span class="string">'application/json'</span>,</span><br><span class="line">        <span class="string">'x-access-token'</span>: token</span><br><span class="line">      &#125;,</span><br><span class="line">      body: <span class="built_in">JSON</span>.stringify(&#123;</span><br><span class="line">        <span class="string">"back"</span>: <span class="literal">false</span>,</span><br><span class="line">        <span class="string">"dialogflowUpdated"</span>: <span class="literal">true</span>,</span><br><span class="line">        <span class="string">"page"</span>: <span class="string">"/"</span> + username</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> serverReturn2 = <span class="keyword">await</span> fetch(ENDPOINT_URL + <span class="string">'/application/messages'</span>, &#123;</span><br><span class="line">      method: <span class="string">'DELETE'</span>,</span><br><span class="line">      headers: &#123;</span><br><span class="line">        <span class="string">'x-access-token'</span>: token</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">    serverReturn2.json()</span><br><span class="line"></span><br><span class="line">    addUserMessage(message);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> serverReturn1 = <span class="keyword">await</span> fetch(ENDPOINT_URL + <span class="string">'/application'</span>, request)</span><br><span class="line">    <span class="keyword">const</span> serverResponse1 = <span class="keyword">await</span> serverReturn1.json()</span><br><span class="line"></span><br><span class="line">    <span class="comment">//console.log(products)</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> token;</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    username = <span class="string">""</span>;</span><br><span class="line">    password = <span class="string">""</span>;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">"fail"</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">addUserMessage</span>(<span class="params">user</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> serverReturn2 = <span class="keyword">await</span> fetch(ENDPOINT_URL + <span class="string">'/application/messages'</span>, &#123;</span><br><span class="line">    method: <span class="string">'POST'</span>,</span><br><span class="line">    headers: &#123;</span><br><span class="line">      <span class="string">'Content-Type'</span>: <span class="string">'application/json'</span>,</span><br><span class="line">      <span class="string">'x-access-token'</span>: token</span><br><span class="line">    &#125;,</span><br><span class="line">    body: <span class="built_in">JSON</span>.stringify(&#123;</span><br><span class="line">      <span class="string">"isUser"</span>: <span class="literal">true</span>,</span><br><span class="line">      <span class="string">"date"</span>: <span class="keyword">new</span> <span class="built_in">Date</span>().toISOString(),</span><br><span class="line">      <span class="string">"text"</span>: user</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;)</span><br><span class="line">  <span class="keyword">await</span> serverReturn2.json()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">addAgentMessage</span>(<span class="params">agent</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> serverReturn2 = <span class="keyword">await</span> fetch(ENDPOINT_URL + <span class="string">'/application/messages'</span>, &#123;</span><br><span class="line">    method: <span class="string">'POST'</span>,</span><br><span class="line">    headers: &#123;</span><br><span class="line">      <span class="string">'Content-Type'</span>: <span class="string">'application/json'</span>,</span><br><span class="line">      <span class="string">'x-access-token'</span>: token</span><br><span class="line">    &#125;,</span><br><span class="line">    body: <span class="built_in">JSON</span>.stringify(&#123;</span><br><span class="line">      <span class="string">"isUser"</span>: <span class="literal">false</span>,</span><br><span class="line">      <span class="string">"date"</span>: <span class="keyword">new</span> <span class="built_in">Date</span>().toISOString(),</span><br><span class="line">      <span class="string">"text"</span>: agent</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;)</span><br><span class="line">  <span class="keyword">await</span> serverReturn2.json()</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">app.get(<span class="string">'/'</span>, (req, res) =&gt; res.send(<span class="string">'online'</span>))</span><br><span class="line">app.post(<span class="string">'/'</span>, express.json(), (req, res) =&gt; &#123;</span><br><span class="line">  <span class="keyword">const</span> agent = <span class="keyword">new</span> WebhookClient(&#123; <span class="attr">request</span>: req, <span class="attr">response</span>: res &#125;)</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">function</span> <span class="title">welcome</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    agent.add(<span class="string">'Webhook works!'</span>)</span><br><span class="line">    <span class="built_in">console</span>.log(ENDPOINT_URL)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">login</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="comment">//console.log(products.products[0].tags);</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (token.localeCompare(<span class="string">""</span>) !== <span class="number">0</span>) &#123;</span><br><span class="line">      <span class="keyword">await</span> addUserMessage(agent.query);</span><br><span class="line">      agent.add(<span class="string">"You have logged in as "</span> + username);</span><br><span class="line">      <span class="keyword">await</span> addAgentMessage(<span class="string">"You have logged in as "</span> + username);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// You need to set this from `username` entity that you declare in DialogFlow</span></span><br><span class="line">    username = agent.parameters.username;</span><br><span class="line">    <span class="comment">// You need to set this from password entity that you declare in DialogFlow</span></span><br><span class="line">    password = agent.parameters.password;</span><br><span class="line">    <span class="keyword">await</span> getToken(agent.query);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (token.localeCompare(<span class="string">""</span>) === <span class="number">0</span>) &#123;</span><br><span class="line">      agent.add(<span class="string">"login failed, try again with login"</span>);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      agent.add(<span class="string">"Successfully logged in as "</span> + username);</span><br><span class="line">      addAgentMessage(<span class="string">"Successfully logged in as "</span> + username);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">loginStatus</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (token.localeCompare(<span class="string">""</span>) === <span class="number">0</span>) &#123;</span><br><span class="line">      <span class="keyword">if</span> (<span class="built_in">Math</span>.random() &gt; <span class="number">0.5</span>)</span><br><span class="line">        agent.add(<span class="string">"You are not logged in. "</span>);</span><br><span class="line">      <span class="keyword">else</span> agent.add(<span class="string">"Please log in at first"</span>);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="keyword">await</span> addUserMessage(agent.query);</span><br><span class="line">      <span class="keyword">if</span> (<span class="built_in">Math</span>.random() &lt; <span class="number">0.3</span>) &#123;</span><br><span class="line">        agent.add(<span class="string">"You are "</span> + username);</span><br><span class="line">        <span class="keyword">await</span> addAgentMessage(<span class="string">"You are "</span> + username);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">else</span> <span class="keyword">if</span> (<span class="built_in">Math</span>.random() &lt; <span class="number">0.6</span>) &#123;</span><br><span class="line">        agent.add(<span class="string">"You username is "</span> + username);</span><br><span class="line">        <span class="keyword">await</span> addAgentMessage(<span class="string">"You username is "</span> + username);</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        agent.add(<span class="string">"Hello, "</span> + username);</span><br><span class="line">        <span class="keyword">await</span> addAgentMessage(<span class="string">"Hello, "</span> + username);</span><br><span class="line"></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">queryCategories</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (token.localeCompare(<span class="string">""</span>) === <span class="number">0</span>) &#123;</span><br><span class="line">      <span class="comment">//ensure user is logged in</span></span><br><span class="line">      agent.add(<span class="string">"Invalid visit, please login first"</span>);</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//console.log(agent.parameters.category);</span></span><br><span class="line">    <span class="keyword">await</span> addUserMessage(agent.query);</span><br><span class="line">    <span class="keyword">await</span> navigation(<span class="literal">false</span>, <span class="literal">true</span>, username + <span class="string">"/"</span> + agent.parameters.category);</span><br><span class="line">    filtered = [];</span><br><span class="line">    <span class="keyword">let</span> k = [];</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> products.products) &#123;</span><br><span class="line">      <span class="keyword">if</span> (i.category.localeCompare(agent.parameters.category) === <span class="number">0</span>) &#123;</span><br><span class="line">        filtered.push(i);</span><br><span class="line">        k.push(i.name)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    agent.add(<span class="string">"I found "</span> + k.length === <span class="number">0</span> ? <span class="string">"nothing"</span> : k.toString() + <span class="string">" belongs to "</span> + agent.parameters.category)</span><br><span class="line">    addAgentMessage(<span class="string">"I found "</span> + k.length === <span class="number">0</span> ? <span class="string">"nothing"</span> : k.toString() + <span class="string">" belongs to "</span> + agent.parameters.category);</span><br><span class="line"></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">filterTags</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (token.localeCompare(<span class="string">""</span>) === <span class="number">0</span>) &#123;</span><br><span class="line">      <span class="comment">//ensure user is logged in</span></span><br><span class="line">      agent.add(<span class="string">"Invalid visit, please login first"</span>);</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">await</span> addUserMessage(agent.query)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> serve = <span class="keyword">await</span> fetch(ENDPOINT_URL + <span class="string">'/application/tags/'</span> + agent.parameters.tags, &#123;</span><br><span class="line">      method: <span class="string">'POST'</span>,</span><br><span class="line">      headers: &#123;</span><br><span class="line">        <span class="string">'x-access-token'</span>: token</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="keyword">await</span> serve.json()</span><br><span class="line">    <span class="keyword">if</span> (serve.ok) &#123;</span><br><span class="line">      <span class="keyword">let</span> k = <span class="string">" "</span>;</span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> filtered) &#123;</span><br><span class="line">        <span class="keyword">if</span> (i.tags.indexOf(agent.parameters.tags) !== <span class="number">-1</span>) &#123;</span><br><span class="line">          k += i.name + <span class="string">", "</span>;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">      agent.add(<span class="string">"Successfully add tag "</span> + agent.parameters.tags + <span class="string">", filtered items: "</span> + k)<span class="comment">//need filter and return something here</span></span><br><span class="line">      addAgentMessage(<span class="string">"Successfully add tag "</span> + agent.parameters.tags + <span class="string">", filtered items: "</span> + k)</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      agent.add(<span class="string">"Unknown problem happened"</span>);</span><br><span class="line">      addAgentMessage(<span class="string">"Unknown problem happened"</span>)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">clearTags</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (token.localeCompare(<span class="string">""</span>) === <span class="number">0</span>) &#123;</span><br><span class="line">      <span class="comment">//ensure user is logged in</span></span><br><span class="line">      agent.add(<span class="string">"Invalid visit, please login first"</span>);</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">await</span> addUserMessage(agent.query)</span><br><span class="line">    <span class="keyword">let</span> serve = <span class="keyword">await</span> fetch(ENDPOINT_URL + <span class="string">'/application/tags'</span>, &#123;</span><br><span class="line">      method: <span class="string">'DELETE'</span>,</span><br><span class="line">      headers: &#123;</span><br><span class="line">        <span class="string">'x-access-token'</span>: token</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="keyword">await</span> serve.json()</span><br><span class="line">    <span class="keyword">if</span> (serve.ok) &#123;</span><br><span class="line">      <span class="keyword">let</span> k = <span class="string">" "</span>;</span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> filtered) &#123;</span><br><span class="line">        k += i.name + <span class="string">", "</span>;</span><br><span class="line">      &#125;</span><br><span class="line">      agent.add(<span class="string">"Successfully cleared all tags filters, current items are "</span> + k)</span><br><span class="line">      addAgentMessage(<span class="string">"Successfully cleared all tags filters, current items are "</span> + k)</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      agent.add(<span class="string">"Unknown problem happened"</span>);</span><br><span class="line">      addAgentMessage(<span class="string">"Unknown problem happened"</span>)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">queryCategoryTag</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (token.localeCompare(<span class="string">""</span>) === <span class="number">0</span>) &#123;</span><br><span class="line">      <span class="comment">//ensure user is logged in</span></span><br><span class="line">      agent.add(<span class="string">"Invalid visit, please login first"</span>);</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">await</span> addUserMessage(agent.query)</span><br><span class="line">    <span class="keyword">let</span> serve = <span class="keyword">await</span> fetch(ENDPOINT_URL + <span class="string">'/application/tags'</span>, &#123;</span><br><span class="line">      method: <span class="string">'DELETE'</span>,</span><br><span class="line">      headers: &#123;</span><br><span class="line">        <span class="string">'x-access-token'</span>: token</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="keyword">await</span> serve.json()</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (serve.ok) &#123;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">await</span> navigation(<span class="literal">false</span>, <span class="literal">true</span>, username + <span class="string">"/"</span> + agent.parameters.category);</span><br><span class="line">      filtered = [];</span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> products.products) &#123;</span><br><span class="line">        <span class="keyword">if</span> (i.category.localeCompare(agent.parameters.category) === <span class="number">0</span>) &#123;</span><br><span class="line">          filtered.push(i);</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">let</span> serve1 = <span class="keyword">await</span> fetch(ENDPOINT_URL + <span class="string">'/application/tags/'</span> + agent.parameters.tags, &#123;</span><br><span class="line">        method: <span class="string">'POST'</span>,</span><br><span class="line">        headers: &#123;</span><br><span class="line">          <span class="string">'x-access-token'</span>: token</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;)</span><br><span class="line">      <span class="keyword">await</span> serve1.json()</span><br><span class="line">      <span class="keyword">if</span> (serve1.ok) &#123;</span><br><span class="line">        <span class="keyword">let</span> k = <span class="string">" "</span>;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> filtered) &#123;</span><br><span class="line">          <span class="keyword">if</span> (i.tags.indexOf(agent.parameters.tags) !== <span class="number">-1</span>) &#123;</span><br><span class="line">            k += i.name + <span class="string">", "</span>;</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        agent.add(<span class="string">"Successfully add tag "</span> + agent.parameters.tags + <span class="string">", filtered items: "</span> + k)<span class="comment">//need filter and return something here</span></span><br><span class="line">        addAgentMessage(<span class="string">"Successfully add tag "</span> + agent.parameters.tags + <span class="string">", filtered items: "</span> + k)</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        agent.add(<span class="string">"Unknown problem happened"</span>);</span><br><span class="line">        addAgentMessage(<span class="string">"Unknown problem happened"</span>)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      agent.add(<span class="string">"Unknown problem happened"</span>);</span><br><span class="line">      addAgentMessage(<span class="string">"Unknown problem happened"</span>)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">goBack</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (token.localeCompare(<span class="string">""</span>) === <span class="number">0</span>) &#123;</span><br><span class="line">      <span class="comment">//ensure user is logged in</span></span><br><span class="line">      agent.add(<span class="string">"Invalid visit, please login first"</span>);</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">await</span> addUserMessage(agent.query)</span><br><span class="line">    <span class="keyword">await</span> navigation(<span class="literal">true</span>, <span class="literal">true</span>, <span class="literal">null</span>);</span><br><span class="line">    agent.add(<span class="string">"Go back successfully"</span>);</span><br><span class="line">    <span class="keyword">await</span> addAgentMessage(<span class="string">"Go back successfully"</span>)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">productRating</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (token.localeCompare(<span class="string">""</span>) === <span class="number">0</span>) &#123;</span><br><span class="line">      <span class="comment">//ensure user is logged in</span></span><br><span class="line">      agent.add(<span class="string">"Invalid visit, please login first"</span>);</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">await</span> addUserMessage(agent.query);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> id;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> products.products) &#123;</span><br><span class="line">      <span class="keyword">if</span> (agent.parameters.product.indexOf(i.name) !== <span class="number">-1</span>) &#123;</span><br><span class="line">        id = i.id;</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> serve = <span class="keyword">await</span> fetch(ENDPOINT_URL + <span class="string">'/products/'</span> + id + <span class="string">"/reviews"</span>)</span><br><span class="line">    <span class="keyword">let</span> reviews = <span class="keyword">await</span> serve.json()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (reviews.reviews.length !== <span class="number">0</span>) &#123;</span><br><span class="line">      <span class="comment">//review exist</span></span><br><span class="line">      <span class="keyword">let</span> reviewText = [];</span><br><span class="line">      <span class="keyword">let</span> rating = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> reviews.reviews) &#123;</span><br><span class="line">        rating += i.stars;</span><br><span class="line">        <span class="keyword">if</span> (i.text.localeCompare(<span class="string">"&lt;Product Review Text&gt;"</span>) !== <span class="number">0</span>) &#123;</span><br><span class="line">          reviewText.push(<span class="string">"Title: "</span> + i.title)</span><br><span class="line">          reviewText.push(<span class="string">"Text: "</span> + i.text)</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      agent.add(<span class="string">"This items has the average rating of "</span> + (rating / reviews.reviews.length).toFixed(<span class="number">2</span>) + <span class="string">". It also contains comments of the following: "</span> + reviewText.toString())</span><br><span class="line">      addAgentMessage(<span class="string">"This items has the average rating of "</span> + (rating / reviews.reviews.length).toFixed(<span class="number">2</span>) + <span class="string">". It also contains comments of the following: "</span> + reviewText.toString())</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      agent.add(<span class="string">"Review do not exist"</span>)</span><br><span class="line">      addAgentMessage(<span class="string">"Review do not exist"</span>)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">viewProduct</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (token.localeCompare(<span class="string">""</span>) === <span class="number">0</span>) &#123;</span><br><span class="line">      <span class="comment">//ensure user is logged in</span></span><br><span class="line">      agent.add(<span class="string">"Invalid visit, please login first"</span>);</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">await</span> addUserMessage(agent.query);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> id;</span><br><span class="line">    <span class="keyword">let</span> catego;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> products.products) &#123;</span><br><span class="line">      <span class="keyword">if</span> (agent.parameters.product.toLocaleLowerCase().indexOf(i.name.toLocaleLowerCase()) !== <span class="number">-1</span>) &#123;</span><br><span class="line">        id = i.id;</span><br><span class="line">        catego = i.category;</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> serve = <span class="keyword">await</span> fetch(ENDPOINT_URL + <span class="string">'/products/'</span> + id + <span class="string">"/reviews"</span>)</span><br><span class="line">    <span class="keyword">let</span> reviews = <span class="keyword">await</span> serve.json()</span><br><span class="line"></span><br><span class="line">    navigation(<span class="literal">false</span>, <span class="literal">true</span>, username + <span class="string">"/"</span> + catego + <span class="string">"/products/"</span> + id)</span><br><span class="line">    agent.add(<span class="string">"Navigate you to "</span> + agent.parameters.product + <span class="string">"page"</span>)</span><br><span class="line">    addAgentMessage(<span class="string">"Navigate you to "</span> + agent.parameters.product + <span class="string">"page"</span>)</span><br><span class="line"></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">addProduct</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (token.localeCompare(<span class="string">""</span>) === <span class="number">0</span>) &#123;</span><br><span class="line">      <span class="comment">//ensure user is logged in</span></span><br><span class="line">      agent.add(<span class="string">"Invalid visit, please login first"</span>);</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">await</span> addUserMessage(agent.query);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> id = <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (agent.parameters.product.localeCompare(<span class="string">""</span>) === <span class="number">0</span> || agent.parameters.product.toLocaleLowerCase().indexOf(<span class="string">"product"</span>) !== <span class="number">-1</span>) &#123;</span><br><span class="line">      <span class="comment">//get info from page</span></span><br><span class="line">      <span class="keyword">const</span> serverReturn2 = <span class="keyword">await</span> fetch(ENDPOINT_URL + <span class="string">'/application/'</span>, &#123;</span><br><span class="line">        method: <span class="string">'GET'</span>,</span><br><span class="line">        headers: &#123;</span><br><span class="line">          <span class="string">'x-access-token'</span>: token</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;)</span><br><span class="line"></span><br><span class="line">      <span class="comment">//page field</span></span><br><span class="line">      <span class="keyword">let</span> result = <span class="keyword">await</span> serverReturn2.json()</span><br><span class="line">      result = result.page.split(<span class="string">"/"</span>);</span><br><span class="line">      <span class="keyword">if</span> (result.length &gt; <span class="number">2</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (result[result.length - <span class="number">2</span>].localeCompare(<span class="string">"products"</span>) === <span class="number">0</span>) &#123;</span><br><span class="line">          <span class="comment">//normal add</span></span><br><span class="line">          id = <span class="built_in">parseInt</span>(result[result.length - <span class="number">1</span>]);</span><br><span class="line"></span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">          agent.add(<span class="string">"You are not in a product page"</span>);</span><br><span class="line">          addAgentMessage(<span class="string">"You are not in a product page"</span>);</span><br><span class="line">          <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        agent.add(<span class="string">"You are not in a product page"</span>);</span><br><span class="line">        addAgentMessage(<span class="string">"You are not in a product page"</span>);</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="keyword">let</span> toFind = agent.parameters.product.toLocaleLowerCase();</span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> products.products) &#123;</span><br><span class="line">        <span class="keyword">let</span> tocompare = i.name.toLocaleLowerCase();</span><br><span class="line">        <span class="keyword">if</span> (toFind.indexOf(tocompare) !== <span class="number">-1</span>) &#123;</span><br><span class="line">          id = i.id;</span><br><span class="line">          <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (id === <span class="literal">null</span>) &#123;</span><br><span class="line">      agent.add(<span class="string">"Product name has problem"</span>);</span><br><span class="line">      addAgentMessage(<span class="string">"Product name has problem"</span>);</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//adding</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> serve = <span class="keyword">await</span> fetch(ENDPOINT_URL + <span class="string">'/application/products/'</span> + id, &#123;</span><br><span class="line">      method: <span class="string">'POST'</span>,</span><br><span class="line">      headers: &#123;</span><br><span class="line">        <span class="string">'Content-Type'</span>: <span class="string">'application/json'</span>,</span><br><span class="line">        <span class="string">'x-access-token'</span>: token</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line"></span><br><span class="line">    <span class="comment">//page field</span></span><br><span class="line">    <span class="keyword">await</span> serve.json()</span><br><span class="line">    <span class="keyword">if</span> (serve.ok) &#123;</span><br><span class="line">      agent.add(<span class="string">"Successfully added 1 of "</span> + agent.parameters.product + <span class="string">" to your cart"</span>)</span><br><span class="line">      addAgentMessage(<span class="string">"Successfully added 1 of "</span> + agent.parameters.product + <span class="string">" to your cart"</span>)</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      agent.add(<span class="string">"Failed with server problem"</span>);</span><br><span class="line">      addAgentMessage(<span class="string">"Failed with server problem"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">cleanCart</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (token.localeCompare(<span class="string">""</span>) === <span class="number">0</span>) &#123;</span><br><span class="line">      <span class="comment">//ensure user is logged in</span></span><br><span class="line">      agent.add(<span class="string">"Invalid visit, please login first"</span>);</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">await</span> addUserMessage(agent.query);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> serve = <span class="keyword">await</span> fetch(ENDPOINT_URL + <span class="string">'/application/products/'</span>, &#123;</span><br><span class="line">      method: <span class="string">'DELETE'</span>,</span><br><span class="line">      headers: &#123;</span><br><span class="line">        <span class="string">'Content-Type'</span>: <span class="string">'application/json'</span>,</span><br><span class="line">        <span class="string">'x-access-token'</span>: token</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">await</span> serve.json()</span><br><span class="line">    <span class="keyword">if</span> (serve.ok) &#123;</span><br><span class="line">      agent.add(<span class="string">"Successfully cleaned your cart"</span>)</span><br><span class="line">      addAgentMessage(<span class="string">"Successfully cleaned your cart"</span>)</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      agent.add(<span class="string">"Failed with server problem"</span>);</span><br><span class="line">      addAgentMessage(<span class="string">"Failed with server problem"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">removeProduct</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (token.localeCompare(<span class="string">""</span>) === <span class="number">0</span>) &#123;</span><br><span class="line">      <span class="comment">//ensure user is logged in</span></span><br><span class="line">      agent.add(<span class="string">"Invalid visit, please login first"</span>);</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">await</span> addUserMessage(agent.query);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> id = <span class="literal">null</span>;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> products.products) &#123;</span><br><span class="line">      <span class="keyword">if</span> (agent.parameters.product.toLocaleLowerCase().indexOf(i.name.toLocaleLowerCase()) !== <span class="number">-1</span>) &#123;</span><br><span class="line">        id = i.id;</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (id === <span class="literal">null</span>) &#123;</span><br><span class="line">      agent.add(<span class="string">"Product name has problem"</span>);</span><br><span class="line">      addAgentMessage(<span class="string">"Product name has problem"</span>);</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> serve = <span class="keyword">await</span> fetch(ENDPOINT_URL + <span class="string">'/application/products/'</span> + id, &#123;</span><br><span class="line">      method: <span class="string">'DELETE'</span>,</span><br><span class="line">      headers: &#123;</span><br><span class="line">        <span class="string">'Content-Type'</span>: <span class="string">'application/json'</span>,</span><br><span class="line">        <span class="string">'x-access-token'</span>: token</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">await</span> serve.json()</span><br><span class="line">    <span class="keyword">if</span> (serve.ok) &#123;</span><br><span class="line">      agent.add(<span class="string">"Successfully removed 1 of "</span> + agent.parameters.product + <span class="string">" from your cart"</span>)</span><br><span class="line">      addAgentMessage(<span class="string">"Successfully removed 1 of "</span> + agent.parameters.product + <span class="string">" from your cart"</span>)</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      agent.add(<span class="string">"Failed with server problem"</span>);</span><br><span class="line">      addAgentMessage(<span class="string">"Failed with server problem"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">navigatePage</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (token.localeCompare(<span class="string">""</span>) === <span class="number">0</span>) &#123;</span><br><span class="line">      <span class="comment">//ensure user is logged in</span></span><br><span class="line">      agent.add(<span class="string">"Invalid visit, please login first"</span>);</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">await</span> addUserMessage(agent.query);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> findContent = agent.parameters.pages.toLocaleLowerCase();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (findContent.indexOf(<span class="string">"home"</span>) !== <span class="number">-1</span>) &#123;</span><br><span class="line">      navigation(<span class="literal">false</span>, <span class="literal">true</span>, username)</span><br><span class="line">      agent.add(<span class="string">"Navigating you to home..."</span>);</span><br><span class="line">      addAgentMessage(<span class="string">"Navigating you to home..."</span>);</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> (findContent.indexOf(<span class="string">"review"</span>) !== <span class="number">-1</span>) &#123;</span><br><span class="line">      navigation(<span class="literal">false</span>, <span class="literal">true</span>, username + <span class="string">"/cart-review"</span>)</span><br><span class="line">      agent.add(<span class="string">"Navigating you to cart-review..."</span>);</span><br><span class="line">      addAgentMessage(<span class="string">"Navigating you to cart-review..."</span>);</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (findContent.indexOf(<span class="string">"confirm"</span>) !== <span class="number">-1</span>) &#123;</span><br><span class="line">      <span class="keyword">const</span> serverReturn2 = <span class="keyword">await</span> fetch(ENDPOINT_URL + <span class="string">'/application/'</span>, &#123;</span><br><span class="line">        method: <span class="string">'GET'</span>,</span><br><span class="line">        headers: &#123;</span><br><span class="line">          <span class="string">'x-access-token'</span>: token</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;)</span><br><span class="line"></span><br><span class="line">      <span class="comment">//page field</span></span><br><span class="line">      <span class="keyword">let</span> result = <span class="keyword">await</span> serverReturn2.json()</span><br><span class="line">      result = result.page.split(<span class="string">"/"</span>);</span><br><span class="line">      <span class="keyword">if</span> (result.length &gt; <span class="number">1</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (result[result.length - <span class="number">1</span>].localeCompare(<span class="string">"cart-review"</span>) === <span class="number">0</span>) &#123;</span><br><span class="line"></span><br><span class="line">          navigation(<span class="literal">false</span>, <span class="literal">true</span>, username + <span class="string">"/cart-confirmed"</span>)</span><br><span class="line">          agent.add(<span class="string">"Navigating you to cart-confirmed..."</span>);</span><br><span class="line">          addAgentMessage(<span class="string">"Navigating you to cart-confirmed..."</span>);</span><br><span class="line">          <span class="keyword">return</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">          agent.add(<span class="string">"You are not in a cart review page"</span>);</span><br><span class="line">          addAgentMessage(<span class="string">"You are not in a cart review page"</span>);</span><br><span class="line">          <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        agent.add(<span class="string">"You are not in a cart review page"</span>);</span><br><span class="line">        addAgentMessage(<span class="string">"You are not in a cart review page"</span>);</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (findContent.indexOf(<span class="string">"cart"</span>) !== <span class="number">-1</span>) &#123;</span><br><span class="line">      navigation(<span class="literal">false</span>, <span class="literal">true</span>, username + <span class="string">"/cart"</span>)</span><br><span class="line">      agent.add(<span class="string">"Navigating you to cart..."</span>);</span><br><span class="line">      addAgentMessage(<span class="string">"Navigating you to cart..."</span>);</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">cartInfo</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (token.localeCompare(<span class="string">""</span>) === <span class="number">0</span>) &#123;</span><br><span class="line">      <span class="comment">//ensure user is logged in</span></span><br><span class="line">      agent.add(<span class="string">"Invalid visit, please login first"</span>);</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">await</span> addUserMessage(agent.query);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> serve = <span class="keyword">await</span> fetch(ENDPOINT_URL + <span class="string">'/application/products/'</span>, &#123;</span><br><span class="line">      method: <span class="string">'GET'</span>,</span><br><span class="line">      headers: &#123;</span><br><span class="line">        <span class="string">'Content-Type'</span>: <span class="string">'application/json'</span>,</span><br><span class="line">        <span class="string">'x-access-token'</span>: token</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> cart = <span class="keyword">await</span> serve.json();</span><br><span class="line">    cart = cart.products;</span><br><span class="line">    navigation(<span class="literal">false</span>, <span class="literal">true</span>, username + <span class="string">"/cart"</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> findContent = agent.parameters.cartInformation.toLocaleLowerCase();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (findContent.indexOf(<span class="string">"number"</span>) !== <span class="number">-1</span>) &#123;</span><br><span class="line">      <span class="keyword">let</span> k = <span class="number">0</span>;</span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> cart) &#123;</span><br><span class="line">        k += i.count;</span><br><span class="line">      &#125;</span><br><span class="line">      agent.add(<span class="string">"You have "</span> + k + <span class="string">" items in your cart"</span>);</span><br><span class="line">      addAgentMessage(<span class="string">"You have "</span> + k + <span class="string">" items in your cart"</span>);</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (findContent.indexOf(<span class="string">"cost"</span>) !== <span class="number">-1</span> || findContent.indexOf(<span class="string">"price"</span>) !== <span class="number">-1</span>) &#123;</span><br><span class="line">      <span class="keyword">let</span> k = <span class="number">0</span>;</span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> cart) &#123;</span><br><span class="line">        k += i.count * i.price;</span><br><span class="line">      &#125;</span><br><span class="line">      agent.add(<span class="string">"Total price is "</span> + k.toFixed(<span class="number">2</span>) + <span class="string">" in your cart"</span>);</span><br><span class="line">      addAgentMessage(<span class="string">"Total price is "</span> + k.toFixed(<span class="number">2</span>) + <span class="string">" in your cart"</span>);</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (findContent.indexOf(<span class="string">"type"</span>) !== <span class="number">-1</span>) &#123;<span class="comment">//assume to be category</span></span><br><span class="line">      <span class="keyword">let</span> k = [];</span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> cart) &#123;</span><br><span class="line">        <span class="keyword">if</span> (k.indexOf(i.category) === <span class="number">-1</span>) &#123;</span><br><span class="line">          k.push(i.category);</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">      agent.add(<span class="string">"You have items belong to the following categories "</span> + k.length === <span class="number">0</span> ? <span class="string">"nothing"</span> : k.toString() + <span class="string">" in your cart"</span>);</span><br><span class="line">      addAgentMessage(<span class="string">"You have items belong to the following categories "</span> + k.length === <span class="number">0</span> ? <span class="string">"nothing"</span> : k.toString() + <span class="string">" in your cart"</span>);</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (findContent.indexOf(<span class="string">"item"</span>) !== <span class="number">-1</span>) &#123;<span class="comment">//assume to be items name + count</span></span><br><span class="line">      <span class="keyword">let</span> k = [];</span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> cart) &#123;</span><br><span class="line">        k.push(i.count + <span class="string">" of "</span> + i.name);</span><br><span class="line">      &#125;</span><br><span class="line">      agent.add(<span class="string">"You have items "</span> + k.length === <span class="number">0</span> ? <span class="string">"nothing"</span> : k.toString() + <span class="string">" in your cart"</span>);</span><br><span class="line">      addAgentMessage(<span class="string">"You have items "</span> + k.length === <span class="number">0</span> ? <span class="string">"nothing"</span> : k.toString() + <span class="string">" in your cart"</span>);</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//entering default, all info</span></span><br><span class="line">    <span class="keyword">let</span> toSend = <span class="string">""</span>;</span><br><span class="line">    <span class="keyword">let</span> k = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> cart) &#123;</span><br><span class="line">      k += i.count;</span><br><span class="line">    &#125;</span><br><span class="line">    toSend += <span class="string">"You have "</span> + k + <span class="string">" items in your cart "</span>;</span><br><span class="line"></span><br><span class="line">    k = <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> cart) &#123;</span><br><span class="line">      k += i.count * i.price;</span><br><span class="line">    &#125;</span><br><span class="line">    toSend += <span class="string">"Total price is "</span> + k.toFixed(<span class="number">2</span>) + <span class="string">" in your cart "</span>;</span><br><span class="line"></span><br><span class="line">    k = [];</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> cart) &#123;</span><br><span class="line">      <span class="keyword">if</span> (k.indexOf(i.category) === <span class="number">-1</span>) &#123;</span><br><span class="line">        k.push(i.category);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    toSend += <span class="string">"You have items belong to the following categories "</span> + k.toString() + <span class="string">" in your cart"</span>;</span><br><span class="line"></span><br><span class="line">    k = [];</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i <span class="keyword">of</span> cart) &#123;</span><br><span class="line">      k.push(i.count + <span class="string">" of "</span> + i.name);</span><br><span class="line">    &#125;</span><br><span class="line">    toSend += <span class="string">"You have items "</span> + k.toString() + <span class="string">" in your cart"</span>;</span><br><span class="line"></span><br><span class="line">    agent.add(toSend);</span><br><span class="line">    addAgentMessage(toSend);</span><br><span class="line"></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> intentMap = <span class="keyword">new</span> <span class="built_in">Map</span>()</span><br><span class="line">  intentMap.set(<span class="string">'Default Welcome Intent'</span>, welcome)</span><br><span class="line">  <span class="comment">// You will need to declare this `Login` content in DialogFlow to make this work</span></span><br><span class="line"></span><br><span class="line">  intentMap.set(<span class="string">'LoginStatus'</span>, loginStatus)</span><br><span class="line">  intentMap.set(<span class="string">'login'</span>, login)</span><br><span class="line">  intentMap.set(<span class="string">'queryCategories'</span>, queryCategories)</span><br><span class="line">  intentMap.set(<span class="string">'filterTags'</span>, filterTags)</span><br><span class="line">  intentMap.set(<span class="string">'clearTags'</span>, clearTags)</span><br><span class="line">  intentMap.set(<span class="string">'queryCategoryTag'</span>, queryCategoryTag)</span><br><span class="line">  intentMap.set(<span class="string">'goBack'</span>, goBack)</span><br><span class="line">  intentMap.set(<span class="string">'productRating'</span>, productRating)</span><br><span class="line">  intentMap.set(<span class="string">'viewProduct'</span>, viewProduct)</span><br><span class="line">  intentMap.set(<span class="string">'addProduct'</span>, addProduct)</span><br><span class="line">  intentMap.set(<span class="string">'cleanCart'</span>, cleanCart)</span><br><span class="line">  intentMap.set(<span class="string">'removeProduct'</span>, removeProduct)</span><br><span class="line">  intentMap.set(<span class="string">'removeProduct'</span>, removeProduct)</span><br><span class="line">  intentMap.set(<span class="string">'navigatePage'</span>, navigatePage)</span><br><span class="line">  intentMap.set(<span class="string">'cartInfo'</span>, cartInfo)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">  agent.handleRequest(intentMap)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">app.listen(process.env.PORT || <span class="number">8080</span>)</span><br></pre></td></tr></table></figure>]]></content:encoded>
      
      
      <category domain="https://shaokang.me/categories/Programs/">Programs</category>
      
      <category domain="https://shaokang.me/categories/Programs/Coursework/">Coursework</category>
      
      
      <category domain="https://shaokang.me/tags/Dialogflow/">Dialogflow</category>
      
      
      <comments>https://shaokang.me/2020/a-dialog-flow-app/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Build Cloudflare worker with endpoint</title>
      <link>https://shaokang.me/2020/projects/Build-Cloudflare-worker-with-endpoint/</link>
      <guid>https://shaokang.me/2020/projects/Build-Cloudflare-worker-with-endpoint/</guid>
      <pubDate>Sat, 05 Dec 2020 20:50:27 GMT</pubDate>
      
      <description>&lt;p&gt;Cloudflare worker is a serverless application based on v9 engine. The structure is a little bit different than the Node.js. Endpoints is familiar to most people in developing. But this seems to be different on worker. And it is useful especially when different services is running in the same worker. This one will show how to integrate traditional endpoint feature on cloudflare worker to likely have a fake endpoint handler. This is a sub-project of Financial website.&lt;/p&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p>Cloudflare worker is a serverless application based on v9 engine. The structure is a little bit different than the Node.js. Endpoints is familiar to most people in developing. But this seems to be different on worker. And it is useful especially when different services is running in the same worker. This one will show how to integrate traditional endpoint feature on cloudflare worker to likely have a fake endpoint handler. This is a sub-project of Financial website.</p><a id="more"></a><h3 id="end-points"><a class="markdownIt-Anchor" href="#end-points"></a> End-points:</h3><p>Three end points is in this sample, they are arranged in three different purpose.</p><blockquote><p>Check the <a href="https://shaokangjiang.github.io/2021/AES-Encrypt-and-Decrypt-on-Cloudflare-worker/" target="_blank" rel="noopener">AES Encrypt and Decrypt on Cloudflare worker</a> to see the encryption and decryption methods using in <code>/authenticate</code> and <code>/generate</code>, which is based on <code>AES-GCM</code></p></blockquote><p><code>/authenticate</code> return a password if the information, like <code>token</code> and <code>quizepartcode</code> matched with our record. Otherwise, return false;</p><p><code>/generate</code> Generate a user learning progress, will need quizpartcode in the body.</p><p><code>/sendmail</code> with a password as authentication to send email via sendgrid from <a href="mailto:admin@capitaltwo.ga" target="_blank" rel="noopener">admin@capitaltwo.ga</a>. This method is not enabled as sendgrid has been blocked by a lot of client.</p><h3 id="initial-handling"><a class="markdownIt-Anchor" href="#initial-handling"></a> Initial Handling</h3><p>In each fetch request to worker, there will be a request with content pass to the worker, usually and officially returning method is</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">addEventListener(<span class="string">'fetch'</span>, event =&gt; &#123;</span><br><span class="line">  event.respondWith(handleRequest(event.request))</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h3 id="reroute-request"><a class="markdownIt-Anchor" href="#reroute-request"></a> Reroute Request</h3><p>Even though Worker is just JavaScript running on v8, we could just create a function to reroute each request based on the address user is requesting, like</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">(endpoint, fn) =&gt; &#123;</span><br><span class="line">      url = <span class="keyword">new</span> URL(request.url);</span><br><span class="line">      <span class="keyword">if</span> (url.pathname === endpoint &amp;&amp; request.method === <span class="string">"POST"</span>)</span><br><span class="line">        <span class="keyword">return</span> fn(request);</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">null</span>;</span><br></pre></td></tr></table></figure><p>In javascript, functions could wrapped using a variable, so, it is possible to create an object to contain everything, like</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> app = &#123;</span><br><span class="line">  <span class="keyword">get</span>: (endpoint, fn) =&gt; &#123; <span class="comment">// for get request</span></span><br><span class="line">    url = <span class="keyword">new</span> URL(request.url);</span><br><span class="line">    <span class="keyword">if</span> (url.pathname === endpoint &amp;&amp; request.method === <span class="string">"GET"</span>)</span><br><span class="line">      <span class="keyword">return</span> fn(request);</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">  &#125;,</span><br><span class="line">  post: <span class="function">(<span class="params">endpoint, fn</span>) =&gt;</span> &#123;</span><br><span class="line">    url = <span class="keyword">new</span> URL(request.url);</span><br><span class="line">    <span class="keyword">if</span> (url.pathname === endpoint &amp;&amp; request.method === <span class="string">"POST"</span>)</span><br><span class="line">      <span class="keyword">return</span> fn(request);</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h3 id="return-a-response"><a class="markdownIt-Anchor" href="#return-a-response"></a> Return a <code>Response</code></h3><p>Whenever needed in <code>handleRequest</code>, it is as easy as calling <code>app.post(&quot;/endPoint&quot;, functionName)</code>. And if null is returned, check next endpoint, otherwise the correct function will be called and executed. The reroute function like this:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * reroute</span></span><br><span class="line"><span class="comment"> * @param &#123;Request&#125; request</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">handleRequest</span>(<span class="params">request</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> app = &#123;</span><br><span class="line">    <span class="keyword">get</span>: (endpoint, fn) =&gt; &#123; <span class="comment">// for get request</span></span><br><span class="line">      url = <span class="keyword">new</span> URL(request.url);</span><br><span class="line">      <span class="keyword">if</span> (url.pathname === endpoint &amp;&amp; request.method === <span class="string">"GET"</span>)</span><br><span class="line">        <span class="keyword">return</span> fn(request);</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">    &#125;,</span><br><span class="line">    post: <span class="function">(<span class="params">endpoint, fn</span>) =&gt;</span> &#123;</span><br><span class="line">      url = <span class="keyword">new</span> URL(request.url);</span><br><span class="line">      <span class="keyword">if</span> (url.pathname === endpoint &amp;&amp; request.method === <span class="string">"POST"</span>)</span><br><span class="line">        <span class="keyword">return</span> fn(request);</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;;</span><br><span class="line">  <span class="keyword">let</span> lastResponse = app.post(<span class="string">"/authenticate"</span>, handleAuthen)</span><br><span class="line">  <span class="keyword">if</span> (lastResponse) &#123;</span><br><span class="line">    <span class="keyword">return</span> lastResponse;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  lastResponse = app.post(<span class="string">"/generate"</span>, handleGen)</span><br><span class="line">  <span class="keyword">if</span> (lastResponse) &#123;</span><br><span class="line">    <span class="keyword">return</span> lastResponse;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  lastResponse = app.post(<span class="string">"/sendmail"</span>, sendMail)</span><br><span class="line">  <span class="keyword">if</span> (lastResponse) &#123;</span><br><span class="line">    <span class="keyword">return</span> lastResponse;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> Response(<span class="string">'&#123;"message":"Hello! Default is touched."&#125;'</span>, notFoundHead);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>notFoundHead</code> is the head content created as a js Object, like</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> notFoundHead = &#123;</span><br><span class="line">  status: <span class="string">'404'</span>,</span><br><span class="line">  statusText: <span class="string">'NOT FOUND'</span>,</span><br><span class="line">  headers: &#123;</span><br><span class="line">    <span class="string">'Content-Type'</span>: <span class="string">'application/json;charset=utf-8'</span>,</span><br><span class="line">    <span class="string">'Access-Control-Allow-Origin'</span>: <span class="string">'https://capitaltwo.ga'</span>,</span><br><span class="line">    <span class="string">'Access-Control-Allow-Methods'</span>: <span class="string">'GET,POST,PUT,DELETE'</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p><strong>Caution:</strong> Without a head containing the <code>Access-Control-Allow-Origin</code>, CORS error will be posted. Cloudflare worker seems to be strict on this thing. If any error or exception happened without any <code>try</code> … <code>catch</code>, CORS will also be given. So, to be convenient in debugging, a good practice is always to return a Not found header when error happened in some cases.</p><p>If method other than <code>GET</code> is used, <code>Access-Control-Allow-Methods</code> should also be used. Otherwise, CORS error would also happen.</p><p>And when posting fetch request, do not append header in this example because it is not appropriately handled and it might have problem in this case.</p></blockquote><p>One function in the sample is <code>handleAuthen</code>, and one another is <code>handleGen</code>. Those two are normal functions and just return a new <code>Response</code> at last would be fine. Like:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * @param &#123;*&#125; request </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">handleAuthen</span>(<span class="params">request</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> data = <span class="keyword">await</span> request.json();</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> Response(<span class="built_in">JSON</span>.stringify(&#123;</span><br><span class="line">  XXX: XXX&#125;), Header)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="visiting-data-part-in-request"><a class="markdownIt-Anchor" href="#visiting-data-part-in-request"></a> Visiting Data part in request</h3><p>Because the data section of the request is a <code>Promise</code> object, it has to be called with <code>await</code> and <code>.json()</code> in order to visit it. Like: <code>var data = await request.json();</code>.</p><h3 id="sendmail-through-sendgrid"><a class="markdownIt-Anchor" href="#sendmail-through-sendgrid"></a> SendMail through sendgrid</h3><p>In the real case, sending a mail to the user is general. And sometimes, we have certain sensitive data that should not be promoted to client. This could be implemented through the following method in worker and called in client like this. That is what the third endpoint <code>/sendmail</code> is doing. like:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * @param &#123;*&#125; request </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">sendMail</span>(<span class="params">request</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">let</span> a = <span class="keyword">await</span> fetch(<span class="string">"https://api.sendgrid.com/v3/mail/send"</span>, &#123;</span><br><span class="line">    method: <span class="string">"POST"</span>,</span><br><span class="line">    headers: &#123;</span><br><span class="line">      <span class="string">"Authorization"</span>: <span class="string">"Bearer SG.P_Xcg7PmRgirESQCCXXX...Tm1xo7tz5w"</span>,</span><br><span class="line">      <span class="string">"Content-Type"</span>: <span class="string">"application/json"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    body: <span class="built_in">JSON</span>.stringify(&#123;</span><br><span class="line">      <span class="string">"personalizations"</span>: [</span><br><span class="line">        &#123;</span><br><span class="line">          <span class="string">"to"</span>: [</span><br><span class="line">            &#123;</span><br><span class="line">              <span class="string">"email"</span>: <span class="string">"admin@capitaltwo.ga"</span></span><br><span class="line">            &#125;</span><br><span class="line">          ]</span><br><span class="line">        &#125;</span><br><span class="line">      ],</span><br><span class="line">      <span class="string">"from"</span>: &#123;</span><br><span class="line">        <span class="string">"email"</span>: <span class="string">"admin@capitaltwo.ga"</span></span><br><span class="line">      &#125;,</span><br><span class="line">      <span class="string">"subject"</span>: <span class="string">"Sending with SendGrid is Fun"</span>,</span><br><span class="line">      <span class="string">"content"</span>: [</span><br><span class="line">        &#123;</span><br><span class="line">          <span class="string">"type"</span>: <span class="string">"text/plain"</span>,</span><br><span class="line">          <span class="string">"value"</span>: <span class="string">"and easy to do anywhere, even with cURL"</span></span><br><span class="line">        &#125;</span><br><span class="line">      ]</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (a.ok) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> Response(<span class="string">'&#123;"message":"successfully sent"&#125;'</span>, normalHeader)</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    <span class="keyword">let</span> k = <span class="keyword">await</span> a.json();</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> Response(<span class="built_in">JSON</span>.stringify(k), normalHeader)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p><strong>Caution:</strong> <code>sendgrid</code> will not return anything if the response status is ok, which could be checked with <code>a.ok</code> in the previous sample. If wrong, a data will be returned and could be decoded to json Object</p></blockquote><h3 id="run"><a class="markdownIt-Anchor" href="#run"></a> Run</h3><p>In order to run and test locally, you need to install <a href="https://developers.cloudflare.com/workers/cli-wrangler/install-update" target="_blank" rel="noopener">Cloudflare Worker Local client</a> first.</p><p>Then do:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wrangler dev</span><br></pre></td></tr></table></figure>]]></content:encoded>
      
      
      <category domain="https://shaokang.me/categories/website/">website</category>
      
      <category domain="https://shaokang.me/categories/website/Cloudflare-Worker/">Cloudflare Worker</category>
      
      
      <category domain="https://shaokang.me/tags/JS/">JS</category>
      
      
      <comments>https://shaokang.me/2020/projects/Build-Cloudflare-worker-with-endpoint/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Financial organization phone app - stage 1</title>
      <link>https://shaokang.me/2020/Financial-organization-phone-application/</link>
      <guid>https://shaokang.me/2020/Financial-organization-phone-application/</guid>
      <pubDate>Sat, 05 Dec 2020 13:52:55 GMT</pubDate>
      
      <description>&lt;p&gt;This is an app provide a easy to use interface to help user organize their spendings/earning and see a summary and guidance by visiting yearly budgeting tool on capitaltwo’s tools page, which will generate those results based on user’s history spending and provide user guidance about their future spending. User is able to provide an importance level to each future spending to guide system which item should be fulfilled at first. System will also intelligently detect user’s past earning and spending and ensure user’s future spending/earning include those fixed monthly/bi-monthly income/expense. Everything is done locally without risk of leaking privacy information. The stage 1 of the app provide a wonderful, easy to use interface and basic functionality, together with cross platform support, including android, ios. More details is in below. Dark and light theme is following user’s system default. This app is done solely by me.&lt;/p&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p>This is an app provide a easy to use interface to help user organize their spendings/earning and see a summary and guidance by visiting yearly budgeting tool on capitaltwo’s tools page, which will generate those results based on user’s history spending and provide user guidance about their future spending. User is able to provide an importance level to each future spending to guide system which item should be fulfilled at first. System will also intelligently detect user’s past earning and spending and ensure user’s future spending/earning include those fixed monthly/bi-monthly income/expense. Everything is done locally without risk of leaking privacy information. The stage 1 of the app provide a wonderful, easy to use interface and basic functionality, together with cross platform support, including android, ios. More details is in below. Dark and light theme is following user’s system default. This app is done solely by me.</p><a id="more"></a><h3 id="usage"><a class="markdownIt-Anchor" href="#usage"></a> Usage</h3><p>Select past date for your spent or income, and select the future date for the stuff you planned. Expense and Income in a future date consider as whatever you plan to do or have, in a past date will be considered as whatever you have done. If an expense or income have a high occurence ratio, like exist &gt;50%, future income and expense will be calculated based on this. So, do not add recurring expense or income in a future date as they will be considered as extra income/plan to buy(like wishlist). And the order of expense category will be used to fulfill this wishlist in order.</p><p><strong>Categories:</strong> Expense is orderable, order is the importancec level, Income are all important</p><h3 id="features"><a class="markdownIt-Anchor" href="#features"></a> Features</h3><p>This app is an organization app contains basic functions, such as add, edit, delete, batch deletion, reorder categories, remove empty categories. A short demo:</p><p>First demo is to show the basic appearance, including add, delete, reorder in dark theme:</p><p><img src="https://github.com/ShaokangJiang/React-Helper/releases/download/0.0/demo1.gif" alt></p><p>Second demo is to show some appearance in light theme:</p><p><img src="https://github.com/ShaokangJiang/React-Helper/releases/download/0.0/demo2.gif" alt></p><h3 id="running"><a class="markdownIt-Anchor" href="#running"></a> Running</h3><p>Click <a href="https://github.com/CapitalTwo/CapitalTwo-Financial" target="_blank" rel="noopener">here</a> for source code.</p><p>Click <a href="https://expo.io/@huangsk100/projects/CapitalTwo-Financial" target="_blank" rel="noopener">here</a> for an expo runable version.</p><p><a href="https://github.com/CapitalTwo/CapitalTwo-Financial/releases/download/0.1.0/CapitalTwo-Financial-android.apk" target="_blank" rel="noopener">Download Apk for android</a></p><p><a href="https://github.com/CapitalTwo/CapitalTwo-Financial/releases/download/0.1.0/CapitalTwo-Financial-ios.tar.gz" target="_blank" rel="noopener">Download for ios</a></p><h3 id="compile-from-source"><a class="markdownIt-Anchor" href="#compile-from-source"></a> Compile from source</h3><p>To compile and run locally:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> https://github.com/CapitalTwo/CapitalTwo-Financial.git</span><br><span class="line"><span class="built_in">cd</span> CapitalTwo-Financial</span><br><span class="line">npm install</span><br><span class="line">expo install</span><br><span class="line">expo start</span><br></pre></td></tr></table></figure><p>And use our phone to scan the QR code on screen.</p><h3 id="span-classcard-titleyearly-budgeting-toolspan"><a class="markdownIt-Anchor" href="#span-classcard-titleyearly-budgeting-toolspan"></a> <span class="card-title">Yearly Budgeting Tool</span></h3><p>This Budgeting tools allows you to create a spending plan for your money and see your past spending more interactively, it ensures that you will have enough money for your top priorities which you can assign in the app. Budget plan will also keep you out of debt or help you work your<br>way out of debt if you currently in debt. Starting by adding some information in the next page.</p><h4 id="methods-behind-this"><a class="markdownIt-Anchor" href="#methods-behind-this"></a> Methods behind this</h4><p>User could type their money on each category or item with an importance level associated to it. With those information, we will solve it by using an optimization rules. User could choose either optimizing saving or optimizing consuming (maybe another word at here).</p><p>User will have choices to indicate if this is a one time purchase or not, like wishlist. Then we will make a plan to tell user when would be the best time to buy it. And in order to achieve this goal, what they should do in each month.</p><p>In this category, we will consider the saved money will be used in some low-risk investment, like 0.036 APR. The report generated would be the item should be bought at that month.</p><p>We could support up to 100 level of priority, but priority of 1 is the essential stuff, like housing, foods. Snacks might be in a lower priority.</p><h6 id="optimize-saving"><a class="markdownIt-Anchor" href="#optimize-saving"></a> Optimize saving</h6><p>This process doesn’t require optimization, thought it could be used to reach this purpose. But it might be as easy as loop through the list and select all components that have a priority level of 1. Sample methods as below:</p><img src="/2020/Financial-organization-phone-application/alg1.png"><h6 id="optimize-consume"><a class="markdownIt-Anchor" href="#optimize-consume"></a> Optimize consume</h6><p>Define variables: <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>P</mi><mrow><mi>i</mi><mi>j</mi></mrow></msub></mrow><annotation encoding="application/x-tex">P_{ij}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:.68333em"></span><span class="strut bottom" style="height:.969438em;vertical-align:-.286108em"></span><span class="base textstyle uncramped"><span class="mord"><span class="mord mathit" style="margin-right:.13889em">P</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.13889em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mord mathit" style="margin-right:.05724em">j</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span></span></span></span> – The amount of money that needs to be spent in different categories i in month j.</p><p><span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>L</mi><mrow><mi>i</mi><mi>j</mi></mrow></msub></mrow><annotation encoding="application/x-tex">L_{ij}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:.68333em"></span><span class="strut bottom" style="height:.969438em;vertical-align:-.286108em"></span><span class="base textstyle uncramped"><span class="mord"><span class="mord mathit">L</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mord mathit" style="margin-right:.05724em">j</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span></span></span></span> – The priority level associate with each spending category, <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>P</mi><mrow><mi>i</mi><mi>j</mi></mrow></msub></mrow><annotation encoding="application/x-tex">P_{ij}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:.68333em"></span><span class="strut bottom" style="height:.969438em;vertical-align:-.286108em"></span><span class="base textstyle uncramped"><span class="mord"><span class="mord mathit" style="margin-right:.13889em">P</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.13889em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mord mathit" style="margin-right:.05724em">j</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span></span></span></span>. It is the reverse of the original list done by user. Like for high priority stuff, <span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>L</mi><mrow><mi>i</mi><mi>j</mi></mrow></msub></mrow><annotation encoding="application/x-tex">L_{ij}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:.68333em"></span><span class="strut bottom" style="height:.969438em;vertical-align:-.286108em"></span><span class="base textstyle uncramped"><span class="mord"><span class="mord mathit">L</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mord mathit" style="margin-right:.05724em">j</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span></span></span></span> will be high</p><p><span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>I</mi><mrow><mi>j</mi></mrow></msub></mrow><annotation encoding="application/x-tex">I_{j}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:.68333em"></span><span class="strut bottom" style="height:.969438em;vertical-align:-.286108em"></span><span class="base textstyle uncramped"><span class="mord"><span class="mord mathit" style="margin-right:.07847em">I</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.07847em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit" style="margin-right:.05724em">j</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span></span></span></span> – The anticipated money in in each month.</p><p><span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>T</mi><mi>j</mi></msub></mrow><annotation encoding="application/x-tex">T_j</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:.68333em"></span><span class="strut bottom" style="height:.969438em;vertical-align:-.286108em"></span><span class="base textstyle uncramped"><span class="mord"><span class="mord mathit" style="margin-right:.13889em">T</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.13889em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathit" style="margin-right:.05724em">j</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span></span></span></span> – The money available at the end of month J.</p><p><span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>S</mi><mrow><mi>i</mi><mi>j</mi></mrow></msub></mrow><annotation encoding="application/x-tex">S_{ij}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:.68333em"></span><span class="strut bottom" style="height:.969438em;vertical-align:-.286108em"></span><span class="base textstyle uncramped"><span class="mord"><span class="mord mathit" style="margin-right:.05764em">S</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.05764em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mord mathit" style="margin-right:.05724em">j</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span></span></span></span> – The binary selector to indicate this category should be selected or not in the month j.</p><p>A – The one month rate of buying some low-risk investment product.</p><p>O – Set including one time purchase, like wait list.</p><p>R – Set including repeating purchase.</p><p>Formula:</p><p><span class="katex-display"><span class="katex"><span class="katex-mathml"><math><semantics><mrow><mtable><mtr><mtd><mrow></mrow></mtd><mtd><mrow><mrow></mrow><mtext><mi mathvariant="normal">M</mi><mi mathvariant="normal">a</mi><mi mathvariant="normal">x</mi><mi mathvariant="normal">m</mi><mi mathvariant="normal">i</mi><mi mathvariant="normal">z</mi><mi mathvariant="normal">e</mi><mtext> </mtext></mtext></mrow></mtd><mtd><mrow><msubsup><mo>∑</mo><mrow><mi>i</mi></mrow><mrow><mi>R</mi><mo>∪</mo><mi>O</mi></mrow></msubsup><msubsup><mo>∑</mo><mrow><mi>j</mi></mrow><mrow><mn>1</mn><mn>2</mn></mrow></msubsup><msub><mi>L</mi><mrow><mi>i</mi><mi>j</mi></mrow></msub><msub><mi>S</mi><mrow><mi>i</mi><mi>j</mi></mrow></msub></mrow></mtd></mtr><mtr><mtd><mrow></mrow></mtd><mtd><mrow><mrow></mrow><mtext><mi mathvariant="normal">S</mi><mi mathvariant="normal">u</mi><mi mathvariant="normal">b</mi><mi mathvariant="normal">j</mi><mi mathvariant="normal">e</mi><mi mathvariant="normal">c</mi><mi mathvariant="normal">t</mi><mtext> </mtext><mi mathvariant="normal">t</mi><mi mathvariant="normal">o</mi></mtext></mrow></mtd><mtd><mrow><msubsup><mo>∑</mo><mrow><mi>i</mi></mrow><mrow><mi>n</mi></mrow></msubsup><msub><mi>P</mi><mrow><mi>i</mi><mi>j</mi></mrow></msub><msub><mi>S</mi><mrow><mi>i</mi><mi>j</mi></mrow></msub><mo>≤</mo><mi>A</mi><msub><mi>T</mi><mrow><mi>j</mi><mo>−</mo><mn>1</mn></mrow></msub><mo>+</mo><msub><mi>I</mi><mi>j</mi></msub></mrow></mtd></mtr><mtr><mtd><mrow></mrow></mtd><mtd><mrow><mrow></mrow></mrow></mtd><mtd><mrow><msub><mi>T</mi><mrow><mi>j</mi></mrow></msub><mo>=</mo><mi>A</mi><msub><mi>T</mi><mrow><mi>j</mi><mo>−</mo><mn>1</mn></mrow></msub><mo>−</mo><msubsup><mo>∑</mo><mrow><mi>i</mi></mrow><mrow><mi>n</mi></mrow></msubsup><msub><mi>P</mi><mrow><mi>i</mi><mi>j</mi></mrow></msub><msub><mi>S</mi><mrow><mi>i</mi><mi>j</mi></mrow></msub><mo>+</mo><msub><mi>I</mi><mi>j</mi></msub></mrow></mtd></mtr><mtr><mtd><mrow></mrow></mtd><mtd><mrow><mrow></mrow></mrow></mtd><mtd><mrow><msubsup><mo>∑</mo><mrow><mi>i</mi></mrow><mrow><mi>O</mi></mrow></msubsup><msubsup><mo>∑</mo><mrow><mi>j</mi></mrow><mrow><mn>1</mn><mn>2</mn></mrow></msubsup><msub><mi>S</mi><mrow><mi>i</mi><mi>j</mi></mrow></msub><mo>=</mo><mn>1</mn></mrow></mtd></mtr><mtr><mtd><mrow></mrow></mtd><mtd><mrow><mrow></mrow></mrow></mtd><mtd><mrow><msubsup><mo>∑</mo><mrow><mi>i</mi></mrow><mrow><mi>R</mi></mrow></msubsup><msub><mi>S</mi><mrow><mi>i</mi><mi>j</mi></mrow></msub><mo>=</mo><mn>1</mn><mspace width="1em"></mspace><mi mathvariant="normal">∀</mi><mi>j</mi><mo>∈</mo><mo>{</mo><mn>1</mn><mi mathvariant="normal">.</mi><mi mathvariant="normal">.</mi><mi mathvariant="normal">.</mi><mn>1</mn><mn>2</mn><mo>}</mo></mrow></mtd></mtr><mtr><mtd><mrow></mrow></mtd></mtr></mtable></mrow><annotation encoding="application/x-tex">\begin{aligned} &amp; \text{Maxmize } &amp; \sum_{i}^{R\cup O}\sum_{j}^{12}L_{ij}S_{ij} \\ &amp; \text{Subject to} &amp; \sum_{i}^{n}P_{ij}S_{ij}\le AT_{j-1}+I_j \\ &amp; &amp; T_{j} = AT_{j-1} - \sum_{i}^{n}P_{ij}S_{ij} +I_j \\ &amp; &amp; \sum_{i}^{O}\sum_{j}^{12}S_{ij} = 1 \\ &amp; &amp; \sum_{i}^{R}S_{ij} = 1 \quad \forall j\in \{1...12\} \\ \end{aligned}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:8.5741815em"></span><span class="strut bottom" style="height:16.648363em;vertical-align:-8.0741815em"></span><span class="base displaystyle textstyle uncramped"><span class="mord"><span class="mtable"><span class="col-align-r"><span class="vlist"><span style="top:-6.7458455em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="mord displaystyle textstyle uncramped"></span></span><span style="top:-3.6806714999999994em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="mord displaystyle textstyle uncramped"></span></span><span style="top:-.7516054999999988em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="mord displaystyle textstyle uncramped"></span></span><span style="top:2.3543995000000013em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="mord displaystyle textstyle uncramped"></span></span><span style="top:5.596512500000001em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="mord displaystyle textstyle uncramped"></span></span><span style="top:7.7141815em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="mord displaystyle textstyle uncramped"></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="col-align-l"><span class="vlist"><span style="top:-6.7458455em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="mord displaystyle textstyle uncramped"><span class="mord displaystyle textstyle uncramped"></span><span class="text mord displaystyle textstyle uncramped"><span class="mord mathrm">M</span><span class="mord mathrm">a</span><span class="mord mathrm">x</span><span class="mord mathrm">m</span><span class="mord mathrm">i</span><span class="mord mathrm">z</span><span class="mord mathrm">e</span><span class="mord mspace"> </span></span></span></span><span style="top:-3.6806714999999994em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="mord displaystyle textstyle uncramped"><span class="mord displaystyle textstyle uncramped"></span><span class="text mord displaystyle textstyle uncramped"><span class="mord mathrm">S</span><span class="mord mathrm">u</span><span class="mord mathrm">b</span><span class="mord mathrm">j</span><span class="mord mathrm">e</span><span class="mord mathrm">c</span><span class="mord mathrm">t</span><span class="mord mspace"> </span><span class="mord mathrm">t</span><span class="mord mathrm">o</span></span></span></span><span style="top:-.7516054999999988em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="mord displaystyle textstyle uncramped"><span class="mord displaystyle textstyle uncramped"></span></span></span><span style="top:2.3543995000000013em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="mord displaystyle textstyle uncramped"><span class="mord displaystyle textstyle uncramped"></span></span></span><span style="top:5.596512500000001em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="mord displaystyle textstyle uncramped"><span class="mord displaystyle textstyle uncramped"></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="arraycolsep" style="width:2em"></span><span class="col-align-r"><span class="vlist"><span style="top:-6.7458455em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="mord displaystyle textstyle uncramped"><span class="mop op-limits"><span class="vlist"><span style="top:1.1776689999999999em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span></span></span></span><span style="top:-.000005000000000143778em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span><span class="op-symbol large-op mop">∑</span></span></span><span style="top:-1.2500050000000003em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle uncramped"><span class="mord scriptstyle uncramped"><span class="mord mathit" style="margin-right:.00773em">R</span><span class="mbin">∪</span><span class="mord mathit" style="margin-right:.02778em">O</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mop op-limits"><span class="vlist"><span style="top:1.1776689999999999em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit" style="margin-right:.05724em">j</span></span></span></span><span style="top:-.000005000000000254801em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span><span class="op-symbol large-op mop">∑</span></span></span><span style="top:-1.2500050000000005em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle uncramped"><span class="mord scriptstyle uncramped"><span class="mord mathrm">1</span><span class="mord mathrm">2</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mord"><span class="mord mathit">L</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mord mathit" style="margin-right:.05724em">j</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mord"><span class="mord mathit" style="margin-right:.05764em">S</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.05764em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mord mathit" style="margin-right:.05724em">j</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span></span></span><span style="top:-3.6806714999999994em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="mord displaystyle textstyle uncramped"><span class="mop op-limits"><span class="vlist"><span style="top:1.1776689999999999em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span></span></span></span><span style="top:-.000005000000000143778em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span><span class="op-symbol large-op mop">∑</span></span></span><span style="top:-1.2500050000000003em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle uncramped"><span class="mord scriptstyle uncramped"><span class="mord mathit">n</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mord"><span class="mord mathit" style="margin-right:.13889em">P</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.13889em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mord mathit" style="margin-right:.05724em">j</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mord"><span class="mord mathit" style="margin-right:.05764em">S</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.05764em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mord mathit" style="margin-right:.05724em">j</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mrel">≤</span><span class="mord mathit">A</span><span class="mord"><span class="mord mathit" style="margin-right:.13889em">T</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.13889em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit" style="margin-right:.05724em">j</span><span class="mbin">−</span><span class="mord mathrm">1</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mbin">+</span><span class="mord"><span class="mord mathit" style="margin-right:.07847em">I</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.07847em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathit" style="margin-right:.05724em">j</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span></span></span><span style="top:-.7516054999999988em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="mord displaystyle textstyle uncramped"><span class="mord"><span class="mord mathit" style="margin-right:.13889em">T</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.13889em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit" style="margin-right:.05724em">j</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mrel">=</span><span class="mord mathit">A</span><span class="mord"><span class="mord mathit" style="margin-right:.13889em">T</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.13889em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit" style="margin-right:.05724em">j</span><span class="mbin">−</span><span class="mord mathrm">1</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mbin">−</span><span class="mop op-limits"><span class="vlist"><span style="top:1.1776689999999999em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span></span></span></span><span style="top:-.000005000000000143778em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span><span class="op-symbol large-op mop">∑</span></span></span><span style="top:-1.2500050000000003em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle uncramped"><span class="mord scriptstyle uncramped"><span class="mord mathit">n</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mord"><span class="mord mathit" style="margin-right:.13889em">P</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.13889em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mord mathit" style="margin-right:.05724em">j</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mord"><span class="mord mathit" style="margin-right:.05764em">S</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.05764em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mord mathit" style="margin-right:.05724em">j</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mbin">+</span><span class="mord"><span class="mord mathit" style="margin-right:.07847em">I</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.07847em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathit" style="margin-right:.05724em">j</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span></span></span><span style="top:2.3543995000000013em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="mord displaystyle textstyle uncramped"><span class="mop op-limits"><span class="vlist"><span style="top:1.1776689999999999em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span></span></span></span><span style="top:-.000005000000000143778em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span><span class="op-symbol large-op mop">∑</span></span></span><span style="top:-1.2500050000000003em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle uncramped"><span class="mord scriptstyle uncramped"><span class="mord mathit" style="margin-right:.02778em">O</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mop op-limits"><span class="vlist"><span style="top:1.1776689999999999em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit" style="margin-right:.05724em">j</span></span></span></span><span style="top:-.000005000000000254801em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span><span class="op-symbol large-op mop">∑</span></span></span><span style="top:-1.2500050000000005em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle uncramped"><span class="mord scriptstyle uncramped"><span class="mord mathrm">1</span><span class="mord mathrm">2</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mord"><span class="mord mathit" style="margin-right:.05764em">S</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.05764em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mord mathit" style="margin-right:.05724em">j</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mrel">=</span><span class="mord mathrm">1</span></span></span><span style="top:5.596512500000001em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="mord displaystyle textstyle uncramped"><span class="mop op-limits"><span class="vlist"><span style="top:1.1776689999999999em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span></span></span></span><span style="top:-.000005000000000143778em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span><span class="op-symbol large-op mop">∑</span></span></span><span style="top:-1.2500050000000003em;margin-left:0"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle uncramped"><span class="mord scriptstyle uncramped"><span class="mord mathit" style="margin-right:.00773em">R</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mord"><span class="mord mathit" style="margin-right:.05764em">S</span><span class="vlist"><span style="top:.15em;margin-right:.05em;margin-left:-.05764em"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord scriptstyle cramped"><span class="mord mathit">i</span><span class="mord mathit" style="margin-right:.05724em">j</span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span><span class="mrel">=</span><span class="mord mathrm">1</span><span class="mord mspace quad"></span><span class="mord mathrm">∀</span><span class="mord mathit" style="margin-right:.05724em">j</span><span class="mrel">∈</span><span class="mopen">{</span><span class="mord mathrm">1</span><span class="mord mathrm">.</span><span class="mord mathrm">.</span><span class="mord mathrm">.</span><span class="mord mathrm">1</span><span class="mord mathrm">2</span><span class="mclose">}</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0">​</span></span>​</span></span></span></span></span></span></span></span></span></p><p>Though optimization might give us the optimal solution in complex cases, but it is also acceptable to use normal methods as shown below.</p><blockquote><p>This is the method the website is using, though small modification is made basedd on this description. The website will calculate your history spending and get a expected income and expense in your future spending. But the core part of calculation is this.</p></blockquote><img src="/2020/Financial-organization-phone-application/alg2.png"><h3 id="next-stage"><a class="markdownIt-Anchor" href="#next-stage"></a> Next Stage</h3><p>By considering non-stable testing, the current version is the stable version and compatible to multiple different platforms. The future version of this app will contains future stuff, such as locally voice interaction to add stuff with local trained Natural language processing. And local trained command to handle nearly all functions this app is able to do.</p><p><a href="https://shaokangjiang.github.io/2021/projects/Financial-organization-phone-app-stage-2/" target="_blank" rel="noopener">Stage two</a> is nearly published now, which is a stable and compatible to multiple different platforms version that user is able to add items using chats.</p>]]></content:encoded>
      
      
      <category domain="https://shaokang.me/categories/Expo/">Expo</category>
      
      
      <category domain="https://shaokang.me/tags/MIP/">MIP</category>
      
      <category domain="https://shaokang.me/tags/Expo/">Expo</category>
      
      
      <comments>https://shaokang.me/2020/Financial-organization-phone-application/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Sample interactive page</title>
      <link>https://shaokang.me/2020/Sample-interactive-page/</link>
      <guid>https://shaokang.me/2020/Sample-interactive-page/</guid>
      <pubDate>Wed, 02 Dec 2020 18:10:46 GMT</pubDate>
      
      <description>&lt;p&gt;Markdown is based on html, so whatever html have markdown can have, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/web/html/element/iframe&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt;&lt;/a&gt; is the most common one. I will show some example by using iframe below:&lt;/p&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p>Markdown is based on html, so whatever html have markdown can have, <a href="https://developer.mozilla.org/en-US/docs/web/html/element/iframe" target="_blank" rel="noopener"><code>&lt;iframe&gt;</code></a> is the most common one. I will show some example by using iframe below:</p><a id="more"></a><h3 id="map"><a class="markdownIt-Anchor" href="#map"></a> Map</h3><p>Use the following code to embedded a map:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">iframe</span> <span class="attr">id</span>=<span class="string">"inlineFrameExample"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">title</span>=<span class="string">"Inline Frame Example"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">width</span>=<span class="string">"100%"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">height</span>=<span class="string">"500"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">src</span>=<span class="string">"https://www.openstreetmap.org/export/embed.html?bbox=-0.004017949104309083%2C51.47612752641776%2C0.00030577182769775396%2C51.478569861898606&amp;layer=mapnik"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">iframe</span>&gt;</span></span><br></pre></td></tr></table></figure><p>Appearance:</p><iframe id="inlineFrameExample" title="Inline Frame Example" width="100%" height="500" src="https://www.openstreetmap.org/export/embed.html?bbox=-0.004017949104309083%2C51.47612752641776%2C0.00030577182769775396%2C51.478569861898606&layer=mapnik"></iframe><h3 id="youtube"><a class="markdownIt-Anchor" href="#youtube"></a> Youtube</h3><p>Use the following code to embedded a youtube, other video platform would have similar function. This is an example for <a href="https://www.youtube.com/watch?v=W6NZfCO5SIk" target="_blank" rel="noopener">JavaScript Tutorial for Beginners: Learn JavaScript in 1 Hour</a> :</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">iframe</span> <span class="attr">width</span>=<span class="string">"100%"</span> <span class="attr">height</span>=<span class="string">"550"</span> <span class="attr">src</span>=<span class="string">"https://www.youtube.com/embed/W6NZfCO5SIk"</span> <span class="attr">frameborder</span>=<span class="string">"0"</span> <span class="attr">allow</span>=<span class="string">"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"</span> <span class="attr">allowfullscreen</span>&gt;</span><span class="tag">&lt;/<span class="name">iframe</span>&gt;</span></span><br></pre></td></tr></table></figure><img src="/2020/Sample-interactive-page/youtube.gif" title="youtube"><p>Appearance:</p><iframe width="100%" height="550" src="https://www.youtube.com/embed/W6NZfCO5SIk" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe><h3 id="document"><a class="markdownIt-Anchor" href="#document"></a> Document</h3><p>Use the following code to embedded a microsoft document (you may get the link through your onedrive panel -&gt; Embed in your personal onedrive, other version/driver should have similar function). The following code would embed our schedule:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">iframe</span> <span class="attr">width</span>=<span class="string">"100%"</span> <span class="attr">height</span>=<span class="string">"500"</span> <span class="attr">frameborder</span>=<span class="string">"0"</span> <span class="attr">scrolling</span>=<span class="string">"no"</span> <span class="attr">src</span>=<span class="string">"https://onedrive.live.com/embed?resid=C4FE7ED776152B7%21179112&amp;authkey=%21AIBpqBFVsOqASe0&amp;em=2&amp;wdAllowInteractivity=False&amp;wdInConfigurator=True"</span>&gt;</span><span class="tag">&lt;/<span class="name">iframe</span>&gt;</span></span><br></pre></td></tr></table></figure><p>Appearance:</p><iframe width="100%" height="500" frameborder="0" scrolling="no" src="https://onedrive.live.com/embed?resid=C4FE7ED776152B7%21179112&authkey=%21AIBpqBFVsOqASe0&em=2&wdAllowInteractivity=False&wdInConfigurator=True"></iframe><h3 id="games"><a class="markdownIt-Anchor" href="#games"></a> Games</h3><p>To be more creative, you can even embedded some games, such as the following 3D games by using glitch using this code: Below code is for project <a href="https://github.com/aframevr/a-blast" target="_blank" rel="noopener">a-blast</a>. You may create your own on glitch or just on any website server and embed to here.</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">iframe</span> <span class="attr">width</span>=<span class="string">"100%"</span> <span class="attr">height</span>=<span class="string">"500"</span> <span class="attr">frameborder</span>=<span class="string">"0"</span> <span class="attr">scrolling</span>=<span class="string">"no"</span> <span class="attr">src</span>=<span class="string">"https://aframe.io/a-blast/"</span>&gt;</span><span class="tag">&lt;/<span class="name">iframe</span>&gt;</span></span><br></pre></td></tr></table></figure><p>Appearance:</p><iframe width="100%" height="500" frameborder="0" scrolling="no" src="https://aframe.io/a-blast/"></iframe><h3 id="conslusion"><a class="markdownIt-Anchor" href="#conslusion"></a> Conslusion</h3><p>As markdown is based on html, there are much more areas could be explored. Be creative.</p>]]></content:encoded>
      
      
      <category domain="https://shaokang.me/categories/website/">website</category>
      
      <category domain="https://shaokang.me/categories/website/Hexo/">Hexo</category>
      
      
      <category domain="https://shaokang.me/tags/Website/">Website</category>
      
      
      <comments>https://shaokang.me/2020/Sample-interactive-page/#disqus_thread</comments>
      
    </item>
    
  </channel>
</rss>
