commit 843ed03d4fcb6fa828280e8af7535a7c270e15c0
Author: Hui Lan
Date: Tue Apr 6 16:22:03 2021 +0800
Publish EnglishPal source code
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7a8be9f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,12 @@
+venv/
+app/__init__.py
+app/__pycache__/
+app/sqlite_commands.py
+app/static/usr/*.jpg
+app/static/img/
+app/static/frequency/frequency_*.pickle
+app/static/frequency/frequency.p
+app/static/wordfreqapp.db
+app/static/wordfreqapp.sql
+app/static/donate-the-author.jpg
+app/static/donate-the-author-hidden.jpg
diff --git a/app/README.md b/app/README.md
new file mode 100644
index 0000000..ab6b56b
--- /dev/null
+++ b/app/README.md
@@ -0,0 +1,90 @@
+How to run EnglishPal
+===========================
+
+
+
+Hui Lan
+1 November 2019
+
+
+
+
+
+Run it on a local machine
+-------------------------
+
+python3 main.py
+
+
+
+
+
+
+Run it within Docker
+--------------------
+
+Assuming that docker has been installed...
+
+
+ssh to ubuntu@118.25.96.118
+cd to /home/lanhui/englishpal
+
+# Stop service
+sudo service docker restart
+
+# Rebuild container. Run this after modifying the source code.
+sudo docker build -t englishpal .
+
+# Run the application
+sudo docker run -d -p 90:80 -v /home/lanhui/englishpal/app/static/frequency:/app/static/frequency -t englishpal # for permanently saving data
+sudo docker run -d -p 90:80 -t englishpal # data will be lost after existing
+
+# Save space. Run it after sudo docker run
+sudo docker system prune -a -f
+
+
+# Other commands
+sudo docker ps -a
+
+sudo docker logs image_name, where image name could be obtained from sudo docker ps.
+
+build.sh contains all the above commands. Run "sudo ./build.sh" to rebuild the web application.
+
+
+
+Update articles
+---------------
+
+pscp wordfreqapp.db lanhui@118.25.96.118:/home/lanhui/englishpal/app/static
+
+
+
+Feedback
+---------
+
+Tianhua people
+~~~~~~~~~~~~~~~~
+
+Need a smart phone app. I use phone a lot.
+
+Can take a picture for text. Automatic translation.
+
+You cannot ask students to use computers.
+
+
+Usability testing
+~~~~~~~~~~~~~~~~~~~~~~
+
+Respondent 1 --- Paid 10 yuan
+
+“成为会员”改成“注册”
+
+“登出”改成“退出”
+
+“收集生词吧”改成“生词收集栏”
+
+***不要自动显示下一篇
+
+需要有“上一篇”、“下一篇”
+
+Internal server error when register using an email address.
diff --git a/app/UseSqlite.py b/app/UseSqlite.py
new file mode 100644
index 0000000..d9b3f22
--- /dev/null
+++ b/app/UseSqlite.py
@@ -0,0 +1,73 @@
+###########################################################################
+# Copyright 2019 (C) Hui Lan
+# Written permission must be obtained from the author for commercial uses.
+###########################################################################
+
+
+# Reference: Dusty Phillips. Python 3 Objected-oriented Programming Second Edition. Pages 326-328.
+# Copyright (C) 2019 Hui Lan
+
+import sqlite3
+
+class Sqlite3Template:
+ def __init__(self, db_fname):
+ self.db_fname = db_fname
+
+ def connect(self, db_fname):
+ self.conn = sqlite3.connect(self.db_fname)
+
+ def instructions(self, query_statement):
+ raise NotImplementedError()
+
+ def operate(self):
+ self.conn.row_factory = sqlite3.Row
+ self.results = self.conn.execute(self.query) # self.query is to be given in the child classes
+ self.conn.commit()
+
+ def format_results(self):
+ raise NotImplementedError()
+
+ def do(self):
+ self.connect(self.db_fname)
+ self.instructions(self.query)
+ self.operate()
+
+
+class InsertQuery(Sqlite3Template):
+ def instructions(self, query):
+ self.query = query
+
+
+class RecordQuery(Sqlite3Template):
+ def instructions(self, query):
+ self.query = query
+
+ def format_results(self):
+ output = []
+ for row_dict in self.results.fetchall():
+ lst = []
+ for k in dict(row_dict):
+ lst.append( row_dict[k] )
+ output.append(', '.join(lst))
+ return '\n\n'.join(output)
+
+ def get_results(self):
+ result = []
+ for row_dict in self.results.fetchall():
+ result.append( dict(row_dict) )
+ return result
+
+
+
+if __name__ == '__main__':
+
+ #iq = InsertQuery('RiskDB.db')
+ #iq.instructions("INSERT INTO inspection Values ('FoodSupplies', 'RI2019051301', '2019-05-13', '{}')")
+ #iq.do()
+ #iq.instructions("INSERT INTO inspection Values ('CarSupplies', 'RI2019051302', '2019-05-13', '{[{\"risk_name\":\"elevator\"}]}')")
+ #iq.do()
+
+ rq = RecordQuery('wordfreqapp.db')
+ rq.instructions("SELECT * FROM article WHERE level=3")
+ rq.do()
+ #print(rq.format_results())
diff --git a/app/WordFreq.py b/app/WordFreq.py
new file mode 100644
index 0000000..3620a41
--- /dev/null
+++ b/app/WordFreq.py
@@ -0,0 +1,25 @@
+###########################################################################
+# Copyright 2019 (C) Hui Lan
+# Written permission must be obtained from the author for commercial uses.
+###########################################################################
+
+from wordfreqCMD import remove_punctuation, freq, sort_in_descending_order
+import string
+
+class WordFreq:
+ def __init__(self, s):
+ self.s = remove_punctuation(s)
+
+ def get_freq(self):
+ lst = []
+ for t in freq(self.s):
+ word = t[0]
+ if len(word) > 0 and word[0] in string.ascii_letters:
+ lst.append(t)
+ return sort_in_descending_order(lst)
+
+
+if __name__ == '__main__':
+ f = WordFreq('BANANA; Banana, apple ORANGE Banana banana.')
+ print(f.get_freq())
+
diff --git a/app/build.sh b/app/build.sh
new file mode 100755
index 0000000..52cc695
--- /dev/null
+++ b/app/build.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+cd /home/lanhui/englishpal
+
+# Stop service
+sudo service docker restart
+
+# Rebuild container. Run this after modifying the source code.
+sudo docker build -t englishpal .
+
+# Run the application
+sudo docker run -d -p 90:80 -v /home/lanhui/englishpal/app/static/frequency:/app/static/frequency -t englishpal # for permanently saving data
+
+# Save space. Run it after sudo docker run
+sudo docker system prune -a -f
+
+
diff --git a/app/difficulty.py b/app/difficulty.py
new file mode 100644
index 0000000..ccd9b6f
--- /dev/null
+++ b/app/difficulty.py
@@ -0,0 +1,243 @@
+###########################################################################
+# Copyright 2019 (C) Hui Lan
+# Written permission must be obtained from the author for commercial uses.
+###########################################################################
+
+# Purpose: compute difficulty level of a English text
+
+import pickle
+import math
+from wordfreqCMD import remove_punctuation, freq, sort_in_descending_order, sort_in_ascending_order
+
+
+def load_record(pickle_fname):
+ f = open(pickle_fname, 'rb')
+ d = pickle.load(f)
+ f.close()
+ return d
+
+
+def difficulty_level_from_frequency(word, d):
+ level = 1
+ if not word in d:
+ return level
+
+ if 'what' in d:
+ ratio = (d['what']+1)/(d[word]+1) # what is a frequent word
+ level = math.log( max(ratio, 1), 2)
+
+ level = min(level, 8)
+ return level
+
+
+def get_difficulty_level(d1, d2):
+ d = {}
+ L = list(d1.keys()) # in d1, we have freuqence for each word
+ L2 = list(d2.keys()) # in d2, we have test types (e.g., CET4,CET6,BBC) for each word
+ L.extend(L2)
+ L3 = list(set(L)) # L3 contains all words
+ for k in L3:
+ if k in d2:
+ if 'CET4' in d2[k]:
+ d[k] = 4 # CET4 word has level 4
+ elif 'CET6' in d2[k]:
+ d[k] = 6
+ elif 'BBC' in d2[k]:
+ d[k] = 8
+ if k in d1: # BBC could contain easy words that are not in CET4 or CET6. So 4 is not reasonable. Recompute difficulty level.
+ d[k] = min(difficulty_level_from_frequency(k, d1), d[k])
+ elif k in d1:
+ d[k] = difficulty_level_from_frequency(k, d1)
+
+ return d
+
+
+
+def revert_dict(d):
+ '''
+ In d2, time is the key, and the value is a list of words picked at that time.
+ '''
+ d2 = {}
+ for k in d:
+ lst = d[k]
+ for time_info in lst:
+ date = time_info[:10] # until hour
+ if not date in d2:
+ d2[date] = [k]
+ else:
+ d2[date].append(k)
+ return d2
+
+
+def user_difficulty_level(d_user, d):
+ d_user2 = revert_dict(d_user) # key is date, and value is a list of words added in that date
+ count = 0
+ geometric = 1
+ for date in sorted(d_user2.keys(), reverse=True): # most recently added words are more important while determining user's level
+ lst = d_user2[date] # a list of words
+ lst2 = [] # a list of tuples, (word, difficulty level)
+ for word in lst:
+ if word in d:
+ lst2.append((word, d[word]))
+
+ lst3 = sort_in_ascending_order(lst2) # easiest tuple first
+ #print(lst3)
+ for t in lst3:
+ word = t[0]
+ hard = t[1]
+ #print('WORD %s HARD %4.2f' % (word, hard))
+ geometric = geometric * (hard)
+ count += 1
+ if count >= 10:
+ return geometric**(1/count)
+
+ return geometric**(1/max(count,1))
+
+
+def text_difficulty_level(s, d):
+ s = remove_punctuation(s)
+ L = freq(s)
+
+ lst = [] # a list of tuples, each tuple being (word, difficulty level)
+ for x in L:
+ word = x[0]
+ if word in d:
+ lst.append((word, d[word]))
+
+ lst2 = sort_in_descending_order(lst) # most difficult words on top
+ #print(lst2)
+ count = 0
+ geometric = 1
+ for t in lst2:
+ word = t[0]
+ hard = t[1]
+ geometric = geometric * (hard)
+ count += 1
+ if count >= 20: # we look for n most difficult words
+ return geometric**(1/count)
+
+ return geometric**(1/max(count,1))
+
+
+
+if __name__ == '__main__':
+
+
+ d1 = load_record('frequency.p')
+ #print(d1)
+
+ d2 = load_record('words_and_tests.p')
+ #print(d2)
+
+
+ d3 = get_difficulty_level(d1, d2)
+
+ s = '''
+South Lawn
+11:53 A.M. EDT
+THE PRESIDENT: Hi, everybody. Hi. How are you? So, the stock market is doing very well.
+The economy is booming. We have a new record in sight. It could happen even today.
+But we have a new stock market record. I think it’ll be about 118 times that we’ve broken the record.
+Jobs look phenomenal.
+ '''
+ s = '''
+By the authority vested in me as President by the Constitution and the laws of the United States, after carefully considering the reports submitted to the Congress by the Energy Information Administration, including the report submitted in October 2019, and other relevant factors, including global economic conditions, increased oil production by certain countries, the global level of spare petroleum production capacity, and the availability of strategic reserves, I determine, pursuant to section 1245(d)(4)(B) and (C) of the National Defense Authorization Act for Fiscal Year 2012, Public Law 112-81, and consistent with prior determinations, that there is a sufficient supply of petroleum and petroleum products from countries other than Iran to permit a significant reduction in the volume of petroleum and petroleum products purchased from Iran by or through foreign financial institutions.
+
+'''
+
+ s = '''
+Democrats keep their witnesses locked behind secure doors, then flood the press with carefully sculpted leaks and accusations, driving the Trump-corruption narrative. And so the party goes, galloping toward an impeachment vote that would overturn the will of the American voters—on a case built in secret.
+
+Conservative commentators keep noting that Mrs. Pelosi’s refusal to hold a vote on the House floor to authorize an official impeachment inquiry helps her caucus’s vulnerable members evade accountability. But there’s a more practical and uglier reason for Democrats to skip the formalities. Normally an authorization vote would be followed by official rules on how the inquiry would proceed. Under today’s process, Mr. Schiff gets to make up the rules as he goes along. Behold the Lord High Impeacher.
+
+Democrats view control over the narrative as essential, having learned from their Russia-collusion escapade the perils of transparency. They banked on special counsel Robert Mueller’s investigation proving impeachment fodder, but got truth-bombed. Their subsequent open hearings on the subject—featuring Michael Cohen, Mr. Mueller and Corey Lewandowski —were, for the Democrats, embarrassing spectacles, at which Republicans punched gaping holes in their story line.
+
+Mr. Schiff is making sure that doesn’t happen again; he’ll present the story, on his terms. His rules mean he can issue that controlling decree about “only one” transcript and Democratic staff supervision of Republican members. It means he can bar the public, the press and even fellow representatives from hearings, even though they’re unclassified.
+'''
+
+ s = '''
+Unemployment today is at a 50-year low. There are more Americans working today than ever before. Median household income in the last two and half years has risen by more than $5,000. And that doesn’t even account for the savings from the President’s tax cuts or energy reforms for working families.
+
+Because of the President’s policies, America has added trillions of dollars of wealth to our economy while China’s economy continues to fall behind.
+
+To level the playing field for the American worker against unethical trade practices, President Trump levied tariffs on $250 billion in Chinese goods in 2018. And earlier this year, the President announced we would place tariffs on another $300 billion of Chinese goods if significant issues in our trading relationship were not resolved by December of this year.
+'''
+ s = '''
+Needless to say, we see it very differently. Despite the great power competition that is underway, and America’s growing strength, we want better for China. That’s why, for the first time in decades, under President Donald Trump’s leadership, the United States is treating China’s leaders exactly how the leaders of any great world power should be treated — with respect, yes, but also with consistency and candor.
+'''
+ s = '''
+Brexit is the scheduled withdrawal of the United Kingdom from the European Union. Following a June 2016 referendum, in which 51.9% voted to leave, the UK government formally announced the country's withdrawal in March 2017, starting a two-year process that was due to conclude with the UK withdrawing on 29 March 2019. As the UK parliament thrice voted against the negotiated withdrawal agreement, that deadline has been extended twice, and is currently 31 October 2019. The Benn Act, passed in September 2019, requires the government to seek a third extension.
+'''
+
+ s = '''
+The argument for Brexit
+According to the BBC, the push to leave the EU was advocated mostly by the UK Independence Party and was not supported by the Prime Minister, David Cameron. Members of the UK Independence Party argued that Britain’s participation in the EU was a restrictive element for the country.
+
+As one of the EU’s primary initiatives is free movement within the region the party’s main arguments centered around regaining border control and reclaiming business rights. In addition, supporters of Brexit cited the high EU membership fees as a negative aspect of participation in the EU. It was argued that if the UK separates itself from the EU, these fees can be used to benefit the UK.
+
+The argument against Brexit
+The Conservative Party and the Prime Minister were strongly in favor of remaining with the EU. As a result of the decision to discontinue its participation in the EU, the Prime Minister has made a public statement that he will be relinquishing his position. He believes that the country needs a leader with the same goals as the majority of the country. He has promised a new PM will be in place by early September.
+
+The argument against Brexit pertains mostly to the business benefits. The argument is that the UK receives business benefits by being able to participate in the single market system established by the EU. In response to the criticism against the open borders, proponents believe that the influx of immigrants helps develop an eager workforce and fuels public service projects.
+
+Leaders in favor of staying also worry about the political backlash that could possibly result from other countries who favored staying with the EU. In addition, proponents of remaining with the EU believe that being part of a wider community of nations provides economic and cultural strength, as well as an additional element of security.
+
+What does Brexit mean for the future?
+While the decision marked a huge statement for the UK, the referendum vote is not legally binding. There are still many hurdles that must be dealt with before Brexit can become a reality.
+
+The UK is still subject to the laws of the EU until Britain’s exit becomes legal. In order for the UK to make its break official, the country needs to invoke Article 50. It is unclear exactly what this process will entail or how long it will take as Britain is the first country to take its leave of the EU. Once Article 50 has been formally invoked, the UK has two years to negotiate its departure with the other member states. But according to the BBC, “Extricating the UK from the EU will be extremely complex, and the process could drag on longer than that.”
+
+Amidst the aftermath of this shocking referendum vote, there is great uncertainty as political leaders decide what this means for the UK.
+
+'''
+
+
+ s = '''
+British Prime Minister Boris Johnson walks towards a voting station during the Brexit referendum in Britain, June 23, 2016. (Photo: EPA-EFE)
+
+LONDON – British Prime Minister Boris Johnson said Thursday he will likely ask Parliament to approve an election as part of an effort to break a Brexit deadlock.
+
+It is not clear if the vote, which Johnson wants to hold on Dec. 12, will take place as opposition lawmakers must also back the move.
+
+They are expected to vote on the measure on Monday.
+
+Johnson's announcement comes ahead of an expected decision Friday from the European Union over whether to delay Britain's exit from the bloc for three months.
+
+Britain's leader has been steadfastly opposed to any extension to the nation's scheduled Oct. 31 departure date from the EU, although in a letter to the leader of the opposition Labour Party this week he said he would accept a short technical postponement, "say to 15 or 30 November," to allow lawmakers to implement an EU withdrawal bill.
+
+Johnson's decision to offer to call an election follows lawmakers' rejection of his plan to rush through an EU exit bill that runs to hundreds of pages in just three days. They want more time to scrutinize the legislation and to make sure it does not leave the door open to a possible "no-deal" Brexit during future exit negotiations with the EU that will run through next year. A "no-deal" Brexit could dramatically harm Britain's economy.
+
+The prime minister was forced to ask for an extension to Britain's EU departure date after Britain's Parliament passed a law to ward off the threat of a "no-deal" Brexit.
+
+Johnson has repeatedly pledged to finalize the first stage, a transition deal, of Britain's EU divorce battle by Oct. 31. A second stage will involve negotiating its future relationship with the EU on trade, security and other salient issues.
+'''
+
+
+ s = '''
+Thank you very much. We have a Cabinet meeting. We’ll have a few questions after grace. And, if you would, Ben, please do the honors.
+
+THE PRESIDENT: All right, thank you, Ben. That was a great job. Appreciate it.
+
+The economy is doing fantastically well. It’s getting very close to another record. We’ve had many records since we won office. We’re getting very close to another record. I don’t know if anybody saw it: The household median income for eight years of President Bush, it rose $400. For eight years of President Obama, it rose $975. And for two and half years of President Trump — they have it down as two and a half years — it rose $5,000, not including $2,000 for taxes. So it rose, let’s say, $7,000. So in two and a half years, we’re up $7,000, compared to $1,000, compared to $400. And that’s for eight years and eight years.
+
+That’s a number that just came out, but that’s a number that I don’t know how there could be any dispute or any — I’ve never heard a number like that, meaning the economy is doing fantastically well.
+
+We need — for our farmers, our manufacturers, for, frankly, unions and non-unions, we need USMCA to be voted on. If it’s voted on, it’ll pass. It’s up to Nancy Pelosi to put it up. If she puts it up, it’s going to pass. It’s going to be very bipartisan. It’s something that’s very much needed. It’ll be hundreds of thousands of jobs.
+
+
+'''
+
+
+
+
+ #f = open('bbc-fulltext/bbc/entertainment/001.txt')
+ f = open('wordlist.txt')
+ s = f.read()
+ f.close()
+
+
+
+
+ print(text_difficulty_level(s, d3))
+
+
diff --git a/app/main.py b/app/main.py
new file mode 100644
index 0000000..1356f12
--- /dev/null
+++ b/app/main.py
@@ -0,0 +1,421 @@
+#! /usr/bin/python3
+# -*- coding: utf-8 -*-
+
+###########################################################################
+# Copyright 2019 (C) Hui Lan
+# Written permission must be obtained from the author for commercial uses.
+###########################################################################
+
+from WordFreq import WordFreq
+from wordfreqCMD import youdao_link, sort_in_descending_order
+from UseSqlite import InsertQuery, RecordQuery
+import pickle_idea, pickle_idea2
+import os
+import random, glob
+from datetime import datetime
+from flask import Flask, request, redirect, render_template, url_for, session, abort, flash
+from difficulty import get_difficulty_level, text_difficulty_level, user_difficulty_level
+
+app = Flask(__name__)
+app.secret_key = 'lunch.time!'
+
+path_prefix = '/var/www/wordfreq/wordfreq/'
+path_prefix = './' # comment this line in deployment
+
+def get_random_image(path):
+ img_path = random.choice(glob.glob(os.path.join(path, '*.jpg')))
+ return img_path[img_path.rfind('/static'):]
+
+def get_random_ads():
+ ads = random.choice(['个性化分析精准提升', '你的专有单词本', '智能捕捉阅读弱点,针对性提高你的阅读水平'])
+ return ads + '。 试试吧!'
+
+def load_freq_history(path):
+ d = {}
+ if os.path.exists(path):
+ d = pickle_idea.load_record(path)
+ return d
+
+def verify_user(username, password):
+ rq = RecordQuery(path_prefix + 'static/wordfreqapp.db')
+ rq.instructions("SELECT * FROM user WHERE name='%s' AND password='%s'" % (username, password))
+ rq.do()
+ result = rq.get_results()
+ return result != []
+
+def add_user(username, password):
+ start_date = datetime.now().strftime('%Y%m%d')
+ expiry_date = '20211230'
+ rq = InsertQuery(path_prefix + 'static/wordfreqapp.db')
+ rq.instructions("INSERT INTO user Values ('%s', '%s', '%s', '%s')" % (username, password, start_date, expiry_date))
+ rq.do()
+
+
+def check_username_availability(username):
+ rq = RecordQuery(path_prefix + 'static/wordfreqapp.db')
+ rq.instructions("SELECT * FROM user WHERE name='%s'" % (username))
+ rq.do()
+ result = rq.get_results()
+ return result == []
+
+def get_expiry_date(username):
+ rq = RecordQuery(path_prefix + 'static/wordfreqapp.db')
+ rq.instructions("SELECT expiry_date FROM user WHERE name='%s'" % (username))
+ rq.do()
+ result = rq.get_results()
+ if len(result) > 0:
+ return result[0]['expiry_date']
+ else:
+ return '20191024'
+
+
+
+def within_range(x, y, r):
+ return x > y and abs(x - y) <= r
+
+
+def get_today_article(user_word_list, articleID):
+
+ rq = RecordQuery(path_prefix + 'static/wordfreqapp.db')
+ if articleID == None:
+ rq.instructions("SELECT * FROM article")
+ else:
+ rq.instructions('SELECT * FROM article WHERE article_id=%d' % (articleID))
+ rq.do()
+ result = rq.get_results()
+
+ # Choose article according to reader's level
+ d1 = load_freq_history(path_prefix + 'static/frequency/frequency.p')
+ d2 = load_freq_history(path_prefix + 'static/words_and_tests.p')
+ d3 = get_difficulty_level(d1, d2)
+
+ d = {}
+ d_user = load_freq_history(user_word_list)
+ user_level = user_difficulty_level(d_user, d3) # more consideration as user's behaviour is dynamic. Time factor should be considered.
+ random.shuffle(result) # shuffle list
+ d = random.choice(result)
+ text_level = text_difficulty_level(d['text'], d3)
+ if articleID == None:
+ for reading in result:
+ text_level = text_difficulty_level(reading['text'], d3)
+ #print('TEXT_LEVEL %4.2f' % (text_level))
+ if within_range(text_level, user_level, 0.5):
+ d = reading
+ break
+
+ s = '
According to your word list, your level is %4.2f and we have chosen an article with a difficulty level of %4.2f for you.
' % (user_level, text_level)
+ s += '
%s
' % (d['date'])
+ s += '
%s
' % (d['text'])
+ s += '
%s
' % (d['source'])
+ s += '
%s
' % (get_question_part(d['question']))
+ s = s.replace('\n', ' ')
+ s += '%s' % (get_answer_part(d['question']))
+ session['articleID'] = d['article_id']
+ return s
+
+
+def appears_in_test(word, d):
+ if not word in d:
+ return ''
+ else:
+ return ','.join(d[word])
+
+
+def get_time():
+ return datetime.now().strftime('%Y%m%d%H%M') # upper to minutes
+
+
+def get_question_part(s):
+ s = s.strip()
+ result = []
+ flag = 0
+ for line in s.split('\n'):
+ line = line.strip()
+ if line == 'QUESTION':
+ result.append(line)
+ flag = 1
+ elif line == 'ANSWER':
+ flag = 0
+ elif flag == 1:
+ result.append(line)
+ return '\n'.join(result)
+
+
+def get_answer_part(s):
+ s = s.strip()
+ result = []
+ flag = 0
+ for line in s.split('\n'):
+ line = line.strip()
+ if line == 'ANSWER':
+ flag = 1
+ elif flag == 1:
+ result.append(line)
+ # https://css-tricks.com/snippets/javascript/showhide-element/
+ js = '''
+
+ '''
+ html_code = js
+ html_code += '\n'
+ html_code += '\n'
+ html_code += '
%s
\n' % ('\n'.join(result))
+ return html_code
+
+
+
+@app.route("//reset", methods=['GET', 'POST'])
+def user_reset(username):
+ if request.method == 'GET':
+ session['articleID'] = None
+ return redirect(url_for('userpage', username=username))
+ else:
+ return 'Under construction'
+
+
+@app.route("/mark", methods=['GET', 'POST'])
+def mark_word():
+ if request.method == 'POST':
+ d = load_freq_history(path_prefix + 'static/frequency/frequency.p')
+ lst_history = pickle_idea.dict2lst(d)
+ lst = []
+ for word in request.form.getlist('marked'):
+ lst.append((word, 1))
+ d = pickle_idea.merge_frequency(lst, lst_history)
+ pickle_idea.save_frequency_to_pickle(d, path_prefix + 'static/frequency/frequency.p')
+ return redirect(url_for('mainpage'))
+ else:
+ return 'Under construction'
+
+
+
+@app.route("/", methods=['GET', 'POST'])
+def mainpage():
+ if request.method == 'POST': # when we submit a form
+ content = request.form['content']
+ f = WordFreq(content)
+ lst = f.get_freq()
+ page = '\n'
+ # save history
+ d = load_freq_history(path_prefix + 'static/frequency/frequency.p')
+ lst_history = pickle_idea.dict2lst(d)
+ d = pickle_idea.merge_frequency(lst, lst_history)
+ pickle_idea.save_frequency_to_pickle(d, path_prefix + 'static/frequency/frequency.p')
+
+ return page
+ elif request.method == 'GET': # when we load a html page
+ page = '''
+
+
+
+
+ EnglishPal 英文单词高效记
+
+
+
+ '''
+ page += '
'
+ lst = pickle_idea2.dict2lst(d)
+ lst2 = []
+ for t in lst:
+ lst2.append((t[0], len(t[1])))
+ for x in sort_in_descending_order(lst2):
+ word = x[0]
+ freq = x[1]
+ if isinstance(d[word], list): # d[word] is a list of dates
+ if freq > 1:
+ page += '