From 19ba24b0e29aaffe1ae3544f726febd0766202b9 Mon Sep 17 00:00:00 2001
From: Dmitrii Suchkov
Date: Wed, 27 Nov 2019 17:53:59 +0300
Subject: [PATCH 01/39] more saas changes
---
converter/assets.py | 2 ++
converter/convert.py | 2 +-
converter/markdown/chips.py | 13 +++++++------
converter/markdown/cite.py | 2 +-
converter/markdown/elaboration.py | 2 +-
converter/markdown/fallacy.py | 2 +-
converter/markdown/picfigure.py | 6 +++---
converter/markdown/sidebar.py | 6 +++++-
converter/markdown/tablefigure.py | 6 +++---
converter/toc.py | 16 +++++++++++++---
10 files changed, 37 insertions(+), 20 deletions(-)
diff --git a/converter/assets.py b/converter/assets.py
index 3a06f077..711022a5 100644
--- a/converter/assets.py
+++ b/converter/assets.py
@@ -54,6 +54,8 @@ def _convert_assets(config, generate_dir, pdfs_for_convert, convert_from_path, b
image = Path(pdf.replace('.pdf', '.jpg'))
page = pages[0]
page.save(dst_folder.joinpath(image.name), 'JPEG')
+ except KeyboardInterrupt as e:
+ raise e
except BaseException as e:
logging.error("convert %s to jpg error" % pdf)
logging.error(e)
diff --git a/converter/convert.py b/converter/convert.py
index d4fbd73a..a7fa2b2d 100644
--- a/converter/convert.py
+++ b/converter/convert.py
@@ -48,7 +48,7 @@ def prepare_codio_rules(config):
def cleanup_latex(lines):
updated = []
starts = (
- '%', '\\index{', '\\label{', '\\markboth{', '\\addcontentsline{',
+ '%', '\\label{', '\\markboth{', '\\addcontentsline{',
'\\vspace', '\\newpage', '\\noindent',
'\\ttfamily', '\\chapter', '\\section', '\\newcommand', '\\vfill', '\\pagebreak'
)
diff --git a/converter/markdown/chips.py b/converter/markdown/chips.py
index eb1c370c..614f2d2c 100644
--- a/converter/markdown/chips.py
+++ b/converter/markdown/chips.py
@@ -11,12 +11,13 @@ def __init__(self, latex_str, caret_token):
super().__init__(latex_str, caret_token)
def make_block(self, matchobj):
- block_contents = matchobj.group('block_contents')
- block_contents = self.to_paragraph(block_contents)
- title = matchobj.group('title')
- title = self.to_paragraph(title)
- caret_token = self._caret_token
- return f'## {title}{caret_token}{block_contents}{caret_token}'
+ # block_contents = matchobj.group('block_contents')
+ # block_contents = self.to_paragraph(block_contents)
+ # title = matchobj.group('title')
+ # title = self.to_paragraph(title)
+ # caret_token = self._caret_token
+ # return f'## {title}{caret_token}{block_contents}{caret_token}'
+ return ''
def convert(self):
return chips_re.sub(self.make_block, self.str)
diff --git a/converter/markdown/cite.py b/converter/markdown/cite.py
index c5ab0c25..5da62866 100644
--- a/converter/markdown/cite.py
+++ b/converter/markdown/cite.py
@@ -40,7 +40,7 @@ def make_bib_content(line):
if len(sub_items) > 1:
value = sub_items[1].strip()
key = sub_items[0].strip().lower()
- if value.startswith('{'):
+ if value.startswith('{') or value.startswith('"{') or value.startswith('\'{'):
value = get_text_in_brackets(value)
value = ' '.join(value.split('\n'))
bib_entry[key] = value
diff --git a/converter/markdown/elaboration.py b/converter/markdown/elaboration.py
index e1d92bb2..fb077275 100644
--- a/converter/markdown/elaboration.py
+++ b/converter/markdown/elaboration.py
@@ -2,7 +2,7 @@
from converter.markdown.text_as_paragraph import TextAsParagraph
-elaboration_re = re.compile(r"""\\begin{elaboration}{(?P.*?)}(?P.*?)\\end{elaboration}""",
+elaboration_re = re.compile(r"""(\s+)?\\begin{elaboration}{(?P.*?)}(?P.*?)\\end{elaboration}""",
flags=re.DOTALL + re.VERBOSE)
diff --git a/converter/markdown/fallacy.py b/converter/markdown/fallacy.py
index a604fe72..8768595b 100644
--- a/converter/markdown/fallacy.py
+++ b/converter/markdown/fallacy.py
@@ -16,7 +16,7 @@ def make_block(self, matchobj):
title = matchobj.group('title')
title = self.to_paragraph(title)
caret_token = self._caret_token
- return f'## {title}{caret_token}{block_contents}'
+ return f'{caret_token}## {title}{caret_token}{block_contents}'
def convert(self):
return fallacy_re.sub(self.make_block, self.str)
diff --git a/converter/markdown/picfigure.py b/converter/markdown/picfigure.py
index e37ab539..3fbe26c6 100644
--- a/converter/markdown/picfigure.py
+++ b/converter/markdown/picfigure.py
@@ -28,15 +28,15 @@ def make_block(self, matchobj):
self.images.append(image)
image = image.replace('.pdf', '.jpg')
self._figure_counter += 1
- caption = '**Figure {}.{}**'.format(
+ caption = '**Figure {}.{}'.format(
self._chapter_num, self._figure_counter + self._figure_counter_offset
)
if self._refs.get(label, {}):
- caption = '**Figure {}**'.format(
+ caption = '**
Figure {}'.format(
self._refs.get(label).get('ref')
)
caret_token = self._caret_token
- return f"{caret_token}{caption}{caret_token}{content}"
+ return f"{caret_token}{caption}: {content}
**{caret_token}"
def convert(self):
self.images.clear()
diff --git a/converter/markdown/sidebar.py b/converter/markdown/sidebar.py
index 393d5597..8ed6b742 100644
--- a/converter/markdown/sidebar.py
+++ b/converter/markdown/sidebar.py
@@ -64,15 +64,19 @@ def _sidebargraphic_block(self, matchobj):
self._pdfs.append(image)
image = image.replace('.pdf', '.jpg')
- image_src = "".format(block_name, image)
+ image_src = "
".format(block_name, image)
block_contents = self.to_paragraph(block_contents)
caret_token = self._caret_token
if block_name:
+ block_name = block_name.strip()
return f'{caret_token}{caret_token}|||xdiscipline{caret_token}**{block_name}** ' \
f'{block_contents}{caret_token}{image_src}{caret_token}|||{caret_token}{caret_token}'
+ if not block_contents:
+ return f'{caret_token}{image_src}{caret_token}'
+
return f'{caret_token}{caret_token}|||xdiscipline{caret_token}{block_contents}' \
f'{caret_token}{image_src}{caret_token}|||{caret_token}{caret_token}'
diff --git a/converter/markdown/tablefigure.py b/converter/markdown/tablefigure.py
index 766ba7d8..3cabfd8f 100644
--- a/converter/markdown/tablefigure.py
+++ b/converter/markdown/tablefigure.py
@@ -27,11 +27,11 @@ def make_block(self, matchobj):
self._matches.append(replace_token)
self._figure_counter += 1
- caption = '**Figure {}.{}: '.format(
+ caption = '**Figure {}.{}: '.format(
self._chapter_num, self._figure_counter + self._figure_counter_offset
)
if self._refs.get(label, {}):
- caption = '**Figure {}: '.format(
+ caption = '**
Figure {}: '.format(
self._refs.get(label).get('ref')
)
@@ -51,7 +51,7 @@ def remove_matched_token(self, output, chars):
caret_token = self._caret_token
content = output[pos + token_len:index - 1]
content = content.strip()
- output = output[0:pos] + content + "**" + caret_token + output[index + 1:]
+ output = output[0:pos] + content + "
**" + caret_token + output[index + 1:]
break
else:
level += 1
diff --git a/converter/toc.py b/converter/toc.py
index 3da38b61..8677a02c 100644
--- a/converter/toc.py
+++ b/converter/toc.py
@@ -74,7 +74,7 @@ def get_name(line):
break
else:
level -= 1
- return cleanup_name(line[start + 1:end])
+ return cleanup_name(line[start + 1:end]), line[end + 1:].strip()
def get_bookdown_name(line):
@@ -116,11 +116,21 @@ def process_toc_lines(lines, tex_folder, parent_folder):
toc[len(toc) - 1].lines = item_lines
item_lines = []
section_type = CHAPTER if is_chapter(line) else SECTION
- toc.append(SectionItem(section_name=get_name(line), section_type=section_type, line_pos=line_pos))
+ section_name, additional_content_in_name = get_name(line)
+ toc.append(SectionItem(section_name=section_name, section_type=section_type, line_pos=line_pos))
if is_section_file(line):
section_lines = get_section_lines(line, parent_folder)
for sub_line in section_lines:
- item_lines.append(sub_line.rstrip('\n'))
+ if is_input(sub_line):
+ sub_content = get_include_lines(tex_folder, input_file(sub_line))
+ if sub_content:
+ item_lines.extend(sub_content)
+ line_pos += len(sub_content)
+ else:
+ item_lines.append(sub_line.rstrip('\n'))
+ elif additional_content_in_name:
+ item_lines.append(additional_content_in_name)
+ line_pos += 1
elif is_input(line) or is_include(line):
if is_input(line):
sub_toc = get_latex_toc(tex_folder, input_file(line))
From 1e7600948d32c993af263565fecd1a2c00fe08fb Mon Sep 17 00:00:00 2001
From: Dmitrii Suchkov
Date: Sun, 1 Dec 2019 10:32:24 +0300
Subject: [PATCH 02/39] render turingwinner
---
converter/latex2markdown.py | 4 ++
converter/markdown/turingwinner.py | 71 ++++++++++++++++++++++++++++++
tests/unit/cases/chips.md | 4 --
tests/unit/cases/esc_dol.md | 3 +-
tests/unit/cases/html.md | 10 ++---
tests/unit/cases/picfigure.md | 7 ++-
tests/unit/cases/saas.md | 2 +-
tests/unit/cases/saas1.md | 10 ++---
tests/unit/cases/saas2.md | 8 +---
tests/unit/cases/saas3.md | 2 +-
tests/unit/cases/sidebargraphic.md | 9 +---
tests/unit/cases/tablefigure.md | 6 +--
tests/unit/cases/turingwinner.md | 24 ++++++++++
tests/unit/cases/turingwinner.tex | 25 +++++++++++
tests/unit/test_render_markdown.py | 3 ++
15 files changed, 147 insertions(+), 41 deletions(-)
create mode 100644 converter/markdown/turingwinner.py
create mode 100644 tests/unit/cases/turingwinner.md
create mode 100644 tests/unit/cases/turingwinner.tex
diff --git a/converter/latex2markdown.py b/converter/latex2markdown.py
index b44140d1..7473caca 100644
--- a/converter/latex2markdown.py
+++ b/converter/latex2markdown.py
@@ -43,6 +43,7 @@
from converter.markdown.tabularx import Tabularx
from converter.markdown.tabular import Tabular
from converter.markdown.unescape import UnEscape
+from converter.markdown.turingwinner import TuringWinner
class LaTeX2Markdown(object):
@@ -123,6 +124,9 @@ def _latex_to_markdown(self):
output = PitFall(output, self._caret_token).convert()
output = Summary(output, self._caret_token).convert()
output = Chips(output, self._caret_token).convert()
+ output, images = TuringWinner(output, self._caret_token, self._detect_asset_ext,).convert()
+ if images:
+ self._pdfs.extend(images)
output = Cleanup(output).convert()
output, images, figure_counter = PicFigure(
diff --git a/converter/markdown/turingwinner.py b/converter/markdown/turingwinner.py
new file mode 100644
index 00000000..a5c3eabe
--- /dev/null
+++ b/converter/markdown/turingwinner.py
@@ -0,0 +1,71 @@
+from converter.markdown.text_as_paragraph import TextAsParagraph
+
+
+class TuringWinner(TextAsParagraph):
+ def __init__(self, latex_str, caret_token, detect_asset_ext):
+ super().__init__(latex_str, caret_token)
+ self._pdfs = []
+ self._detect_asset_ext = detect_asset_ext
+
+ def match_elements(self, text, n_matches):
+ level = 0
+ offset = 0
+ found_matches = 0
+ founds = []
+ last_index = 0
+ for index in range(0, len(text), 1):
+ ch = text[index]
+ last_index = index
+ if ch == '}':
+ level -= 1
+ if level == 0:
+ start_position = text.find("{", offset) + 1
+ offset += start_position
+ founds.append(text[start_position:index])
+ found_matches += 1
+ if found_matches == n_matches:
+ break
+ elif ch == '{':
+ level += 1
+ return founds, last_index
+
+ def make_content(self, image, block_name, block_contents, q_content, q_name):
+ if '.' not in image:
+ ext = self._detect_asset_ext(image)
+ if ext:
+ image = '{}.{}'.format(image, ext)
+
+ if image.lower().endswith('.pdf'):
+ self._pdfs.append(image)
+ image = image.replace('.pdf', '.jpg')
+
+ image_src = "
".format(block_name, image)
+
+ block_contents = self.to_paragraph(block_contents)
+ caret_token = self._caret_token
+
+ block_name = block_name.strip()
+ sidebar = f'{caret_token}{caret_token}|||xdiscipline{caret_token}**{block_name}** ' \
+ f'{block_contents}{caret_token}{image_src}{caret_token}|||{caret_token}{caret_token}'
+
+ quote = ''
+ if q_name and q_content:
+ quote = f'{caret_token}> {q_content}{caret_token}>' \
+ f'{caret_token}> __{q_name}__{caret_token}{caret_token}'
+
+ return sidebar + quote
+
+ def convert(self):
+ out = self.str
+ search_str = "\\turingwinner"
+ pos = out.find(search_str)
+ while pos != -1:
+ matches, index = self.match_elements(out[pos + len(search_str):], 5)
+ start = out[0:pos]
+ end_pos = pos + len(search_str) + 1 + index
+ end = out[end_pos:]
+ out = start + self.make_content(
+ f'turing/figs/{matches[0]}', matches[1], matches[2], matches[3], matches[4]
+ ) + end
+ pos = out.find(search_str, end_pos + 1)
+ return out, self._pdfs
diff --git a/tests/unit/cases/chips.md b/tests/unit/cases/chips.md
index 84ada25f..e69de29b 100644
--- a/tests/unit/cases/chips.md
+++ b/tests/unit/cases/chips.md
@@ -1,4 +0,0 @@
-## Regular Expressions
-_**Regular expressions**_, sometimes abbreviated *regexps* or *regexes*, are sequences of characters that define a search pattern. A regex can be applied to a string to determine whether the string contains those patterns. Given the preponderance of string manipulation in interactive and Web applications, all modern programming languages support regexes either within the language or as part of a library. This exercise will help you refresh your skills at constructing regular expressions.
-
-(Other skill “refreshers” needed? Some general questions about encapsulation and inheritance, before moving on to concrete examples in Ruby?)
\ No newline at end of file
diff --git a/tests/unit/cases/esc_dol.md b/tests/unit/cases/esc_dol.md
index 562da2a2..dcc89541 100644
--- a/tests/unit/cases/esc_dol.md
+++ b/tests/unit/cases/esc_dol.md
@@ -1,3 +1,2 @@

-**Figure 1.1**
-a) Study of software projects found that 53% of projects exceeding their budgets by a factor of 2.9 and overshot their schedule by a factor of 3.2 and another 31% of software projects were cancelled before completion (standish95). The estimated annual cost in the United States for such software projects was \$100B. b) Survey of members of the British Computer Society found that only 130 of 1027 projects met their schedule and budget. Half of all projects were maintenance or data conversion projects and half new development projects, but the successful projects divided into 127 of the former and just 3 of the latter (taylor00). c) Survey of 250 large projects, each with the equivalent of more than a million lines of C code, found similarly disappointing results (Jones04). d) Survey listing just the large examples of 50,000 projects, in that they cost at least \$10M in development (standish13). It has the most dismal outcomes, suggesting that HealthCare.gov had just a 10% chance of success.
\ No newline at end of file
+**Figure 1.1: a) Study of software projects found that 53% of projects exceeding their budgets by a factor of 2.9 and overshot their schedule by a factor of 3.2 and another 31% of software projects were cancelled before completion (standish95). The estimated annual cost in the United States for such software projects was \$100B. b) Survey of members of the British Computer Society found that only 130 of 1027 projects met their schedule and budget. Half of all projects were maintenance or data conversion projects and half new development projects, but the successful projects divided into 127 of the former and just 3 of the latter (taylor00). c) Survey of 250 large projects, each with the equivalent of more than a million lines of C code, found similarly disappointing results (Jones04). d) Survey listing just the large examples of 50,000 projects, in that they cost at least \$10M in development (standish13). It has the most dismal outcomes, suggesting that HealthCare.gov had just a 10% chance of success.
**
\ No newline at end of file
diff --git a/tests/unit/cases/html.md b/tests/unit/cases/html.md
index 9973cfcd..9024bff5 100644
--- a/tests/unit/cases/html.md
+++ b/tests/unit/cases/html.md
@@ -62,15 +62,15 @@ There are four basic mechanisms by which a selector in a CSS file can match an H
ch_arch/tables/css_cheat
-**Figure 1.1: A few CSS constructs, including those explained in Screencast css-intro. The top table shows some CSS *selectors*, which identify the elements to be styled; the bottom table shows a few of the many attributes, whose names are usually self-explanatory, and example values they can be assigned. Not all attributes are valid on all elements.**
+**Figure 1.1: A few CSS constructs, including those explained in Screencast css-intro. The top table shows some CSS *selectors*, which identify the elements to be styled; the bottom table shows a few of the many attributes, whose names are usually self-explanatory, and example values they can be assigned. Not all attributes are valid on all elements.
**
Using this new information, Figure fig:10k expands steps 2 and 3 from the previous section's summary of how SaaS works.

-**Figure 1.3**
-SaaS from 10,000 feet. Compared to Figure fig:50k, step 2 has been expanded to describe the content returned by the Web server, and step 3 has been expanded to describe the role of CSS in how the Web browser renders the content.
+**Figure 1.3: SaaS from 10,000 feet. Compared to Figure fig:50k, step 2 has been expanded to describe the content returned by the Web server, and step 3 has been expanded to describe the role of CSS in how the Web browser renders the content.
**
+
CSS provides for sophisticated layout behaviors, but can be tricky to use in 2 regards. First, some background in layout and graphic design is helpful in deciding how to style site elements - spacing, typography, color palette. Second, even if you know what you want the site to look like, it can be tricky to write the necessary CSS to achieve complex layouts, in which elements may "float" to the far left or far right of the page while text flows around them, or rearrange themselves responsively when the screen geometry changes (browser window resized, phone rotates) to provide a defensible user experience on both desktop and mobile devices.
@@ -82,9 +82,7 @@ JavaScript - more sophisticated behaviors such as animations, collapsing menus,
Rather than delving deeply into the aesthetics of graphic design, our goal for you as a well-rounded full-stack developer is that you should know how to provide well-structured pages with proper element nesting and clean CSS class tags, for two reasons. First, with a good front-end framework, just doing this will be enough to provide an AURA site (aesthetic, usable, responsive, accessible). Second, a clean site layout and classing allows designers to refine, customize, or work separately on the site's visual appearance.
-There are 2 principles to using front-end frameworks successfully in this way: semantic styling and grid layout. Semantic styling means First, think of your page's visual elements not in terms of their visual characteristics ("This message should appear in a red box with bold text") but in terms of their function ("This message signals an error", "This text is the page title", "This list of items is a menu of navigation options"). A good front-end framework names its styles according to the function they enable an element to fulfill, rather than according to their visual appearance.
-
-## SPA or MPA?
+There are 2 principles to using front-end frameworks successfully in this way: semantic styling and grid layout. Semantic styling means First, think of your page's visual elements not in terms of their visual characteristics ("This message should appear in a red box with bold text") but in terms of their function ("This message signals an error", "This text is the page title", "This list of items is a menu of navigation options"). A good front-end framework names its styles according to the function they enable an element to fulfill, rather than according to their visual appearance.## SPA or MPA?
SPA vs MPA: Are you building something that's more like a website (transactional? lots of different possible screens? user navigates large amounts of data in a typical session? multi-screen workflows?) or more like a desktop app (few screens? continuous interaction vs transactional, eg something like Pivotal Tracker? user navigates modest amounts of data in a typical session? short workflows or interactions typically limited to 1 screen?) If it's primarily a website, use HTML5 + jQuery where needed. If primarily an app, may be better off using a framework. [Need a checklist like "when to use agile" for "when to build a SPA vs MPA"]. Examples of popular SPAs: Gmail, Google Docs, Pivotal Tracker. Popular MPAs: IMDb, Amazon.com, Google Search. *MPA vs SPA is primarily a user experience question, not a technical one!*
diff --git a/tests/unit/cases/picfigure.md b/tests/unit/cases/picfigure.md
index af8e79d1..d45825ae 100644
--- a/tests/unit/cases/picfigure.md
+++ b/tests/unit/cases/picfigure.md
@@ -1,7 +1,6 @@

-**Figure 1.1**
-Screen image of the UI of the Pivotal Tracker service.
+**Figure 1.1: Screen image of the UI of the Pivotal Tracker service.
**
+

-**Figure 1.2**
-Storyboard of UI for searching The Movie Database.
\ No newline at end of file
+**Figure 1.2: Storyboard of UI for searching The Movie Database.
**
\ No newline at end of file
diff --git a/tests/unit/cases/saas.md b/tests/unit/cases/saas.md
index ee2a3a56..7be5b08c 100644
--- a/tests/unit/cases/saas.md
+++ b/tests/unit/cases/saas.md
@@ -25,7 +25,7 @@ Combining the advantages to the customer and the developer together explains why
file content
-**Figure 1.1: Examples of SaaS programming frameworks and the programming languages they are written in**
+**Figure 1.1: Examples of SaaS programming frameworks and the programming languages they are written in
**
diff --git a/tests/unit/cases/saas1.md b/tests/unit/cases/saas1.md
index d8638357..775315ed 100644
--- a/tests/unit/cases/saas1.md
+++ b/tests/unit/cases/saas1.md
@@ -85,8 +85,8 @@ This observation led to a software development lifecycle developed in the 1980s

-**Figure 1.1**
-The Spiral lifecycle combines Waterfall with prototyping. It starts at the center, with each iteration around the spiral going through the four phases and resulting in a revised prototype until the product is ready for release.
+**Figure 1.1: The Spiral lifecycle combines Waterfall with prototyping. It starts at the center, with each iteration around the spiral going through the four phases and resulting in a revised prototype until the product is ready for release.
**
+
Rather than document all the requirements at the beginning, as in the Waterfall model, the requirement documents are developed across the iteration as they are needed and evolve with the project. Iterations involve the customer before the product is completed, which reduces chances of misunderstandings. However, as originally envisioned, these iterations were 6 to 24 months long, so there is plenty of time for customers to change their minds during an iteration! Thus, Spiral still relies on planning and extensive documentation, but the plan is expected to evolve on each iteration.
@@ -128,8 +128,8 @@ In addition to the dynamically changing phases of the project, RUP identifies si
These disciplines are more static than the phases, in that they nominally exist over the whole lifetime of the project. However, some disciplines get used more in earlier phases (like business modeling), some periodically throughout the process (like test), and some more towards the end (deployment). Figure fig:RUP shows the relationship of the phases and the disciplines, with the area indicating the amount of effort in each discipline over time.

-**Figure 1.2**
-The Rational Unified Process lifecycle allows the project to have multiple iterations in each phase and identifies the skills needed by the project team, which vary in effort over time. RUP also has three “supporting disciplines” not shown in this figure: Configuration and Change Management, Project Management, and Environment. (Image from Wikipedia Commons by Dutchgilder.)
+**Figure 1.2: The Rational Unified Process lifecycle allows the project to have multiple iterations in each phase and identifies the skills needed by the project team, which vary in effort over time. RUP also has three “supporting disciplines” not shown in this figure: Configuration and Change Management, Project Management, and Environment. (Image from Wikipedia Commons by Dutchgilder.)
**
+
An unfortunate downside to teaching a Plan-and-Document approach is that students may find software development tedious (Nawrocki02,Estler12). Given the importance of predictable software development, this is hardly a strong enough reason not to teach it; the good news is that there are alternatives that work just as well for many projects that are a better fit to the classroom, as we describe in the next section.
@@ -157,8 +157,6 @@ An unfortunate downside to teaching a Plan-and-Document approach is that student
Check yourself
Waterfall phases separate planning (requirements and architectural design) from implementation. Testing the product before release is next, followed by a separate operations phase. The Spiral phases are aimed at an iteration: set the goals for an iteration; explore alternatives; develop and verify the prototype for this iteration; and plan the next iteration. RUP phases are tied closer to business objectives: inception makes business case and sets schedule and budget; elaboration works with customers to build an initial prototype; construction builds and test the first version; and transition deploys the product.
|||
-
-
## SEI Capability Maturity Model (CMM)
The Software Engineering Institute at Carnegie Mellon University proposed the _**Capability Maturity Model**_ (CMM) (Paulk05) to evaluate organizations' software-development processes based on Plan-and-Document methodologies. The idea is that by modeling the software development process, an organization can improve them. SEI studies observed five levels of software practice:
diff --git a/tests/unit/cases/saas2.md b/tests/unit/cases/saas2.md
index 03a76a01..5b3f7017 100644
--- a/tests/unit/cases/saas2.md
+++ b/tests/unit/cases/saas2.md
@@ -15,14 +15,8 @@ While we now see how to build some software successfully, not all projects are s
Check yourself
False: Both build working but incomplete prototypes that the customer helps evaluate. The difference is that customers are involved every two weeks in Agile versus up to two years in with Spiral.
|||
-
-
-
-
## Versions of Agile
-There is not just a single Agile lifecycle. We are following _**Extreme Programming**_ (XP), which includes one- to two-week iterations, behavior driven design (see Chapter chap:bdd), test-driven development (see Chapter chap:tdd), and pair programming (see Section sec:Pair). Another popular version is _**Scrum**_ (see Section sec:Scrum), where self-organizing teams use two- to four-week iterations called _**sprints**_, and then regroup to plan the next sprint. A key feature is daily standup meetings to identify and overcome obstacles. While there are multiple roles in the scrum team, the norm is to rotate the roles over time. The _**Kanban**_ approach is derived from Toyota's just-in-time manufacturing process, which in this case treats software development as a pipeline. Here the team members have fixed roles, and the goal is to balance the number of team members so that there are no bottlenecks with tasks stacking up waiting for processing. One common feature is a wall of cards that to illustrate the state of all tasks in the pipeline. There are also hybrid lifecycles that try to combine the best of two worlds. For example, _**ScrumBan**_ uses the daily meetings and sprints of Scrum but replaces the planning phase with the more dynamic pipeline control of the wall of cards from Kanban.
-
-## Reforming Acquisition Regulations
+There is not just a single Agile lifecycle. We are following _**Extreme Programming**_ (XP), which includes one- to two-week iterations, behavior driven design (see Chapter chap:bdd), test-driven development (see Chapter chap:tdd), and pair programming (see Section sec:Pair). Another popular version is _**Scrum**_ (see Section sec:Scrum), where self-organizing teams use two- to four-week iterations called _**sprints**_, and then regroup to plan the next sprint. A key feature is daily standup meetings to identify and overcome obstacles. While there are multiple roles in the scrum team, the norm is to rotate the roles over time. The _**Kanban**_ approach is derived from Toyota's just-in-time manufacturing process, which in this case treats software development as a pipeline. Here the team members have fixed roles, and the goal is to balance the number of team members so that there are no bottlenecks with tasks stacking up waiting for processing. One common feature is a wall of cards that to illustrate the state of all tasks in the pipeline. There are also hybrid lifecycles that try to combine the best of two worlds. For example, _**ScrumBan**_ uses the daily meetings and sprints of Scrum but replaces the planning phase with the more dynamic pipeline control of the wall of cards from Kanban.## Reforming Acquisition Regulations
Long before the ACA website, there were calls to reform software acquisition, as in this US National Academies study of the Department of Defense (DOD):
“The DOD is hampered by a culture and acquisition-related practices that favor large programs, high-level oversight, and a very deliberate, serial approach to development and testing (the waterfall model). Programs that are expected to deliver complete, nearly perfect solutions and that take years to develop are the norm in the DOD... These approaches run counter to Agile acquisition practices in which the product is the primary focus, end users are engaged early and often, the oversight of incremental product development is delegated to the lowest practical level, and the program management team has the flexibility to adjust the content of the increments in order to meet delivery schedules... Agile approaches have allowed their adopters to outstrip established industrial giants that were beset with ponderous, process-bound, industrial-age management structures. Agile approaches have succeeded because their adopters recognized the issues that contribute to risks in an IT program and changed their management structures and processes to mitigate the risks.”
diff --git a/tests/unit/cases/saas3.md b/tests/unit/cases/saas3.md
index 91a31601..8d3e5f62 100644
--- a/tests/unit/cases/saas3.md
+++ b/tests/unit/cases/saas3.md
@@ -8,7 +8,7 @@
|||xdiscipline
**Grace Murray Hopper** (1906--1992) was one of the first programmers, developed the first compiler, and was referred to as “Amazing Grace.” She became a Rear Admiral in the US Navy, and in 1997, a warship was named for her: the USS Hopper.
-
+
|||
diff --git a/tests/unit/cases/sidebargraphic.md b/tests/unit/cases/sidebargraphic.md
index bbf0101c..4845031e 100644
--- a/tests/unit/cases/sidebargraphic.md
+++ b/tests/unit/cases/sidebargraphic.md
@@ -1,17 +1,12 @@
|||xdiscipline
**Alan Perlis** (1922--1990) was the first recipient of the Turing Award (1966), conferred for his influence on advanced programming languages and compilers. In 1958 he helped design ALGOL, which has influenced virtually every imperative programming language including C and Java. To avoid FORTRAN's syntactic and semantic problems, ALGOL was the first language described in terms of a formal grammar, the eponymous _**Backus-Naur form**_ (named for Turing award winner Jim Backus and his colleague Peter Naur).
-
+
|||
-
-|||xdiscipline
-
-
-|||
-
+
**David Patterson** recently retired from a 40-year career as a Professor of Computer Science at UC Berkeley. In the
\ No newline at end of file
diff --git a/tests/unit/cases/tablefigure.md b/tests/unit/cases/tablefigure.md
index bfcbf9be..ebcfd1a1 100644
--- a/tests/unit/cases/tablefigure.md
+++ b/tests/unit/cases/tablefigure.md
@@ -2,14 +2,14 @@ We can therefore say that the expression **3+2** results in calling **Fixnum#+**
file content content
-**Figure 1.1: The first column is Ruby's syntactic sugar for common operations, the second column shows the explicit method call, and the third column shows how to perform the same method call using Ruby's **send**, which accepts either a string or (more idiomatically) a symbol for the method name.**
+**Figure 1.1: The first column is Ruby's syntactic sugar for common operations, the second column shows the explicit method call, and the third column shows how to perform the same method call using Ruby's **send**, which accepts either a string or (more idiomatically) a symbol for the method name.
**
file content content
-**Figure 1.2: Comparing Amazon.com and Healthcare.gov during its first three months. (Thorp13) After its stumbling start, the deadline was extended from December 15, 2013 to March 31, 2014, which explains the lower goal in customers per day in December. Note that availability for ACA does *not* include time for “scheduled maintenance,” which Amazon does include (Zients13). The error rate was for significant errors on the forms sent to insurance companies (Horsley13). The site was widely labeled by security experts as insecure, as the developers were under tremendous pressure to get proper functionality, and little attention was paid to security (Harrington13)**
+**Figure 1.2: Comparing Amazon.com and Healthcare.gov during its first three months. (Thorp13) After its stumbling start, the deadline was extended from December 15, 2013 to March 31, 2014, which explains the lower goal in customers per day in December. Note that availability for ACA does *not* include time for “scheduled maintenance,” which Amazon does include (Zients13). The error rate was for significant errors on the forms sent to insurance companies (Horsley13). The site was widely labeled by security experts as insecure, as the developers were under tremendous pressure to get proper functionality, and little attention was paid to security (Harrington13)
**
file content content
-**Figure 1.3: Some common Ruby methods on collections. For those that expect a block, the “Block” column shows the number of arguments expected by the block; if blank, the method doesn't expect a block. For example, a call to **sort**, whose block expects 2 arguments, might look like: **c.sort { |a,b| a $<=>$ b }**. These methods all return a new object rather than modifying the receiver, but some methods also have a *destructive* variant ending in **!**, for example **sort!**, that modify their argument in place (and also return the new value). Use destructive methods with extreme care, if at all.**
\ No newline at end of file
+**Figure 1.3: Some common Ruby methods on collections. For those that expect a block, the “Block” column shows the number of arguments expected by the block; if blank, the method doesn't expect a block. For example, a call to **sort**, whose block expects 2 arguments, might look like: **c.sort { |a,b| a $<=>$ b }**. These methods all return a new object rather than modifying the receiver, but some methods also have a *destructive* variant ending in **!**, for example **sort!**, that modify their argument in place (and also return the new value). Use destructive methods with extreme care, if at all.
**
\ No newline at end of file
diff --git a/tests/unit/cases/turingwinner.md b/tests/unit/cases/turingwinner.md
new file mode 100644
index 00000000..4d3c0059
--- /dev/null
+++ b/tests/unit/cases/turingwinner.md
@@ -0,0 +1,24 @@
+Hello content
+
+|||xdiscipline
+**Alan Perlis (1922--1990)** was the first recipient of the Turing Award (1966), conferred for his influence on advanced programming languages and compilers. In 1958 he helped design ALGOL, which has influenced virtually every imperative programming language including C and Java. To avoid FORTRAN's syntactic and semantic problems, ALGOL was the first language described in terms of a formal grammar, the eponymous _**Backus-Naur form**_ (named for Turing award winner Jim Backus and his colleague Peter Naur).
+
+|||
+
+
+> In programming, everything we do is a special case of something more general---and often we know it too quickly.
+>
+> __Alan Perlis__
+
+ End content
+
+
+
+|||xdiscipline
+**Vinton E. “Vint” Cerf (1943--) and Bob Kahn (1938--)** shared the 2004 Turing Award for their pioneering work on networking architecture and protocols, including TCP/IP.
+
+|||
+
+
+
+End content2
\ No newline at end of file
diff --git a/tests/unit/cases/turingwinner.tex b/tests/unit/cases/turingwinner.tex
new file mode 100644
index 00000000..3c216473
--- /dev/null
+++ b/tests/unit/cases/turingwinner.tex
@@ -0,0 +1,25 @@
+Hello content
+\turingwinner{perlis}{Alan Perlis (1922--1990)}%
+ {was the first recipient of the Turing Award (1966), conferred
+ for his influence on advanced programming languages and compilers.
+ In 1958 he helped design ALGOL,
+ which has influenced virtually every imperative programming language
+ including C and Java. To avoid FORTRAN's
+ syntactic and semantic problems, ALGOL was the first language
+ described in terms of a formal grammar, the eponymous
+ \w[Backus-Naur_Form]{Backus-Naur form} (named for Turing award
+ winner Jim Backus and his colleague Peter Naur).}%
+ {In programming, everything we do is a special case of
+ something more general---and often we know it too quickly.}{Alan
+ Perlis}
+End content
+
+\turingwinner{cerf_kahn}{Vinton E. ``Vint'' Cerf (1943--) and Bob Kahn
+(1938--)}%
+{shared the 2004 Turing Award for their pioneering work on networking
+architecture and protocols, including TCP/IP.}{}{}
+
+End content2
+
+
+
diff --git a/tests/unit/test_render_markdown.py b/tests/unit/test_render_markdown.py
index 0933175c..7a498d1b 100644
--- a/tests/unit/test_render_markdown.py
+++ b/tests/unit/test_render_markdown.py
@@ -297,3 +297,6 @@ def test_tabularx(self):
def test_twoicons(self):
self.run_case("twoicons")
+
+ def test_turingwinner(self):
+ self.run_case("turingwinner")
From 8369ee0c0cea03e366f25b31b324973dc286cb2b Mon Sep 17 00:00:00 2001
From: Dmitrii Suchkov
Date: Sun, 1 Dec 2019 10:35:23 +0300
Subject: [PATCH 03/39] toc case
---
tests/unit/test_toc.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/tests/unit/test_toc.py b/tests/unit/test_toc.py
index 8fd3830f..c7ce2f94 100644
--- a/tests/unit/test_toc.py
+++ b/tests/unit/test_toc.py
@@ -102,4 +102,5 @@ def test_toc_generation_exception(self):
('\\section{{\\tt Comparable} and {\\tt Comparator}}', 'Comparable and Comparator')
])
def test_name_generation(self, case, should_be):
- self.assertEqual(get_name(case), should_be)
+ name, _ = get_name(case)
+ self.assertEqual(name, should_be)
From 6fa0920e7d53b32ec37c9b11d9cd7f58e76b3a31 Mon Sep 17 00:00:00 2001
From: achetporov
Date: Tue, 14 Jan 2020 16:33:09 +0300
Subject: [PATCH 04/39] fix after tex structure change
---
converter/convert.py | 2 +-
converter/toc.py | 6 ++++--
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/converter/convert.py b/converter/convert.py
index a7fa2b2d..befe3cf9 100644
--- a/converter/convert.py
+++ b/converter/convert.py
@@ -55,7 +55,7 @@ def cleanup_latex(lines):
for line in lines:
if line.startswith(starts):
continue
- updated.append(line)
+ updated.append(line.rstrip('\n'))
return updated
diff --git a/converter/toc.py b/converter/toc.py
index 8677a02c..44546a32 100644
--- a/converter/toc.py
+++ b/converter/toc.py
@@ -1,6 +1,6 @@
import yaml
import re
-
+import os
from pathlib import Path
from converter.guides.item import SectionItem, SECTION, CHAPTER
@@ -95,7 +95,9 @@ def get_section_lines(line, tex_folder):
if result:
file = result.group("block_path")
if '.tex' not in file:
- file = '_{}.tex'.format(file)
+ dirname = os.path.basename(tex_folder)
+ prefix = dirname.split('_')[-1]
+ file = prefix + '_{}.tex'.format(file)
tex_file = tex_folder.joinpath(file)
if tex_file.exists():
with open(tex_file, 'r', errors='replace') as file:
From e6968454fb35e63da800ca64eff39cf833bdfd36 Mon Sep 17 00:00:00 2001
From: achetporov
Date: Wed, 15 Jan 2020 09:58:22 +0300
Subject: [PATCH 05/39] fix after tex structure change
---
converter/toc.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/converter/toc.py b/converter/toc.py
index 44546a32..8854d180 100644
--- a/converter/toc.py
+++ b/converter/toc.py
@@ -1,6 +1,6 @@
import yaml
import re
-import os
+
from pathlib import Path
from converter.guides.item import SectionItem, SECTION, CHAPTER
@@ -95,9 +95,9 @@ def get_section_lines(line, tex_folder):
if result:
file = result.group("block_path")
if '.tex' not in file:
- dirname = os.path.basename(tex_folder)
- prefix = dirname.split('_')[-1]
- file = prefix + '_{}.tex'.format(file)
+ dirname = Path(tex_folder).name
+ prefix = dirname.split('ch_')[-1]
+ file = f'{prefix}_{file}.tex'
tex_file = tex_folder.joinpath(file)
if tex_file.exists():
with open(tex_file, 'r', errors='replace') as file:
From d77f550e4c8a7a12be07c60dc7e742acb5b57a9e Mon Sep 17 00:00:00 2001
From: achetporov
Date: Mon, 27 Apr 2020 12:17:12 +0300
Subject: [PATCH 06/39] 11080 fix some more problems (#40)
fix some more problems
---
converter/convert.py | 4 +--
converter/latex2markdown.py | 2 ++
converter/markdown/bold.py | 2 +-
converter/markdown/center.py | 3 +-
converter/markdown/chips.py | 13 ++++----
converter/markdown/codefilefigure.py | 2 +-
converter/markdown/del_icons_description.py | 14 +++++++++
converter/markdown/elaboration.py | 2 +-
converter/markdown/figure.py | 13 ++++++--
converter/markdown/ignore.py | 9 ++++++
converter/markdown/italic_bold.py | 2 +-
converter/markdown/links.py | 8 ++++-
converter/markdown/lists.py | 33 +++++++++------------
converter/markdown/match_elements.py | 21 +++++++++++++
converter/markdown/newline.py | 1 +
converter/markdown/picfigure.py | 26 +++++++++-------
converter/markdown/quotation.py | 32 +++++++++-----------
converter/markdown/saas_specific.py | 12 ++++++--
converter/markdown/sidebar.py | 5 ++--
converter/markdown/tablefigure.py | 1 +
converter/markdown/tabular.py | 19 ++++++++++--
converter/markdown/turingwinner.py | 27 ++---------------
converter/refs.py | 20 +++++++++++--
converter/toc.py | 9 ++++++
tests/unit/cases/bc.md | 8 ++---
tests/unit/cases/checkyourself_complex.md | 10 +++----
tests/unit/cases/chips.md | 2 ++
tests/unit/cases/chips.tex | 24 ++++++---------
tests/unit/cases/codefigure.md | 10 +++----
tests/unit/cases/concepts.md | 12 ++++----
tests/unit/cases/html.md | 33 +++++++++++----------
tests/unit/cases/index.md | 2 +-
tests/unit/cases/italic_bold.md | 4 +--
tests/unit/cases/makequotation.md | 13 +++++++-
tests/unit/cases/nested_list.md | 4 +--
tests/unit/cases/saas.md | 8 ++---
tests/unit/cases/saas1.md | 23 ++++++++------
tests/unit/cases/saas1.tex | 2 +-
tests/unit/cases/saas2.md | 8 +++--
tests/unit/cases/saas3.md | 2 +-
tests/unit/cases/saas3.tex | 2 +-
tests/unit/cases/screencast.md | 8 ++---
tests/unit/cases/sidebar.md | 4 +--
tests/unit/cases/sidebargraphic.md | 4 +--
tests/unit/cases/tablefigure.md | 6 ++--
tests/unit/cases/turingwinner.md | 4 +--
tests/unit/cases/w.md | 4 +--
tests/unit/cases/x.md | 2 +-
tests/unit/test_render_markdown.py | 3 ++
49 files changed, 293 insertions(+), 189 deletions(-)
create mode 100644 converter/markdown/del_icons_description.py
create mode 100644 converter/markdown/match_elements.py
diff --git a/converter/convert.py b/converter/convert.py
index befe3cf9..936038cb 100644
--- a/converter/convert.py
+++ b/converter/convert.py
@@ -49,8 +49,8 @@ def cleanup_latex(lines):
updated = []
starts = (
'%', '\\label{', '\\markboth{', '\\addcontentsline{',
- '\\vspace', '\\newpage', '\\noindent',
- '\\ttfamily', '\\chapter', '\\section', '\\newcommand', '\\vfill', '\\pagebreak'
+ '\\vspace', '\\newpage', '\\vfill', '\\pagebreak',
+ '\\ttfamily', '\\chapter', '\\section', '\\newcommand'
)
for line in lines:
if line.startswith(starts):
diff --git a/converter/latex2markdown.py b/converter/latex2markdown.py
index 7473caca..b414065b 100644
--- a/converter/latex2markdown.py
+++ b/converter/latex2markdown.py
@@ -1,6 +1,7 @@
import uuid
import re
+from converter.markdown.del_icons_description import DelIconsDescription
from converter.markdown.inline_code_block import InlineCodeBlock
from converter.markdown.code_block import CodeBlock
from converter.markdown.bold import Bold
@@ -75,6 +76,7 @@ def increment_figure_counter(self, figure_counter):
def _latex_to_markdown(self):
output = self._latex_string
+ output = DelIconsDescription(output).convert()
output, figure_counter = TableFigure(
output, self._caret_token, self._load_workspace_file,
self._figure_counter_offset, self._chapter_num, self._refs
diff --git a/converter/markdown/bold.py b/converter/markdown/bold.py
index 6004477e..b0a27421 100644
--- a/converter/markdown/bold.py
+++ b/converter/markdown/bold.py
@@ -14,7 +14,7 @@ def convert(self):
output = re.sub(r"{\\sf[ ](.*?)}", r"**\1**", output, flags=re.DOTALL + re.VERBOSE)
output = match_block("\\B{", output, lambda match: f"**{match}**")
- output = match_block("\\C{", output, lambda match: f"**{match}**")
+ output = match_block("\\C{", output, lambda match: f"__{match}__")
output = match_block("\\T{", output, lambda match: f"**{match}**")
return output
diff --git a/converter/markdown/center.py b/converter/markdown/center.py
index 046f6d5c..bfa4d37f 100644
--- a/converter/markdown/center.py
+++ b/converter/markdown/center.py
@@ -2,7 +2,8 @@
from converter.markdown.text_as_paragraph import TextAsParagraph
-center_re = re.compile(r"""\\begin{center}(?P.*?)\\end{center}""", flags=re.DOTALL + re.VERBOSE)
+center_re = re.compile(r"""\\begin{(center|centering)}(?P.*?)\\end{(center|centering)}""",
+ flags=re.DOTALL + re.VERBOSE)
class Center(TextAsParagraph):
diff --git a/converter/markdown/chips.py b/converter/markdown/chips.py
index 614f2d2c..eb1c370c 100644
--- a/converter/markdown/chips.py
+++ b/converter/markdown/chips.py
@@ -11,13 +11,12 @@ def __init__(self, latex_str, caret_token):
super().__init__(latex_str, caret_token)
def make_block(self, matchobj):
- # block_contents = matchobj.group('block_contents')
- # block_contents = self.to_paragraph(block_contents)
- # title = matchobj.group('title')
- # title = self.to_paragraph(title)
- # caret_token = self._caret_token
- # return f'## {title}{caret_token}{block_contents}{caret_token}'
- return ''
+ block_contents = matchobj.group('block_contents')
+ block_contents = self.to_paragraph(block_contents)
+ title = matchobj.group('title')
+ title = self.to_paragraph(title)
+ caret_token = self._caret_token
+ return f'## {title}{caret_token}{block_contents}{caret_token}'
def convert(self):
return chips_re.sub(self.make_block, self.str)
diff --git a/converter/markdown/codefilefigure.py b/converter/markdown/codefilefigure.py
index 730b2453..adcb0d76 100644
--- a/converter/markdown/codefilefigure.py
+++ b/converter/markdown/codefilefigure.py
@@ -51,7 +51,7 @@ def make_block(self, matchobj):
self._refs.get(label).get('ref')
)
- return f'{caret_token}{caption}{caret_token}**source:{file_path}**{caret_token}' \
+ return f'{caret_token}{caption}{caret_token}**source: {file_path}**{caret_token}' \
f'```code{caret_token}{file_content}{caret_token}```{caret_token}{replace_token}'
def remove_matched_token(self, output, chars):
diff --git a/converter/markdown/del_icons_description.py b/converter/markdown/del_icons_description.py
new file mode 100644
index 00000000..55dbae5f
--- /dev/null
+++ b/converter/markdown/del_icons_description.py
@@ -0,0 +1,14 @@
+import re
+
+
+class DelIconsDescription(object):
+ def __init__(self, latex_str):
+ self.str = latex_str
+
+ def convert(self):
+ output = self.str
+
+ output = re.sub(r"\s*We also use.*?look them up.\s*", "", output)
+ output = re.sub(r"\\tablefigure{ch_intro/tables/icons_table}{.*?}{.*?}", "", output)
+
+ return output
diff --git a/converter/markdown/elaboration.py b/converter/markdown/elaboration.py
index fb077275..dc6d7d28 100644
--- a/converter/markdown/elaboration.py
+++ b/converter/markdown/elaboration.py
@@ -16,7 +16,7 @@ def make_block(self, matchobj):
title = self.to_paragraph(title)
block_contents = self.to_paragraph(block_contents)
caret_token = self._caret_token
- return f'## {title}{caret_token}{block_contents}'
+ return f'{caret_token}## {title}{caret_token}{block_contents}'
def convert(self):
return elaboration_re.sub(self.make_block, self.str)
diff --git a/converter/markdown/figure.py b/converter/markdown/figure.py
index 13211040..7986b66c 100644
--- a/converter/markdown/figure.py
+++ b/converter/markdown/figure.py
@@ -34,7 +34,7 @@ def _figure_block(self, matchobj):
if not line.startswith("\\includegraphics"):
line = get_text_in_brackets(line)
images.append(get_text_in_brackets(line))
- elif line.startswith("\\caption"):
+ elif "\\caption" in line:
if '}' in line:
caption += get_text_in_brackets(line)
else:
@@ -59,9 +59,16 @@ def _figure_block(self, matchobj):
markdown_images.append(
"".format(caption, image)
)
-
caret_token = self._caret_token
- return f'{self._caret_token.join(markdown_images)}{caret_token}{caret_token}**{caption}**'
+ caption = caption.replace("**", "").strip()
+
+ if markdown_images:
+ return f'{self._caret_token.join(markdown_images)}{caret_token}{caret_token}**{caption}**'
+
+ block_contents = block_contents.replace('\\label{.*?}', '')
+ block_contents = re.sub(r"\\caption{(.*?)}", r"", block_contents, flags=re.DOTALL + re.VERBOSE)
+
+ return f'{block_contents}**{caption}
**{caret_token}'
def convert(self):
output = self.str
diff --git a/converter/markdown/ignore.py b/converter/markdown/ignore.py
index 2144efa5..dc50035e 100644
--- a/converter/markdown/ignore.py
+++ b/converter/markdown/ignore.py
@@ -40,7 +40,16 @@ def convert(self):
output = self.remove_chars(output, "\\index{")
output = self.remove_chars(output, "\\label{")
output = self.remove_chars(output, "\\vspace{")
+ output = self.remove_chars(output, "\\addtocounter{")
output = re.sub(r"\\noindent", "", output)
+ output = re.sub(r"\\prereq", "", output)
+ output = re.sub(r"\\relax", "", output)
+ output = re.sub(r"\s\\n\n", "", output)
+ output = re.sub(r"\\fbox{(.*?\\end{minipage}\n)}\n", r"\1", output, flags=re.DOTALL + re.VERBOSE)
+ output = re.sub(r"\\begin{minipage}{.*?}", "", output)
+ output = re.sub(r"\\end{minipage}", "", output)
+ output = re.sub(r"\\begin{textfigure}", "", output)
+ output = re.sub(r"\\end{textfigure}", "", output)
output = ifhtml_re.sub(self.make_block, output)
output = ifmobile_re.sub(self.make_block, output)
diff --git a/converter/markdown/italic_bold.py b/converter/markdown/italic_bold.py
index 60396676..cc8e370b 100644
--- a/converter/markdown/italic_bold.py
+++ b/converter/markdown/italic_bold.py
@@ -8,7 +8,7 @@ def __init__(self, latex_str):
def make_block(self, matchobj):
block_contents = matchobj.group('block_contents')
block_contents = re.sub(r"\\\\", r"\\", block_contents)
- return "_**{}**_".format(block_contents)
+ return "___{}___".format(block_contents)
def convert(self):
output = self.str
diff --git a/converter/markdown/links.py b/converter/markdown/links.py
index 92b07d8f..ccf99efb 100644
--- a/converter/markdown/links.py
+++ b/converter/markdown/links.py
@@ -5,10 +5,16 @@ class Links(object):
def __init__(self, latex_str):
self.str = latex_str
+ def _clean_block(self, matchobj):
+ block_link = matchobj.group(1)
+ block_name = matchobj.group(3)
+ block_link = re.sub(r"[~]", "", block_link)
+ return f"[{block_name}]({block_link})"
+
def convert(self):
output = self.str
- output = re.sub(r"\\weblink{(.*?)}([\s%])?{(.*?)}", r"[\3](\1)", output, flags=re.DOTALL + re.VERBOSE)
+ output = re.sub(r"\\weblink{(.*?)}(.*?)?{(.*?)}", self._clean_block, output, flags=re.DOTALL + re.VERBOSE)
output = re.sub(r"\\weblink{(.*?)}", r"[\1](\1)", output, flags=re.MULTILINE)
output = re.sub(r"\\url{(.*?)}", r"[\1](\1)", output)
output = re.sub(r"\\href{(.*?)}{(\\[a-z]+)?\s?(.*?)}", r"[\1](\3)", output)
diff --git a/converter/markdown/lists.py b/converter/markdown/lists.py
index 7f89a540..7e6b06ee 100644
--- a/converter/markdown/lists.py
+++ b/converter/markdown/lists.py
@@ -40,31 +40,26 @@ def __init__(self, latex_str, caret_token):
def _format_list_contents(self, block_name, block_contents):
block_config = self._block_configuration[block_name]
-
list_heading = block_config["list_heading"]
output_str = ""
- for line in block_contents.lstrip().rstrip().split("\n"):
+ for line in block_contents.lstrip().rstrip().split("\\item"):
line = line.lstrip().rstrip()
line = line.replace("\\\\", "
")
-
- markdown_list_line = re.sub(r"\\item(\s+)?", list_heading, line)
if not line:
continue
- if "\\term" in line:
- if output_str:
- output_str = output_str.strip() + self._caret_token
- markdown_list_line = markdown_list_line.replace("\\term", list_heading)
- if "\\term{" in line:
- markdown_list_line = markdown_list_line.replace("{", "**", 1)
- markdown_list_line = markdown_list_line.replace("}", "**", 1)
- elif "\\item" in line:
- if output_str:
- output_str = output_str.strip() + self._caret_token
- if "\\item[" in line:
- markdown_list_line = markdown_list_line.replace("[", "**", 1)
- markdown_list_line = markdown_list_line.replace("]", "**", 1)
- output_str += markdown_list_line + ' '
+
+ cline = ""
+ for sub_str in line.split("\n"):
+ if not sub_str:
+ continue
+ cline += sub_str.strip() + " "
+
+ md_list_line = list_heading + cline.strip() + self._caret_token
+ if cline.startswith('['):
+ md_list_line = md_list_line.replace("[", "**", 1)
+ md_list_line = md_list_line.replace("]", "**", 1)
+ output_str += md_list_line
return output_str
def _format_block_name(self, block_name, block_title=None):
@@ -102,7 +97,7 @@ def _replace_block(self, matchobj):
header = self._format_block_name(block_name, block_title)
caret_token = self._caret_token
- output_str = f"{header}{caret_token}{caret_token}{formatted_contents}{caret_token}{caret_token}"
+ output_str = f"{header}{caret_token}{caret_token}{formatted_contents}{caret_token}"
if block_name == "description":
output_str = f"{header}{formatted_contents}{caret_token}{caret_token}"
return output_str
diff --git a/converter/markdown/match_elements.py b/converter/markdown/match_elements.py
new file mode 100644
index 00000000..f8b02a4d
--- /dev/null
+++ b/converter/markdown/match_elements.py
@@ -0,0 +1,21 @@
+def match_elements(text, n_matches):
+ level = 0
+ offset = 0
+ found_matches = 0
+ founds = []
+ last_index = 0
+ for index in range(0, len(text), 1):
+ ch = text[index]
+ last_index = index
+ if ch == '}':
+ level -= 1
+ if level == 0:
+ start_position = text.find("{", offset) + 1
+ offset += start_position
+ founds.append(text[start_position:index])
+ found_matches += 1
+ if found_matches == n_matches:
+ break
+ elif ch == '{':
+ level += 1
+ return founds, last_index
diff --git a/converter/markdown/newline.py b/converter/markdown/newline.py
index 466d4de0..7849ee84 100644
--- a/converter/markdown/newline.py
+++ b/converter/markdown/newline.py
@@ -9,6 +9,7 @@ def convert(self):
output = self.str
output = re.sub(r"^\\\\ ", "
", output, flags=re.MULTILINE)
output = re.sub(r"\\newline ", "
", output, flags=re.MULTILINE)
+ output = re.sub(r"\\newline<", "
<", output, flags=re.MULTILINE)
output = re.sub(r"\\newline$", "
", output, flags=re.MULTILINE)
return output
diff --git a/converter/markdown/picfigure.py b/converter/markdown/picfigure.py
index 3fbe26c6..42f8b7cc 100644
--- a/converter/markdown/picfigure.py
+++ b/converter/markdown/picfigure.py
@@ -1,10 +1,6 @@
-import re
-
+from converter.markdown.match_elements import match_elements
from converter.markdown.text_as_paragraph import TextAsParagraph
-picfigure_re = re.compile(r"""\\picfigure{(?P.*?)}{(?P.*?)}{(?P.*?)}""",
- flags=re.DOTALL + re.VERBOSE)
-
class PicFigure(TextAsParagraph):
def __init__(self, latex_str, caret_token, detect_asset_ext, figure_counter_offset, chapter_num, refs):
@@ -16,10 +12,8 @@ def __init__(self, latex_str, caret_token, detect_asset_ext, figure_counter_offs
self._chapter_num = chapter_num
self._refs = refs
- def make_block(self, matchobj):
- content = matchobj.group('content').strip()
- label = matchobj.group('refs').strip()
- image = matchobj.group('image').strip()
+ def make_block(self, image, label, content):
+ content = content.strip()
if '.' not in image:
ext = self._detect_asset_ext(image)
if ext:
@@ -41,4 +35,16 @@ def make_block(self, matchobj):
def convert(self):
self.images.clear()
pdfs = filter(lambda img: img.endswith('.pdf'), self.images)
- return picfigure_re.sub(self.make_block, self.str), list(pdfs), self._figure_counter
+ out = self.str
+ search_str = "\\picfigure"
+ pos = out.find(search_str)
+ while pos != -1:
+ matches, index = match_elements(out[pos + len(search_str):], 3)
+ start = out[0:pos]
+ end_pos = pos + len(search_str) + 1 + index
+ end = out[end_pos:]
+ out = start + self.make_block(
+ matches[0], matches[1], matches[2]
+ ) + end
+ pos = out.find(search_str, end_pos + 1)
+ return out, list(pdfs), self._figure_counter
diff --git a/converter/markdown/quotation.py b/converter/markdown/quotation.py
index 4baa00c5..177a54f7 100644
--- a/converter/markdown/quotation.py
+++ b/converter/markdown/quotation.py
@@ -1,5 +1,4 @@
-import re
-
+from converter.markdown.match_elements import match_elements
from converter.markdown.text_as_paragraph import TextAsParagraph
@@ -7,20 +6,17 @@ class Quotation(TextAsParagraph):
def __init__(self, latex_str, caret_token):
super().__init__(latex_str, caret_token)
- self._makequotation_re = re.compile(r"""\\makequotation{(?P.*?)}([\s]+)?
- {(?P.*?)}([ \t]+)?$""",
- flags=re.DOTALL + re.VERBOSE + re.MULTILINE)
-
- def _makequotation_block(self, matchobj):
- block_contents = matchobj.group('block_contents')
- block_author = matchobj.group('block_author')
- block_contents = self.to_paragraph(block_contents)
- block_contents = re.sub(r"\\\\", '
', block_contents)
- caret_token = self._caret_token
- return f'> {block_contents}{caret_token}>{caret_token}> __{block_author}__{caret_token}{caret_token}'
-
def convert(self):
- output = self.str
- output = self._makequotation_re.sub(self._makequotation_block, output)
-
- return output
+ out = self.str
+ search_str = "\\makequotation"
+ pos = out.find(search_str)
+ caret_token = self._caret_token
+ while pos != -1:
+ matches, index = match_elements(out[pos + len(search_str):], 2)
+ start = out[0:pos]
+ end_pos = pos + len(search_str) + 1 + index
+ end = out[end_pos:]
+ out = start + f'{caret_token}> {matches[0]}{caret_token}>' \
+ f'{caret_token}> __{matches[1]}__{caret_token}{caret_token}' + end
+ pos = out.find(search_str, end_pos + 1)
+ return out
diff --git a/converter/markdown/saas_specific.py b/converter/markdown/saas_specific.py
index bc85a5db..4d981d77 100644
--- a/converter/markdown/saas_specific.py
+++ b/converter/markdown/saas_specific.py
@@ -43,11 +43,19 @@ def convert(self):
output = re.sub(r"\\\"{(.*?)\}", r"\1", output)
output = re.sub(r"\\spaceship({\})?", r"<=>", output)
output = re.sub(r"\\thinspace({\})?", r" ", output)
- output = re.sub(r"\\tl({\})?", r"<", output)
- output = re.sub(r"\\tg({\})?", r">", output)
+ output = re.sub(r"\\tl({\})?", r"\<", output)
+ output = re.sub(r"\\tg({\})?", r"\>", output)
output = re.sub(r"\\ttil({\})?", r"~", output)
output = re.sub(r"\\textbar({\})?", r"|", output)
output = re.sub(r"\\hrule", "
", output)
+ output = re.sub(r"\\hfill", "", output)
+ output = re.sub(r"\\addtocounter{.*?}{.*?}", r"", output)
+ output = re.sub(r"\\small{", r"", output)
+ output = re.sub(r"\\cline{.*?}", "", output)
+ output = re.sub(r"vs.\\", "vs.", output)
+ output = re.sub(r"\\\\\*", "", output)
+ output = re.sub(r"\\textsection", "$", output)
+ output = re.sub(r"\\fillinblank{}", "_________", output)
output = self._saas_icons_re.sub(self._saas_icons_block, output)
output = self._saas_2icons_re.sub(self._saas_icons_block, output)
output = self._new_re.sub(self.make_block, output)
diff --git a/converter/markdown/sidebar.py b/converter/markdown/sidebar.py
index 8ed6b742..ffc419e4 100644
--- a/converter/markdown/sidebar.py
+++ b/converter/markdown/sidebar.py
@@ -11,7 +11,8 @@ def __init__(self, latex_str, detect_asset_ext, caret_token):
self._pdfs = []
- self._sidebargraphic_re = re.compile(r"""\\begin{sidebargraphic}(\[(?P.*?)])?{(?P.*?)}
+ self._sidebargraphic_re = re.compile(r"""\\begin{sidebargraphic}(\[(?P.*?)])?
+ {(?P.*?)}(.*?)
{(?P.*?)}
(?P.*?)
\\end{sidebargraphic}""", flags=re.DOTALL + re.VERBOSE)
@@ -32,7 +33,7 @@ def _sidebar_block(self, matchobj):
matches = re.match(r"(\[.*\])?({.*?\})(.*)?", head)
if matches:
title = matches.group(2).strip()
- title = get_text_in_brackets(title)
+ title = get_text_in_brackets(title).strip('*')
additional = matches.group(3).strip()
if additional:
diff --git a/converter/markdown/tablefigure.py b/converter/markdown/tablefigure.py
index 3cabfd8f..0832e6ae 100644
--- a/converter/markdown/tablefigure.py
+++ b/converter/markdown/tablefigure.py
@@ -63,6 +63,7 @@ def convert(self):
output = self.str
output = table_re.sub(self.make_block, output)
+ output = re.sub(r"\\protect\\index{.*?}%?", "", output)
for token in self._matches:
output = self.remove_matched_token(output, token)
diff --git a/converter/markdown/tabular.py b/converter/markdown/tabular.py
index d4b750f7..8efe7093 100644
--- a/converter/markdown/tabular.py
+++ b/converter/markdown/tabular.py
@@ -9,6 +9,9 @@ class Tabular(TextAsParagraph):
def __init__(self, latex_str, caret_token):
super().__init__(latex_str, caret_token)
+ self._graphics_re = re.compile(r"\\includegraphics(\[.*?]){(.*?)}",
+ flags=re.DOTALL + re.VERBOSE)
+
self._table_re = re.compile(r"""\\begin{(?Ptabular)}
(?P.*?)
\\end{(?P=block_name)}""",
@@ -28,7 +31,7 @@ def _format_table(self, matchobj):
size = get_text_in_brackets(sub_lines[0])
block_contents = '\n'.join(sub_lines[1:])
block_contents = block_contents.replace('\\hline', '')
-
+ block_contents = block_contents.replace('\\raggedright', '')
token = str(uuid.uuid4())
items = block_contents.split('\\\\')
@@ -43,7 +46,19 @@ def _format_table(self, matchobj):
continue
pos = 0
row = row.replace('\\&', token)
- for ind in range(0, len(table_size)):
+
+ row = re.sub(r"\\multicolumn{(.*?)}{(.*?)}{(.*?)}", r"\3", row, flags=re.DOTALL + re.VERBOSE)
+ row = re.sub(r"\\multirow{(.*?)}{(.*?)}\s?{(.*?)}", r"\3", row, flags=re.DOTALL + re.VERBOSE)
+
+ t_size = len(table_size)
+
+ match = self._graphics_re.search(row)
+ if match:
+ row = row.replace('\\icondir', 'icons')
+ row = self._graphics_re.sub(r"
", row)
+ t_size = len(row.split("&"))
+
+ for ind in range(0, t_size):
data = row.split('&')
col = self.safe_list_get(data, ind, '').strip()
col = col.replace('\n', '
')
diff --git a/converter/markdown/turingwinner.py b/converter/markdown/turingwinner.py
index a5c3eabe..250c2f55 100644
--- a/converter/markdown/turingwinner.py
+++ b/converter/markdown/turingwinner.py
@@ -1,3 +1,4 @@
+from converter.markdown.match_elements import match_elements
from converter.markdown.text_as_paragraph import TextAsParagraph
@@ -7,28 +8,6 @@ def __init__(self, latex_str, caret_token, detect_asset_ext):
self._pdfs = []
self._detect_asset_ext = detect_asset_ext
- def match_elements(self, text, n_matches):
- level = 0
- offset = 0
- found_matches = 0
- founds = []
- last_index = 0
- for index in range(0, len(text), 1):
- ch = text[index]
- last_index = index
- if ch == '}':
- level -= 1
- if level == 0:
- start_position = text.find("{", offset) + 1
- offset += start_position
- founds.append(text[start_position:index])
- found_matches += 1
- if found_matches == n_matches:
- break
- elif ch == '{':
- level += 1
- return founds, last_index
-
def make_content(self, image, block_name, block_contents, q_content, q_name):
if '.' not in image:
ext = self._detect_asset_ext(image)
@@ -46,7 +25,7 @@ def make_content(self, image, block_name, block_contents, q_content, q_name):
block_name = block_name.strip()
sidebar = f'{caret_token}{caret_token}|||xdiscipline{caret_token}**{block_name}** ' \
- f'{block_contents}{caret_token}{image_src}{caret_token}|||{caret_token}{caret_token}'
+ f'{block_contents}{caret_token}{image_src}{caret_token}|||{caret_token}{caret_token}'
quote = ''
if q_name and q_content:
@@ -60,7 +39,7 @@ def convert(self):
search_str = "\\turingwinner"
pos = out.find(search_str)
while pos != -1:
- matches, index = self.match_elements(out[pos + len(search_str):], 5)
+ matches, index = match_elements(out[pos + len(search_str):], 5)
start = out[0:pos]
end_pos = pos + len(search_str) + 1 + index
end = out[end_pos:]
diff --git a/converter/refs.py b/converter/refs.py
index daf33715..618290e5 100644
--- a/converter/refs.py
+++ b/converter/refs.py
@@ -64,6 +64,7 @@ def make_refs(toc, chapter_counter_from=1):
figs_counter = 0
is_figure = False
is_exercise = False
+ line_break = False
for item in toc:
if item.section_type == CHAPTER:
@@ -87,15 +88,30 @@ def make_refs(toc, chapter_counter_from=1):
is_exercise = True
elif line.startswith("\\end{exercise}"):
is_exercise = False
- elif "figure{" in line:
- result = re.match(r'\\(?Ppic|table|codefile)figure{(?P.*?)\}{(?P[.*?)\}', line)
+ elif "figure{" in line or "figure[" in line:
+ result = re.search(r'\\(?Ppic|table|codefile)figure(\[.*\])?{(?P.*?)}'
+ r'(%?\s*)?({(?P][.*?)})?', line)
if result:
ref = result.group('ref')
+ if ref:
+ figs_counter += 1
+ refs[ref] = {
+ 'pageref': item.section_name
+ }
+ refs[ref]["ref"] = f'{chapter_counter}.{figs_counter}'
+ else:
+ line_break = True
+ continue
+ elif line_break:
+ res = re.search(r'{(?P][fig:.*?)}', line)
+ if res:
+ ref = res.group('ref')
figs_counter += 1
refs[ref] = {
'pageref': item.section_name
}
refs[ref]["ref"] = f'{chapter_counter}.{figs_counter}'
+ line_break = False
elif "\\label{" in line:
start_pos = line.find("\\label{")
end_pos = line.find("}", start_pos)
diff --git a/converter/toc.py b/converter/toc.py
index 8854d180..4a79b0ce 100644
--- a/converter/toc.py
+++ b/converter/toc.py
@@ -38,6 +38,7 @@ def include_file(line):
def cleanup_name(name):
+ name = convert_name(name)
l_pos = name.find('{')
r_pos = name.find('}')
cut_pos = l_pos + 1
@@ -58,6 +59,14 @@ def cleanup_name(name):
return name
+def convert_name(name):
+ name = re.sub(r"\\js({\})?", "JavaScript", name)
+ name = re.sub("``", "“", name)
+ name = re.sub("''", "”", name)
+ name = re.sub(r"--", "-", name)
+ return name
+
+
def get_name(line):
level = 0
start = 0
diff --git a/tests/unit/cases/bc.md b/tests/unit/cases/bc.md
index b4b1ca2e..a8940168 100644
--- a/tests/unit/cases/bc.md
+++ b/tests/unit/cases/bc.md
@@ -1,11 +1,11 @@
**Summary of legacy code exploration**
-**Voucher**
+__Voucher__
-jQuery defines a global function **jQuery()** (aliased as **\$()**) that, when passed a CSS selector (examples of which we saw in Figure fig:css_cheat), returns all of the current page's DOM elements matching that selector. For example, **jQuery('#movies')** or **\$('#movies')** would return the single element whose ID is **movies**, if one exists on the page; **\$('h1.title')** would return all the **h1** elements whose CSS class is **title**. A more general version of this functionality is **.find(***selector***)**, which only searches the DOM subtree rooted at the target. To illustrate the distinction, **\$('p span')** finds *any* **span** element that is contained inside a **p** element, whereas if **elt** already refers to a *particular* **p** element, then **elt.find('span')** only finds **span** elements that are descendants of **elt**.
+jQuery defines a global function __jQuery()__ (aliased as __\$()__) that, when passed a CSS selector (examples of which we saw in Figure fig:css_cheat), returns all of the current page's DOM elements matching that selector. For example, __jQuery('#movies')__ or __\$('#movies')__ would return the single element whose ID is **movies**, if one exists on the page; __\$('h1.title')__ would return all the **h1** elements whose CSS class is **title**. A more general version of this functionality is __.find(__*selector*__)__, which only searches the DOM subtree rooted at the target. To illustrate the distinction, __\$('p span')__ finds *any* **span** element that is contained inside a **p** element, whereas if __elt__ already refers to a *particular* **p** element, then __elt.find('span')__ only finds **span** elements that are descendants of __elt__.
|||info
-The call **jQuery.noConflict()** “undefines” the **\$** alias, in case your app uses the browser's built-in **\$** (usually an alias for **document.-getElementById**) or loads another JavaScript library such as [Prototype](http://prototypejs.org) that also tries to define **\$**.
+The call __jQuery.noConflict()__ “undefines” the __\$__ alias, in case your app uses the browser's built-in __\$__ (usually an alias for __document.-getElementById__) or loads another JavaScript library such as [Prototype](http://prototypejs.org) that also tries to define __\$__.
-|||
\ No newline at end of file
+|||
diff --git a/tests/unit/cases/checkyourself_complex.md b/tests/unit/cases/checkyourself_complex.md
index 03f1d714..1f6ec0d4 100644
--- a/tests/unit/cases/checkyourself_complex.md
+++ b/tests/unit/cases/checkyourself_complex.md
@@ -1,8 +1,8 @@
|||challenge
- Suppose you mix **Enumerable** into a class **Foo** that does not
- provide the **each** method. What error will be raised when you
- call **Foo.new.map { |elt| puts elt }**?
- ]Check yourself
The **map** method in **Enumerable** will attempt to call **each** on its receiver, but since the new **Foo** object doesn't define **each**, Ruby will raise an Undefined Method error.
+ Suppose you mix __Enumerable__ into a class __Foo__ that does not
+ provide the __each__ method. What error will be raised when you
+ call __Foo.new.map { |elt| puts elt }__?
+ Check yourself
The __map__ method in __Enumerable__ will attempt to call __each__ on its receiver, but since the new __Foo__ object doesn't define __each__, Ruby will raise an Undefined Method error.
-|||
\ No newline at end of file
+|||
diff --git a/tests/unit/cases/chips.md b/tests/unit/cases/chips.md
index e69de29b..6147a572 100644
--- a/tests/unit/cases/chips.md
+++ b/tests/unit/cases/chips.md
@@ -0,0 +1,2 @@
+## ActiveRecord Basics
+{https://github.com/saasbook/hw-activerecord-practice} Although ActiveRecord is part of Rails, the ActiveRecord subsystem can be used outside of Rails apps. In this assignment, you will write various ActiveRecord operations to manipulate a database of (fictional) customers for whom we store names, email addresses, and birthdays. In a typical Rails app, such queries usually appear in the model code, but working on these simple examples will help familiarize you with ActiveRecord's basic features before writing such code yourself
\ No newline at end of file
diff --git a/tests/unit/cases/chips.tex b/tests/unit/cases/chips.tex
index 0ab16a2e..102c194a 100644
--- a/tests/unit/cases/chips.tex
+++ b/tests/unit/cases/chips.tex
@@ -1,16 +1,10 @@
-\begin{chips}{Regular Expressions}
-
- \w{Regular expressions}, sometimes abbreviated \emph{regexps} or
- \emph{regexes}, are sequences of characters that define a search
- pattern. A regex can be applied to a string to determine whether
- the string contains those patterns. Given the preponderance of
- string manipulation in interactive and Web applications, all modern
- programming languages support regexes either within the language or
- as part of a library. This exercise will help you refresh your
- skills at constructing regular expressions.
-
- (Other skill ``refreshers'' needed? Some general questions about
- encapsulation and inheritance, before moving on to concrete examples
- in Ruby?)
-
+\begin{chips}{ActiveRecord Basics}{https://github.com/saasbook/hw-activerecord-practice}
+ Although ActiveRecord is part of Rails, the ActiveRecord subsystem
+ can be used outside of Rails apps.
+ In this assignment, you will write various ActiveRecord operations
+ to manipulate a database of (fictional) customers for whom we store
+ names, email addresses, and birthdays. In a typical Rails app, such queries
+ usually appear in the model code, but working on these simple examples
+ will help familiarize you with ActiveRecord's basic features before
+ writing such code yourself
\end{chips}
\ No newline at end of file
diff --git a/tests/unit/cases/codefigure.md b/tests/unit/cases/codefigure.md
index d447c93f..3080c256 100644
--- a/tests/unit/cases/codefigure.md
+++ b/tests/unit/cases/codefigure.md
@@ -1,5 +1,5 @@
**Figure 1.1**
-**source:ch_javascript/code/json_example.js**
+**source: ch_javascript/code/json_example.js**
```code
file content
```
@@ -7,16 +7,16 @@ file content
**Figure 1.2**
-**source:ch_ruby_rails/code/class_example.rb**
+**source: ch_ruby_rails/code/class_example.rb**
```code
file content
```
- A simple class definition in Ruby showing that explicit getter and setter methods are the only way to access instance variables from outside a class, and that Ruby provides shortcuts (lines 19--20) that avoid having to define every accessor method explicitly. Rather than distinguish “private” vs.\ “public” instance and class variables, one simply provides public accessor methods (read-only, write-only, or read/write) for state that should be publicly visible.
+ A simple class definition in Ruby showing that explicit getter and setter methods are the only way to access instance variables from outside a class, and that Ruby provides shortcuts (lines 19--20) that avoid having to define every accessor method explicitly. Rather than distinguish “private” vs. “public” instance and class variables, one simply provides public accessor methods (read-only, write-only, or read/write) for state that should be publicly visible.
**Figure 1.3**
-**source:ch_ruby_rails/code/class_example.rb**
+**source: ch_ruby_rails/code/class_example.rb**
```code
file content
```
- A simple class definition in Ruby showing that explicit getter and setter methods are the only way to access instance variables from outside a class, and that Ruby provides shortcuts (lines 19--20) that avoid having to define every accessor method explicitly. Rather than distinguish “private” vs.\ “public” instance and class variables, one simply provides public accessor methods (read-only, write-only, or read/write) for state that should be publicly visible.
\ No newline at end of file
+ A simple class definition in Ruby showing that explicit getter and setter methods are the only way to access instance variables from outside a class, and that Ruby provides shortcuts (lines 19--20) that avoid having to define every accessor method explicitly. Rather than distinguish “private” vs. “public” instance and class variables, one simply provides public accessor methods (read-only, write-only, or read/write) for state that should be publicly visible.
diff --git a/tests/unit/cases/concepts.md b/tests/unit/cases/concepts.md
index 41839a1b..70e334b5 100644
--- a/tests/unit/cases/concepts.md
+++ b/tests/unit/cases/concepts.md
@@ -1,10 +1,10 @@
## Concepts
-_**JavaScript**_ is a dynamic, interpreted scripting language built into modern browsers. This chapter describes its main features, including some that we recommend avoiding because they represent questionable design choices, and how it extends the types of content and applications that can be delivered as SaaS.
+___JavaScript___ is a dynamic, interpreted scripting language built into modern browsers. This chapter describes its main features, including some that we recommend avoiding because they represent questionable design choices, and how it extends the types of content and applications that can be delivered as SaaS.
-* A browser represents a web page as a data structure called the _**Document Object Model**_ (DOM). JavaScript code running in the browser can inspect and modify this data structure, causing the browser to redraw the modified page elements.
-* When a user interacts with the browser (for example, by typing, clicking, or moving the mouse) or the browser makes progress in an interaction with a server, the browser generates an _**event**_ indicating what happened. Your JavaScript code can take app-specific actions to modify the DOM when such events occur.
-* Using _**AJAX**_, or Asynchronous JavaScript And XML, JavaScript code can make HTTP requests to a Web server *without* triggering a page reload. The information in the response can then be used to modify page elements in place, giving a richer and often more responsive user experience than traditional Web pages. Rails partials and controller actions can be readily used to handle AJAX interactions.
-* Just as we use the highly-productive Rails framework (Chapter chap:rails_intro) and RSpec TDD tool (Chapter chap:tdd) for server-side SaaS code, here we use the highly-productive _**jQuery**_ framework and [Jasmine](http://pivotal.github.com/jasmine) TDD tool to develop client-side code.
-* We follow the best practice of “graceful degradation,” also referred to as “progressive enhancement”: legacy browsers lacking JavaScript support will still provide a good user experience, while JavaScript-enabled browsers will provide an even better experience.
\ No newline at end of file
+* A browser represents a web page as a data structure called the ___Document Object Model___ (DOM). JavaScript code running in the browser can inspect and modify this data structure, causing the browser to redraw the modified page elements.
+* When a user interacts with the browser (for example, by typing, clicking, or moving the mouse) or the browser makes progress in an interaction with a server, the browser generates an ___event___ indicating what happened. Your JavaScript code can take app-specific actions to modify the DOM when such events occur.
+* Using ___AJAX___, or Asynchronous JavaScript And XML, JavaScript code can make HTTP requests to a Web server *without* triggering a page reload. The information in the response can then be used to modify page elements in place, giving a richer and often more responsive user experience than traditional Web pages. Rails partials and controller actions can be readily used to handle AJAX interactions.
+* Just as we use the highly-productive Rails framework (Chapter chap:rails_intro) and RSpec TDD tool (Chapter chap:tdd) for server-side SaaS code, here we use the highly-productive ___jQuery___ framework and [Jasmine](http://pivotal.github.com/jasmine) TDD tool to develop client-side code.
+* We follow the best practice of “graceful degradation,” also referred to as “progressive enhancement”: legacy browsers lacking JavaScript support will still provide a good user experience, while JavaScript-enabled browsers will provide an even better experience.
diff --git a/tests/unit/cases/html.md b/tests/unit/cases/html.md
index 9024bff5..b56a0475 100644
--- a/tests/unit/cases/html.md
+++ b/tests/unit/cases/html.md
@@ -4,21 +4,21 @@ In contrast to a native app, which is designed to render a particular user inter
Indeed, modern practice suggests that even when creating a user-facing SaaS app designed to be used via a browser, we should design the app as a collection of resources accessible via RESTful APIs, but then provide a Web browser-based user interface “on top of” those API calls.
-If the Web browser is the universal client, _**HTML**_, the HyperText Markup Language, is the universal language. A _**markup language**_ combines text with markup (annotations about the text) in a way that makes it easy to syntactically distinguish the two.
+If the Web browser is the universal client, ___HTML___, the HyperText Markup Language, is the universal language. A ___markup language___ combines text with markup (annotations about the text) in a way that makes it easy to syntactically distinguish the two.
-HTML consists of a hierarchy of nested elements, each of which consists of an opening tag such as ****, a content part (in some cases), and a closing tag such as **
**. Most opening tags can also have attributes, as in **$<$a href="http://..."$>$**. Some tags that don't have a content part are self-closing, such as **
** for a line break that clears both left and right margins.
+HTML consists of a hierarchy of nested elements, each of which consists of an opening tag such as **\**, a content part (in some cases), and a closing tag such as **\
**. Most opening tags can also have attributes, as in **$<$a href="http://..."$>$**. Some tags that don't have a content part are self-closing, such as **\
** for a line break that clears both left and right margins.
|||info
-The use of angle brackets for tags comes from _**SGML**_ (Standard Generalized Markup Language), a codified standardization of IBM's Generalized Markup Language, developed in the 1960s for encoding computer-readable project documents.
+The use of angle brackets for tags comes from ___SGML___ (Standard Generalized Markup Language), a codified standardization of IBM's Generalized Markup Language, developed in the 1960s for encoding computer-readable project documents.
|||
-There is an unfortunate and confusing mess of terminology surrounding the [lineage of HTML](http://www.w3.org/TR/html5/introduction.html#history-1). HTML 5 includes features of both its predecessors (HTML versions 1 through 4) and XHTML (eXtended HyperText Markup Language), which is a subset of _**XML**_, an eXtensible Markup Language that can be used both to represent data and to describe other markup languages. Indeed, XML is a common data representation for exchanging information *between* two services in a Service-Oriented Architecture, as we'll see in Chapter chap:tdd when we extend RottenPotatoes to retrieve movie information from a separate movie database service. The differences among the variants of XHTML and HTML are difficult to keep straight, and not all browsers support all versions. Unless otherwise noted, from now on when we say HTML we mean HTML 5, and we will try to avoid using features that aren't widely supported.
+There is an unfortunate and confusing mess of terminology surrounding the [lineage of HTML](http://www.w3.org/TR/html5/introduction.html#history-1). HTML 5 includes features of both its predecessors (HTML versions 1 through 4) and XHTML (eXtended HyperText Markup Language), which is a subset of ___XML___, an eXtensible Markup Language that can be used both to represent data and to describe other markup languages. Indeed, XML is a common data representation for exchanging information *between* two services in a Service-Oriented Architecture, as we'll see in Chapter chap:tdd when we extend RottenPotatoes to retrieve movie information from a separate movie database service. The differences among the variants of XHTML and HTML are difficult to keep straight, and not all browsers support all versions. Unless otherwise noted, from now on when we say HTML we mean HTML 5, and we will try to avoid using features that aren't widely supported.
Of particular interest are the HTML tag attributes **id** and **class**, because they figure heavily into connecting the HTML structure of a page with its visual appearance. The following screencast illustrates the use of Firefox's Web Developer toolbar to quickly identify the ID's and Classes of HTML elements on a page.
@@ -30,7 +30,7 @@ Of particular interest are the HTML tag attributes **id** and **class**, because
-CSS uses _**selector notations**_ such as **div#***name* to indicate a **div** element whose **id** is *name* and **div.***name* to indicate a **div** element with class *name*. Only one element in an HTML document can have a given **id**, whereas many elements (even of different tag types) can share the same **class**. All three aspects of an element---its tag type, its **id** (if it has one), and its **class** attributes (if it has any)---can be used to identify an element as a candidate for visual formatting.
+CSS uses ___selector notations___ such as **div#***name* to indicate a **div** element whose **id** is *name* and **div.***name* to indicate a **div** element with class *name*. Only one element in an HTML document can have a given **id**, whereas many elements (even of different tag types) can share the same **class**. All three aspects of an element---its tag type, its **id** (if it has one), and its **class** attributes (if it has any)---can be used to identify an element as a candidate for visual formatting.
@@ -43,7 +43,7 @@ For an extreme example of how much can be done with CSS, visit the [CSS Zen Gard
|||
-As the next screencast shows, the _**CSS**_ (_**Cascading Style Sheets**_) standard allows us to associate visual “styling” instructions with HTML elements by using the elements' classes and IDs. The screencast covers only a few basic CSS constructs, which are summarized in Figure fig:css_cheat. The Resources section at the end of the chapter lists sites and books that describe CSS in great detail, including how to use CSS for aligning content on a page, something designers used to do manually with HTML tables.
+As the next screencast shows, the ___CSS___ (___Cascading Style Sheets___) standard allows us to associate visual “styling” instructions with HTML elements by using the elements' classes and IDs. The screencast covers only a few basic CSS constructs, which are summarized in Figure fig:css_cheat. The Resources section at the end of the chapter lists sites and books that describe CSS in great detail, including how to use CSS for aligning content on a page, something designers used to do manually with HTML tables.
@@ -54,7 +54,7 @@ As the next screencast shows, the _**CSS**_ (_**Cascading Style Sheets**_) stand
-There are four basic mechanisms by which a selector in a CSS file can match an HTML element: by tag name, by class, by ID, and by hierarchy. If multiple selectors match a given element, the rules for which properties to apply are complex, so most designers try to avoid such ambiguities by keeping their CSS simple. A useful way to see the “bones” of a page is to select \Sf{CSS>-Disable Styles>-All Styles} from the Firefox Web Developer toolbar; most developer-friendly browsers offer a “developer mode” featuring similar behaviors. Disabling styles will display the page with all CSS formatting turned off, showing the extent to which CSS can be used to separate visual appearance from logical structure.
+There are four basic mechanisms by which a selector in a CSS file can match an HTML element: by tag name, by class, by ID, and by hierarchy. If multiple selectors match a given element, the rules for which properties to apply are complex, so most designers try to avoid such ambiguities by keeping their CSS simple. A useful way to see the “bones” of a page is to select \Sf{CSS\>-Disable Styles\>-All Styles} from the Firefox Web Developer toolbar; most developer-friendly browsers offer a “developer mode” featuring similar behaviors. Disabling styles will display the page with all CSS formatting turned off, showing the extent to which CSS can be used to separate visual appearance from logical structure.
@@ -82,7 +82,8 @@ JavaScript - more sophisticated behaviors such as animations, collapsing menus,
Rather than delving deeply into the aesthetics of graphic design, our goal for you as a well-rounded full-stack developer is that you should know how to provide well-structured pages with proper element nesting and clean CSS class tags, for two reasons. First, with a good front-end framework, just doing this will be enough to provide an AURA site (aesthetic, usable, responsive, accessible). Second, a clean site layout and classing allows designers to refine, customize, or work separately on the site's visual appearance.
-There are 2 principles to using front-end frameworks successfully in this way: semantic styling and grid layout. Semantic styling means First, think of your page's visual elements not in terms of their visual characteristics ("This message should appear in a red box with bold text") but in terms of their function ("This message signals an error", "This text is the page title", "This list of items is a menu of navigation options"). A good front-end framework names its styles according to the function they enable an element to fulfill, rather than according to their visual appearance.## SPA or MPA?
+There are 2 principles to using front-end frameworks successfully in this way: semantic styling and grid layout. Semantic styling means First, think of your page's visual elements not in terms of their visual characteristics ("This message should appear in a red box with bold text") but in terms of their function ("This message signals an error", "This text is the page title", "This list of items is a menu of navigation options"). A good front-end framework names its styles according to the function they enable an element to fulfill, rather than according to their visual appearance.
+## SPA or MPA?
SPA vs MPA: Are you building something that's more like a website (transactional? lots of different possible screens? user navigates large amounts of data in a typical session? multi-screen workflows?) or more like a desktop app (few screens? continuous interaction vs transactional, eg something like Pivotal Tracker? user navigates modest amounts of data in a typical session? short workflows or interactions typically limited to 1 screen?) If it's primarily a website, use HTML5 + jQuery where needed. If primarily an app, may be better off using a framework. [Need a checklist like "when to use agile" for "when to build a SPA vs MPA"]. Examples of popular SPAs: Gmail, Google Docs, Pivotal Tracker. Popular MPAs: IMDb, Amazon.com, Google Search. *MPA vs SPA is primarily a user experience question, not a technical one!*
@@ -91,9 +92,9 @@ SPA vs MPA: Are you building something that's more like a website (transactional
**Summary**
-* An _**HTML**_ (HyperText Markup Language) document consists of a hierarchically nested collection of elements. Each element begins with a _**tag**_ in that may have optional _**attributes**_. Some elements enclose content.
-* A _**selector**_ is an expression that identifies one or more HTML elements in a document by using a combination of the element name (such as **body**), element **id** (an element attribute that must be unique on a page), and element **class** (an attribute that need not be unique on a page).
-* _**Cascading Style Sheets**_ (CSS) is a stylesheet language describing visual attributes of elements on a Web page. A stylesheet associates sets of visual properties with selectors. A special **link** element inside the **head** element of an HTML document associates a stylesheet with that document.
+* An ___HTML___ (HyperText Markup Language) document consists of a hierarchically nested collection of elements. Each element begins with a ___tag___ in \ that may have optional ___attributes___. Some elements enclose content.
+* A ___selector___ is an expression that identifies one or more HTML elements in a document by using a combination of the element name (such as **body**), element **id** (an element attribute that must be unique on a page), and element **class** (an attribute that need not be unique on a page).
+* ___Cascading Style Sheets___ (CSS) is a stylesheet language describing visual attributes of elements on a Web page. A stylesheet associates sets of visual properties with selectors. A special **link** element inside the **head** element of an HTML document associates a stylesheet with that document.
* The “developer tools” in each browser, such as the Firefox Web Developer toolbar, are invaluable in peeking under the hood to examine both the structure of a page and its stylesheets.
@@ -133,7 +134,7 @@ ch_arch/code/htmlexercise.html
Write down a CSS selector that will select *only* the word
*Mondays* for styling.
- Check yourself
Three possibilities, from most specific to least specific, are: **#i span**, **p.x span**, and **.x span**. Other selectors are possible but redundant or over-constrained; for example, **p#i span** and **p#i.x span** are redundant with respect to this HTML snippet since at most one element can have the ID **i**.
+ Check yourself
Three possibilities, from most specific to least specific, are: __#i span__, __p.x span__, and __.x span__. Other selectors are possible but redundant or over-constrained; for example, __p#i span__ and __p#i.x span__ are redundant with respect to this HTML snippet since at most one element can have the ID __i__.
|||
@@ -141,9 +142,9 @@ ch_arch/code/htmlexercise.html
|||challenge
- In Self-Check ex:css1, why are **span**
- and **p span** *not* valid answers?
- Check yourself
Both of those selector also match *Tuesdays*, which is a **span** inside a **p**.
+ In Self-Check ex:css1, why are __span__
+ and __p span__ *not* valid answers?
+ Check yourself
Both of those selector also match *Tuesdays*, which is a __span__ inside a __p__.
|||
@@ -156,4 +157,4 @@ ch_arch/code/htmlexercise.html
Check yourself
Within the **HEAD** element of the HTML or HTML document, include a **LINK** element with at least the following three attributes: **REL="STYLESHEET"**, **TYPE="text/css"**, and **HREF="*uri*"**, where ***uri*** is the full or partial URI of the stylesheet. That is, the stylesheet must be accessible as a resource named by a URI.
-|||
\ No newline at end of file
+|||
diff --git a/tests/unit/cases/index.md b/tests/unit/cases/index.md
index 8f8470ed..87fa14b5 100644
--- a/tests/unit/cases/index.md
+++ b/tests/unit/cases/index.md
@@ -1,2 +1,2 @@
## Versions of Agile
-There is not just a single Agile lifecycle. We are following _**Extreme Programming**_ (XP), which includes one- to two-week iterations, behavior driven design (see Chapter chap:bdd), test-driven development (see Chapter chap:tdd), and pair programming (see Section sec:Pair). Another popular version is _**Scrum**_ (see Section sec:Scrum), where self-organizing teams use two- to four-week iterations called _**sprints**_, and then regroup to plan the next sprint. A key feature is daily standup meetings to identify and overcome obstacles. While there are multiple roles in the scrum team, the norm is to rotate the roles over time. The _**Kanban**_ approach is derived from Toyota's just-in-time manufacturing process, which in this case treats software development as a pipeline. Here the team members have fixed roles, and the goal is to balance the number of team members so that there are no bottlenecks with tasks stacking up waiting for processing. One common feature is a wall of cards that to illustrate the state of all tasks in the pipeline. There are also hybrid lifecycles that try to combine the best of two worlds. For example, _**ScrumBan**_ uses the daily meetings and sprints of Scrum but replaces the planning phase with the more dynamic pipeline control of the wall of cards from Kanban.
\ No newline at end of file
+There is not just a single Agile lifecycle. We are following ___Extreme Programming___ (XP), which includes one- to two-week iterations, behavior driven design (see Chapter chap:bdd), test-driven development (see Chapter chap:tdd), and pair programming (see Section sec:Pair). Another popular version is ___Scrum___ (see Section sec:Scrum), where self-organizing teams use two- to four-week iterations called ___sprints___, and then regroup to plan the next sprint. A key feature is daily standup meetings to identify and overcome obstacles. While there are multiple roles in the scrum team, the norm is to rotate the roles over time. The ___Kanban___ approach is derived from Toyota's just-in-time manufacturing process, which in this case treats software development as a pipeline. Here the team members have fixed roles, and the goal is to balance the number of team members so that there are no bottlenecks with tasks stacking up waiting for processing. One common feature is a wall of cards that to illustrate the state of all tasks in the pipeline. There are also hybrid lifecycles that try to combine the best of two worlds. For example, ___ScrumBan___ uses the daily meetings and sprints of Scrum but replaces the planning phase with the more dynamic pipeline control of the wall of cards from Kanban.
diff --git a/tests/unit/cases/italic_bold.md b/tests/unit/cases/italic_bold.md
index 15c2ff1d..e4570298 100644
--- a/tests/unit/cases/italic_bold.md
+++ b/tests/unit/cases/italic_bold.md
@@ -1,3 +1,3 @@
|||info
-**Big Design Up Front** , abbreviated _**BDUF**_, is a name some use for software processes like Waterfall, Spiral, and RUP that depend on extensive planning and documentation. They are also known variously as _**heavyweight**_, _**plan-driven**_, _**disciplined**_, or _**structured**_ processes.
-|||
\ No newline at end of file
+**Big Design Up Front** , abbreviated ___BDUF___, is a name some use for software processes like Waterfall, Spiral, and RUP that depend on extensive planning and documentation. They are also known variously as ___heavyweight___, ___plan-driven___, ___disciplined___, or ___structured___ processes.
+|||
diff --git a/tests/unit/cases/makequotation.md b/tests/unit/cases/makequotation.md
index 2904370f..5d46d3f3 100644
--- a/tests/unit/cases/makequotation.md
+++ b/tests/unit/cases/makequotation.md
@@ -4,30 +4,35 @@
+
> I'd be far more likely to prefer graduates of this program than any other I've seen.
>
> __Brad Green, Engineering Manager, Google Inc.__
+
> Many congratulations... Very proud of including the SPOC in our redeveloped Bachelors' in Software Engineering degree... The book is the best I've bought, within minutes of seeing it at ICSE.
>
> __Ali Babar, University of Adelaide__
+
> A number of software engineers at C3 Energy consistently report that this book and its companion online course enabled them to rapidly attain proficiency in SaaS development. I recommend this unique book and course to anyone who wants to develop or improve their SaaS programming skills.
>
> __Thomas M. Siebel, CEO, C3 Energy, and founder and former CEO, Siebel Systems (the leading Customer Relationship Management software company)__
+
> We have gone from teaching about 60 graduate students per year in traditional software engineering to 160 per year using ESaaS. We have similarly seen a large increase in undergraduate students. The local community of non-profits has come to depend on us for software development.
>
> __Prof. Hank Walker, Texas A\&M University__
+
> I love this course so much. It's such an amazing advancement in [Software Engineering] education, and I've been so proud to offer it for the past 2 years. It is a big learning curve to new instructors and students, but I truly believe it's worth it. My students seem to agree.
>
> __Prof. Kristen Walcott-Justice, University of Colorado---Colorado Springs__
@@ -35,6 +40,7 @@
+
> A wide and deep coverage of all you need to get started in the SaaS business.
>
> __Vicente Cuellar, Chief Executive Officer, Wave Crafters, Inc.__
@@ -42,30 +48,35 @@
+
> The book filled a gap in my knowledge about cloud computing and the lectures were easy to follow. Perhaps the most exciting part was to write a cloud application, upload, and deploy it to Heroku.
>
> __Peter Englmaier, University of Zurich, Switzerland__
+
> An excellent kickstart into Ruby, Rails and test driven approaches. The fundamentals have been covered with great depth and experience, it's the perfect introduction to modern web development. It should be a requisite for new engineers.
>
> __Stuart Corbishley, Clue Technologies/CloudSeed, South Africa.__
-> An excellent book that will have you up and running building SaaS apps progressively in a few short days. The screencasts and the GitHub Gists are invaluable. A very practical approach to Agile software development.
+
+> An excellent book that will have you up and running building SaaS apps progressively in a few short days. The screencasts and the GitHub Gists are invaluable. A very practical approach to Agile software development.
>
> __Prof. Rakhi Saxena, Assistant Professor, Delhi University, India__
+
> The authors have accomplished a very welcome juxtaposition of theory and practice for any modern beginning to advanced Software Engineering course ... I have used the Beta Edition of this book very successfully in my advanced undergraduate software engineering course, where it beautifully complements both my lectures and the team project.
>
> __Prof. Ingolf Krueger, Professor, University of California at San Diego__
+
> A really good introduction book to practical Agile development. All you need is gathered in one book with lots of practical examples.
>
> __Dmitrij Savicev, Sungard Front Arena, Sweden__
\ No newline at end of file
diff --git a/tests/unit/cases/nested_list.md b/tests/unit/cases/nested_list.md
index 6a1f83fc..101dc46e 100644
--- a/tests/unit/cases/nested_list.md
+++ b/tests/unit/cases/nested_list.md
@@ -10,7 +10,7 @@ ch_bdd/code/vaguefeature.rb
ch_bdd/code/unmeasurablefeature.rb
```
Only the second case can be tested to see if the system fulfills the requirement.
-* *Achievable.* Ideally, you implement the user story in one Agile iteration. If you are getting less than one story per iteration, then they are too big and you need to subdivide these stories into smaller ones. As mentioned above, the tool _**Pivotal Tracker**_ measures _**Velocity**_, which is the rate of completing stories of varying difficulty.
+* *Achievable.* Ideally, you implement the user story in one Agile iteration. If you are getting less than one story per iteration, then they are too big and you need to subdivide these stories into smaller ones. As mentioned above, the tool ___Pivotal Tracker___ measures ___Velocity___, which is the rate of completing stories of varying difficulty.
* *Relevant.* A user story must have business value to one or more stakeholders. To drill down to the real business value, one technique is to keep asking “Why.” Using as an example a ticket-selling app for a regional theater, suppose the proposal is to add a Facebook linking feature. Here are the “Five Whys” in action with their recursive questions and answers:
1. Why add the Facebook feature? As box office manager, I think more people will go with friends and enjoy the show more.
@@ -20,4 +20,4 @@ ch_bdd/code/unmeasurablefeature.rb
1. Why does it matter that theater is in business next year? If not, I have no job.
(We're pretty sure the business value is now apparent to at least one stakeholder!)
-* *Timeboxed.* Timeboxing means that you stop developing a story once you've exceeded the time budget. Either you give up, divide the user story into smaller ones, or reschedule what is left according to a new estimate. If dividing looks like it won't help, then you go back to the customers to find the highest value part of the story that you can do quickly. The reason for a time budget per user story is that it is extremely easy to underestimate the length of a software project. Without careful accounting of each iteration, the whole project could be late, and thus fail. Learning to budget a software project is a critical skill, and exceeding a story budget and then refactoring it is one way to acquire that skill.
\ No newline at end of file
+* *Timeboxed.* Timeboxing means that you stop developing a story once you've exceeded the time budget. Either you give up, divide the user story into smaller ones, or reschedule what is left according to a new estimate. If dividing looks like it won't help, then you go back to the customers to find the highest value part of the story that you can do quickly. The reason for a time budget per user story is that it is extremely easy to underestimate the length of a software project. Without careful accounting of each iteration, the whole project could be late, and thus fail. Learning to budget a software project is a critical skill, and exceeding a story budget and then refactoring it is one way to acquire that skill.
diff --git a/tests/unit/cases/saas.md b/tests/unit/cases/saas.md
index 7be5b08c..43594973 100644
--- a/tests/unit/cases/saas.md
+++ b/tests/unit/cases/saas.md
@@ -1,7 +1,7 @@
### Software as a Service
-The power of SOA combined with the power of the Internet led to a special case of SOA with its own name: _**Software as a Service (SaaS)**_. It delivers software and data as a service over the Internet, usually via a thin program such as a browser that runs on local client devices instead as an application binary that must be installed and runs wholly on that device. Examples that many use every day include searching, social networking, and watching videos. The advantages for the customer and for the software developer are widely touted:
+The power of SOA combined with the power of the Internet led to a special case of SOA with its own name: ___Software as a Service (SaaS)___. It delivers software and data as a service over the Internet, usually via a thin program such as a browser that runs on local client devices instead as an application binary that must be installed and runs wholly on that device. Examples that many use every day include searching, social networking, and watching videos. The advantages for the customer and for the software developer are widely touted:
@@ -34,7 +34,7 @@ Unsurprisingly, given the popularity of SaaS, Figure fig:SaaS_frameworks lists t
Ruby is typical of modern scripting languages in including automatic memory management and dynamic typing. By including important advances in programming languages, Ruby goes beyond languages like Perl in supporting multiple programming paradigms such as object oriented and functional programming.
-Useful additional features that help productivity via reuse include _**mix-ins**_, which collect related behaviors and make it easy to add them to many different classes, and _**metaprogramming**_, which allows Ruby programs to synthesize code at runtime. Reuse is also enhanced with Ruby's support for _**closures**_ via _**blocks**_ and _**yield**_. Chapter chap:ruby_intro is a short description of Ruby for those who already know Java, and Chapter chap:rails_intro introduces Rails.
+Useful additional features that help productivity via reuse include ___mix-ins___, which collect related behaviors and make it easy to add them to many different classes, and ___metaprogramming___, which allows Ruby programs to synthesize code at runtime. Reuse is also enhanced with Ruby's support for ___closures___ via ___blocks___ and ___yield___. Chapter chap:ruby_intro is a short description of Ruby for those who already know Java, and Chapter chap:rails_intro introduces Rails.
In addition to our view of Rails being technically superior for Agile and SaaS, Ruby and Rails are widely used. For example, Ruby routinely appears among top 10 most popular programming languages. A well-known SaaS app associated with Rails is Twitter, which began as a Rails app in 2006 and grew from 20,000 tweets per day in 2007 to 200,000,000 in 2011, during which time other frameworks replaced various parts of it.
@@ -44,7 +44,7 @@ Note that frequent upgrades of SaaS---due to only having a single copy of the so
---
-**Summary:** _**Software as a Service (SaaS)**_ is attractive to both customers and providers because the universal client (the Web browser) makes it easier for customers to use the service and the single version of the software at a centralized site makes it easier for the provider to deliver and improve the service. Given the ability and desire to frequently upgrade SaaS, the Agile software development process is popular for SaaS, and so there are many frameworks to support Agile and SaaS. This book uses Ruby on Rails.
+**Summary:** ___Software as a Service (SaaS)___ is attractive to both customers and providers because the universal client (the Web browser) makes it easier for customers to use the service and the single version of the software at a centralized site makes it easier for the provider to deliver and improve the service. Given the ability and desire to frequently upgrade SaaS, the Agile software development process is popular for SaaS, and so there are many frameworks to support Agile and SaaS. This book uses Ruby on Rails.
---
@@ -77,4 +77,4 @@ Which of the examples of Google SaaS apps---Search, Maps, News, Gmail, Calendar
|||
-Given the case for SaaS and the understanding that it relies on a Service Oriented Architecture, we are ready to see the underlying hardware that makes SaaS possible.
\ No newline at end of file
+Given the case for SaaS and the understanding that it relies on a Service Oriented Architecture, we are ready to see the underlying hardware that makes SaaS possible.
diff --git a/tests/unit/cases/saas1.md b/tests/unit/cases/saas1.md
index 775315ed..79ff865a 100644
--- a/tests/unit/cases/saas1.md
+++ b/tests/unit/cases/saas1.md
@@ -2,24 +2,27 @@
-> If builders built buildings the way programmers wrote programs, then the first woodpecker that came along would destroy civilization.
+
+> If builders built buildings the way programmers wrote programs, then the first woodpecker that came along would destroy civilization.
>
> __Gerald Weinberg, *Weinberg's Second Law*__
-The general unpredictability of software development in the late 1960s, along with the software disasters similar to ACA, led to the study of how high-quality software could be developed on a predictable schedule and budget. Drawing the analogy to other engineering fields, the term _**software engineering**_ was coined (Naur69). The goal was to discover methods to build software that were as predictable in quality, cost, and time as those used to build bridges in civil engineering.
+The general unpredictability of software development in the late 1960s, along with the software disasters similar to ACA, led to the study of how high-quality software could be developed on a predictable schedule and budget. Drawing the analogy to other engineering fields, the term ___software engineering___ was coined (Naur69). The goal was to discover methods to build software that were as predictable in quality, cost, and time as those used to build bridges in civil engineering.
One thrust of software engineering was to bring an engineering discipline to what was often unplanned software development. Before starting to code, come up with a plan for the project, including extensive, detailed documentation of all phases of that plan. Progress is then measured against the plan. Changes to the project must be reflected in the documentation and possibly to the plan.
The goal of all these “Plan-and-Document” software development processes is to improve predictability via extensive documentation, which must be changed whenever the goals change. Here is how textbook authors put it (Lethbridge02,Braude01):
+
> Documentation should be written at all stages of development, and includes requirements, designs, user manuals, instructions for testers and project plans.
>
> __Timothy Lethbridge and Robert Laganiere, 2002__
+
> Documentation is the lifeblood of software engineering.
>
> __Eric Braude, 2001__
@@ -53,7 +56,7 @@ An early version of this Plan-and-Document software development process was deve
Given that the earlier you find an error the cheaper it is to fix, the philosophy of this process is to complete a phase before going on to the next one, thereby removing as many errors as early as possible. Getting the early phases right could also prevent unnecessary work downstream. As this process could take years, the extensive documentation helps to ensure that important information is not lost if a person leaves the project and that new people can get up to speed quickly when they join the project.
-Because it flows from the top down to completion, this process is called the _**Waterfall**_ software development process or Waterfall software development _**lifecycle**_. Understandably, given the complexity of each stage in the Waterfall lifecycle, product releases are major events toward which engineers worked feverishly and which are accompanied by much fanfare.
+Because it flows from the top down to completion, this process is called the ___Waterfall___ software development process or Waterfall software development ___lifecycle___. Understandably, given the complexity of each stage in the Waterfall lifecycle, product releases are major events toward which engineers worked feverishly and which are accompanied by much fanfare.
|||info
@@ -66,6 +69,7 @@ In the Waterfall lifecycle, the long life of software is acknowledged by a maint
The Waterfall model can work well with well-specified tasks like NASA space flights, but it runs into trouble when customers change their minds about what they want. A Turing Award winner captures this observation:
+
> Plan to throw one [implementation] away; you will, anyhow.
>
> __Fred Brooks, Jr.__
@@ -74,7 +78,7 @@ The Waterfall model can work well with well-specified tasks like NASA space flig
That is, it's easier for customers to understand what they want once they see a prototype and for engineers to understand how to build it better once they've done it the first time.
-This observation led to a software development lifecycle developed in the 1980s that combines prototypes with the Waterfall model (boehm86). The idea is to iterate through a sequence of four phases, with each iteration resulting in a prototype that is a refinement of the previous version. Figure fig:spiral illustrates this model of development across the four phases, which gives this lifecycle its name: the _**Spiral model**_. The phases are
+This observation led to a software development lifecycle developed in the 1980s that combines prototypes with the Waterfall model (boehm86). The idea is to iterate through a sequence of four phases, with each iteration resulting in a prototype that is a refinement of the previous version. Figure fig:spiral illustrates this model of development across the four phases, which gives this lifecycle its name: the ___Spiral model___. The phases are
1. Determine objectives and constraints of this iteration
@@ -93,11 +97,11 @@ Rather than document all the requirements at the beginning, as in the Waterfall
|||info
-**Big Design Up Front** , abbreviated _**BDUF**_, is a name some use for software processes like Waterfall, Spiral, and RUP that depend on extensive planning and documentation. They are also known variously as _**heavyweight**_, _**plan-driven**_, _**disciplined**_, or _**structured**_ processes.
+**Big Design Up Front** , abbreviated ___BDUF___, is a name some use for software processes like Waterfall, Spiral, and RUP that depend on extensive planning and documentation. They are also known variously as ___heavyweight___, ___plan-driven___, ___disciplined___, or ___structured___ processes.
|||
-Given the importance of software development, many variations of Plan-and-Document methodologies were proposed beyond these two. A recent one is called the _**Rational Unified Process**_ (_**RUP**_) (Kruchten03), which combines features of both Waterfall and Spiral lifecycles as well standards for diagrams and documentation. We'll use RUP as a representative of the latest thinking in Plan-and-Document lifecycles. Unlike Waterfall and Spiral, it is more closely allied to business issues than to technical issues.
+Given the importance of software development, many variations of Plan-and-Document methodologies were proposed beyond these two. A recent one is called the ___Rational Unified Process___ (___RUP___) (Kruchten03), which combines features of both Waterfall and Spiral lifecycles as well standards for diagrams and documentation. We'll use RUP as a representative of the latest thinking in Plan-and-Document lifecycles. Unlike Waterfall and Spiral, it is more closely allied to business issues than to technical issues.
Like Waterfall and Spiral, RUP has phases:
@@ -136,7 +140,7 @@ An unfortunate downside to teaching a Plan-and-Document approach is that student
---
-**Summary:** The basic *activities* of software engineering are the same in all the software development process or _**lifecycles**_, but their interaction over time relative to product releases differs among the models. The Waterfall lifecycle is characterized by much of the design being done in advance of coding, completing each phase before going on to the next one. The Spiral lifecycle iterates through all the development phases to produce prototypes, but like Waterfall, the customers may only get involved every 6 to 24 months. The more recent Rational Unified Process lifecycle includes phases, iterations, and prototypes, while identifying the people skills needed for the project. All rely on careful planning and thorough documentation, and all measure progress against a plan.
+**Summary:** The basic *activities* of software engineering are the same in all the software development process or ___lifecycles___, but their interaction over time relative to product releases differs among the models. The Waterfall lifecycle is characterized by much of the design being done in advance of coding, completing each phase before going on to the next one. The Spiral lifecycle iterates through all the development phases to produce prototypes, but like Waterfall, the customers may only get involved every 6 to 24 months. The more recent Rational Unified Process lifecycle includes phases, iterations, and prototypes, while identifying the people skills needed for the project. All rely on careful planning and thorough documentation, and all measure progress against a plan.
---
@@ -157,8 +161,9 @@ An unfortunate downside to teaching a Plan-and-Document approach is that student
Check yourself
Waterfall phases separate planning (requirements and architectural design) from implementation. Testing the product before release is next, followed by a separate operations phase. The Spiral phases are aimed at an iteration: set the goals for an iteration; explore alternatives; develop and verify the prototype for this iteration; and plan the next iteration. RUP phases are tied closer to business objectives: inception makes business case and sets schedule and budget; elaboration works with customers to build an initial prototype; construction builds and test the first version; and transition deploys the product.
|||
+
## SEI Capability Maturity Model (CMM)
-The Software Engineering Institute at Carnegie Mellon University proposed the _**Capability Maturity Model**_ (CMM) (Paulk05) to evaluate organizations' software-development processes based on Plan-and-Document methodologies. The idea is that by modeling the software development process, an organization can improve them. SEI studies observed five levels of software practice:
+The Software Engineering Institute at Carnegie Mellon University proposed the ___Capability Maturity Model___ (CMM) (Paulk05) to evaluate organizations' software-development processes based on Plan-and-Document methodologies. The idea is that by modeling the software development process, an organization can improve them. SEI studies observed five levels of software practice:
1. Initial or Chaotic---undocumented/*ad hoc*/unstable software development.
@@ -168,4 +173,4 @@ The Software Engineering Institute at Carnegie Mellon University proposed the _*
1. Optimizing---Deliberate process optimization improvements as part of management process.
-CMM implicitly encourages an organization to move up the CMM levels. While not proposed as a software development methodology, many consider it one. For example, (Nawrocki02) compares CMM Level 2 to the Agile software methodology (see next section).
\ No newline at end of file
+CMM implicitly encourages an organization to move up the CMM levels. While not proposed as a software development methodology, many consider it one. For example, (Nawrocki02) compares CMM Level 2 to the Agile software methodology (see next section).
diff --git a/tests/unit/cases/saas1.tex b/tests/unit/cases/saas1.tex
index 4d435b1f..87e94954 100644
--- a/tests/unit/cases/saas1.tex
+++ b/tests/unit/cases/saas1.tex
@@ -4,7 +4,7 @@ \section{Software Development Processes: Plan and Document}
\index{Plan-and-Document!overview|textbf}%
\index{Software as a Service (SaaS)!plan-and-document|textbf}%
-\makequotation{If builders built buildings the way programmers wrote programs, then the first woodpecker that came along would destroy civilization.\\}{Gerald Weinberg, \emph{Weinberg's Second Law}}
+\makequotation{If builders built buildings the way programmers wrote programs, then the first woodpecker that came along would destroy civilization.}{Gerald Weinberg, \emph{Weinberg's Second Law}}
The general unpredictability of software development in the late 1960s,
along with the software disasters similar to ACA, led to the study of
diff --git a/tests/unit/cases/saas2.md b/tests/unit/cases/saas2.md
index 5b3f7017..2ae31a29 100644
--- a/tests/unit/cases/saas2.md
+++ b/tests/unit/cases/saas2.md
@@ -3,7 +3,7 @@ Thus, we concentrate on Agile in the six software development chapters in Part I
While we now see how to build some software successfully, not all projects are small. We next show how to design software to enable composition into services like Amazon.com.
---
-**Summary:** In contrast to the Plan-and-Document lifecycles, the Agile lifecycle works with customers to continuously add features to working prototypes until the customer is satisfied, allowing customers to change what they want as the project develops. Documentation is primarily through user stories and test cases, and it does not measure progress against a predefined plan. Progress is gauged instead by recording _**velocity**_, which essentially is the rate that a project completes features.
+**Summary:** In contrast to the Plan-and-Document lifecycles, the Agile lifecycle works with customers to continuously add features to working prototypes until the customer is satisfied, allowing customers to change what they want as the project develops. Documentation is primarily through user stories and test cases, and it does not measure progress against a predefined plan. Progress is gauged instead by recording ___velocity___, which essentially is the rate that a project completes features.
---
@@ -15,12 +15,14 @@ While we now see how to build some software successfully, not all projects are s
Check yourself
False: Both build working but incomplete prototypes that the customer helps evaluate. The difference is that customers are involved every two weeks in Agile versus up to two years in with Spiral.
|||
+
## Versions of Agile
-There is not just a single Agile lifecycle. We are following _**Extreme Programming**_ (XP), which includes one- to two-week iterations, behavior driven design (see Chapter chap:bdd), test-driven development (see Chapter chap:tdd), and pair programming (see Section sec:Pair). Another popular version is _**Scrum**_ (see Section sec:Scrum), where self-organizing teams use two- to four-week iterations called _**sprints**_, and then regroup to plan the next sprint. A key feature is daily standup meetings to identify and overcome obstacles. While there are multiple roles in the scrum team, the norm is to rotate the roles over time. The _**Kanban**_ approach is derived from Toyota's just-in-time manufacturing process, which in this case treats software development as a pipeline. Here the team members have fixed roles, and the goal is to balance the number of team members so that there are no bottlenecks with tasks stacking up waiting for processing. One common feature is a wall of cards that to illustrate the state of all tasks in the pipeline. There are also hybrid lifecycles that try to combine the best of two worlds. For example, _**ScrumBan**_ uses the daily meetings and sprints of Scrum but replaces the planning phase with the more dynamic pipeline control of the wall of cards from Kanban.## Reforming Acquisition Regulations
+There is not just a single Agile lifecycle. We are following ___Extreme Programming___ (XP), which includes one- to two-week iterations, behavior driven design (see Chapter chap:bdd), test-driven development (see Chapter chap:tdd), and pair programming (see Section sec:Pair). Another popular version is ___Scrum___ (see Section sec:Scrum), where self-organizing teams use two- to four-week iterations called ___sprints___, and then regroup to plan the next sprint. A key feature is daily standup meetings to identify and overcome obstacles. While there are multiple roles in the scrum team, the norm is to rotate the roles over time. The ___Kanban___ approach is derived from Toyota's just-in-time manufacturing process, which in this case treats software development as a pipeline. Here the team members have fixed roles, and the goal is to balance the number of team members so that there are no bottlenecks with tasks stacking up waiting for processing. One common feature is a wall of cards that to illustrate the state of all tasks in the pipeline. There are also hybrid lifecycles that try to combine the best of two worlds. For example, ___ScrumBan___ uses the daily meetings and sprints of Scrum but replaces the planning phase with the more dynamic pipeline control of the wall of cards from Kanban.
+## Reforming Acquisition Regulations
Long before the ACA website, there were calls to reform software acquisition, as in this US National Academies study of the Department of Defense (DOD):
“The DOD is hampered by a culture and acquisition-related practices that favor large programs, high-level oversight, and a very deliberate, serial approach to development and testing (the waterfall model). Programs that are expected to deliver complete, nearly perfect solutions and that take years to develop are the norm in the DOD... These approaches run counter to Agile acquisition practices in which the product is the primary focus, end users are engaged early and often, the oversight of incremental product development is delegated to the lowest practical level, and the program management team has the flexibility to adjust the content of the increments in order to meet delivery schedules... Agile approaches have allowed their adopters to outstrip established industrial giants that were beset with ponderous, process-bound, industrial-age management structures. Agile approaches have succeeded because their adopters recognized the issues that contribute to risks in an IT program and changed their management structures and processes to mitigate the risks.”
(national2010Achieving)
-Even President Obama belatedly recognized the difficulties of software acquisition. On November 14, 2013, he said in a speech: “... when I do some Monday morning quarterbacking on myself, one of the things that I do recognize is since I know how we purchase technology in the federal government is cumbersome, complicated and outdated ... it's part of the reason why, chronically, federal IT programs are over budget, behind schedule... since I [now] know that the federal government has not been good at this stuff in the past, two years ago as we were thinking about this... we might have done more to make sure that we were breaking the mold on how we were going to be setting this up.”
\ No newline at end of file
+Even President Obama belatedly recognized the difficulties of software acquisition. On November 14, 2013, he said in a speech: “... when I do some Monday morning quarterbacking on myself, one of the things that I do recognize is since I know how we purchase technology in the federal government is cumbersome, complicated and outdated ... it's part of the reason why, chronically, federal IT programs are over budget, behind schedule... since I [now] know that the federal government has not been good at this stuff in the past, two years ago as we were thinking about this... we might have done more to make sure that we were breaking the mold on how we were going to be setting this up.”
diff --git a/tests/unit/cases/saas3.md b/tests/unit/cases/saas3.md
index 8d3e5f62..e47f23de 100644
--- a/tests/unit/cases/saas3.md
+++ b/tests/unit/cases/saas3.md
@@ -1,4 +1,4 @@
-> To me programming is more than an important practical art. It is also a gigantic undertaking in the foundations of knowledge.
+> To me programming is more than an important practical art. It is also a gigantic undertaking in the foundations of knowledge.
>
> __Grace Murray Hopper__
diff --git a/tests/unit/cases/saas3.tex b/tests/unit/cases/saas3.tex
index 985d0d6e..021b5655 100644
--- a/tests/unit/cases/saas3.tex
+++ b/tests/unit/cases/saas3.tex
@@ -1,5 +1,5 @@
\makequotation{
-To me programming is more than an important practical art. It is also a gigantic undertaking in the foundations of knowledge.\\}{Grace Murray Hopper}
+To me programming is more than an important practical art. It is also a gigantic undertaking in the foundations of knowledge.}{Grace Murray Hopper}
\index{Software as a Service (SaaS)!beautiful \textit{vs.} legacy code|textbf}%
\begin{sidebargraphic}[-1in]{ch_backwards_forwards/figs/Hopper}{Grace Murray Hopper}
diff --git a/tests/unit/cases/screencast.md b/tests/unit/cases/screencast.md
index a660c6fc..a8965fae 100644
--- a/tests/unit/cases/screencast.md
+++ b/tests/unit/cases/screencast.md
@@ -5,7 +5,7 @@
-CSS uses _**selector notations**_ such as **div#***name* to indicate a **div** element whose **id** is *name* and **div.***name* to indicate a **div** element with class *name*. Only one element in an HTML document can have a given **id**, whereas many elements (even of different tag types) can share the same **class**. All three aspects of an element---its tag type, its **id** (if it has one), and its **class** attributes (if it has any)---can be used to identify an element as a candidate for visual formatting.
+CSS uses ___selector notations___ such as **div#***name* to indicate a **div** element whose **id** is *name* and **div.***name* to indicate a **div** element with class *name*. Only one element in an HTML document can have a given **id**, whereas many elements (even of different tag types) can share the same **class**. All three aspects of an element---its tag type, its **id** (if it has one), and its **class** attributes (if it has any)---can be used to identify an element as a candidate for visual formatting.
@@ -17,7 +17,7 @@ CSS uses _**selector notations**_ such as **div#***name* to indicate a **div** e
-In a Haml template, lines beginning with **%** expand into the corresponding HTML opening tag, with no closing tag needed since Haml uses indentation to determine structure. Ruby-like hashes following a tag become HTML attributes. Lines \mbox{**--beginning with a dash**} are executed as Ruby code with the result discarded, and lines \mbox{**=beginning with an equals sign**} are executed as Ruby code with the result interpolated into the HTML output.
+In a Haml template, lines beginning with **%** expand into the corresponding HTML opening tag, with no closing tag needed since Haml uses indentation to determine structure. Ruby-like hashes following a tag become HTML attributes. Lines \mbox{__--beginning with a dash__} are executed as Ruby code with the result discarded, and lines \mbox{__=beginning with an equals sign__} are executed as Ruby code with the result interpolated into the HTML output.
@@ -29,6 +29,6 @@ In a Haml template, lines beginning with **%** expand into the corresponding HTM
-CSS uses _**selector notations**_ such as **div#***name* to indicate a **div** element whose **id** is *name* and **div.***name* to indicate a **div** element with class *name*. Only one element in an HTML document can have a given **id**, whereas many elements (even of different tag types) can share the same **class**. All three aspects of an element---its tag type, its **id** (if it has one), and its **class** attributes (if it has any)---can be used to identify an element as a candidate for visual formatting.
+CSS uses ___selector notations___ such as **div#***name* to indicate a **div** element whose **id** is *name* and **div.***name* to indicate a **div** element with class *name*. Only one element in an HTML document can have a given **id**, whereas many elements (even of different tag types) can share the same **class**. All three aspects of an element---its tag type, its **id** (if it has one), and its **class** attributes (if it has any)---can be used to identify an element as a candidate for visual formatting.
-
\ No newline at end of file
+
diff --git a/tests/unit/cases/sidebar.md b/tests/unit/cases/sidebar.md
index 21e4598a..0c1a0de8 100644
--- a/tests/unit/cases/sidebar.md
+++ b/tests/unit/cases/sidebar.md
@@ -15,6 +15,6 @@
|||info
-The use of angle brackets for tags comes from _**SGML**_ (Standard Generalized Markup Language), a codified standardization of IBM's Generalized Markup Language, developed in the 1960s for encoding computer-readable project documents.
+The use of angle brackets for tags comes from ___SGML___ (Standard Generalized Markup Language), a codified standardization of IBM's Generalized Markup Language, developed in the 1960s for encoding computer-readable project documents.
-|||
\ No newline at end of file
+|||
diff --git a/tests/unit/cases/sidebargraphic.md b/tests/unit/cases/sidebargraphic.md
index 4845031e..fb73c2b1 100644
--- a/tests/unit/cases/sidebargraphic.md
+++ b/tests/unit/cases/sidebargraphic.md
@@ -1,5 +1,5 @@
|||xdiscipline
-**Alan Perlis** (1922--1990) was the first recipient of the Turing Award (1966), conferred for his influence on advanced programming languages and compilers. In 1958 he helped design ALGOL, which has influenced virtually every imperative programming language including C and Java. To avoid FORTRAN's syntactic and semantic problems, ALGOL was the first language described in terms of a formal grammar, the eponymous _**Backus-Naur form**_ (named for Turing award winner Jim Backus and his colleague Peter Naur).
+**Alan Perlis** (1922--1990) was the first recipient of the Turing Award (1966), conferred for his influence on advanced programming languages and compilers. In 1958 he helped design ALGOL, which has influenced virtually every imperative programming language including C and Java. To avoid FORTRAN's syntactic and semantic problems, ALGOL was the first language described in terms of a formal grammar, the eponymous ___Backus-Naur form___ (named for Turing award winner Jim Backus and his colleague Peter Naur).
|||
@@ -9,4 +9,4 @@
-**David Patterson** recently retired from a 40-year career as a Professor of Computer Science at UC Berkeley. In the
\ No newline at end of file
+**David Patterson** recently retired from a 40-year career as a Professor of Computer Science at UC Berkeley. In the
diff --git a/tests/unit/cases/tablefigure.md b/tests/unit/cases/tablefigure.md
index ebcfd1a1..04de2267 100644
--- a/tests/unit/cases/tablefigure.md
+++ b/tests/unit/cases/tablefigure.md
@@ -1,8 +1,8 @@
-We can therefore say that the expression **3+2** results in calling **Fixnum#+** on the receiver **3**.
+We can therefore say that the expression __3+2__ results in calling __Fixnum#+__ on the receiver __3__.
file content content
-**Figure 1.1: The first column is Ruby's syntactic sugar for common operations, the second column shows the explicit method call, and the third column shows how to perform the same method call using Ruby's **send**, which accepts either a string or (more idiomatically) a symbol for the method name.
**
+**Figure 1.1: The first column is Ruby's syntactic sugar for common operations, the second column shows the explicit method call, and the third column shows how to perform the same method call using Ruby's __send__, which accepts either a string or (more idiomatically) a symbol for the method name.
**
file content content
@@ -12,4 +12,4 @@ file content content
file content content
-**Figure 1.3: Some common Ruby methods on collections. For those that expect a block, the “Block” column shows the number of arguments expected by the block; if blank, the method doesn't expect a block. For example, a call to **sort**, whose block expects 2 arguments, might look like: **c.sort { |a,b| a $<=>$ b }**. These methods all return a new object rather than modifying the receiver, but some methods also have a *destructive* variant ending in **!**, for example **sort!**, that modify their argument in place (and also return the new value). Use destructive methods with extreme care, if at all.
**
\ No newline at end of file
+**Figure 1.3: Some common Ruby methods on collections. For those that expect a block, the “Block” column shows the number of arguments expected by the block; if blank, the method doesn't expect a block. For example, a call to __sort__, whose block expects 2 arguments, might look like: __c.sort { |a,b| a $<=>$ b }__. These methods all return a new object rather than modifying the receiver, but some methods also have a *destructive* variant ending in __!__, for example __sort!__, that modify their argument in place (and also return the new value). Use destructive methods with extreme care, if at all.
**
diff --git a/tests/unit/cases/turingwinner.md b/tests/unit/cases/turingwinner.md
index 4d3c0059..4717439b 100644
--- a/tests/unit/cases/turingwinner.md
+++ b/tests/unit/cases/turingwinner.md
@@ -1,7 +1,7 @@
Hello content
|||xdiscipline
-**Alan Perlis (1922--1990)** was the first recipient of the Turing Award (1966), conferred for his influence on advanced programming languages and compilers. In 1958 he helped design ALGOL, which has influenced virtually every imperative programming language including C and Java. To avoid FORTRAN's syntactic and semantic problems, ALGOL was the first language described in terms of a formal grammar, the eponymous _**Backus-Naur form**_ (named for Turing award winner Jim Backus and his colleague Peter Naur).
+**Alan Perlis (1922--1990)** was the first recipient of the Turing Award (1966), conferred for his influence on advanced programming languages and compilers. In 1958 he helped design ALGOL, which has influenced virtually every imperative programming language including C and Java. To avoid FORTRAN's syntactic and semantic problems, ALGOL was the first language described in terms of a formal grammar, the eponymous ___Backus-Naur form___ (named for Turing award winner Jim Backus and his colleague Peter Naur).
|||
@@ -21,4 +21,4 @@ Hello content
-End content2
\ No newline at end of file
+End content2
diff --git a/tests/unit/cases/w.md b/tests/unit/cases/w.md
index 7a3fe05b..67bfaee0 100644
--- a/tests/unit/cases/w.md
+++ b/tests/unit/cases/w.md
@@ -1,5 +1,5 @@
-Many SaaS apps, including those based on Rails, follow the _**Model-View-Controller**_ (MVC) architectural pattern. In MVC, Models deal with the app's _**resources**_ such as users or blog posts, Views present information to the user via the browser, and Controllers map the user's browser actions to application code.
+Many SaaS apps, including those based on Rails, follow the ___Model-View-Controller___ (MVC) architectural pattern. In MVC, Models deal with the app's ___resources___ such as users or blog posts, Views present information to the user via the browser, and Controllers map the user's browser actions to application code.
-* Using _**AJAX**_, or Asynchronous JavaScript And XML, JavaScript code can make HTTP requests to a Web server *without* triggering a page reload. The information in the response can then be used to modify page elements in place, giving a richer and often more responsive user experience than traditional Web pages. Rails partials and controller actions can be readily used to handle AJAX interactions.
\ No newline at end of file
+* Using ___AJAX___, or Asynchronous JavaScript And XML, JavaScript code can make HTTP requests to a Web server *without* triggering a page reload. The information in the response can then be used to modify page elements in place, giving a richer and often more responsive user experience than traditional Web pages. Rails partials and controller actions can be readily used to handle AJAX interactions.
diff --git a/tests/unit/cases/x.md b/tests/unit/cases/x.md
index 21f44b97..a5aef04d 100644
--- a/tests/unit/cases/x.md
+++ b/tests/unit/cases/x.md
@@ -1 +1 @@
-The _**SMART**_ acronym captures the desirable features of a good user story: Specific, Measurable, Achievable, Relevant, and Timeboxed.
\ No newline at end of file
+The ___SMART___ acronym captures the desirable features of a good user story: Specific, Measurable, Achievable, Relevant, and Timeboxed.
diff --git a/tests/unit/test_render_markdown.py b/tests/unit/test_render_markdown.py
index 7a498d1b..3709898c 100644
--- a/tests/unit/test_render_markdown.py
+++ b/tests/unit/test_render_markdown.py
@@ -34,6 +34,9 @@ def make_converter(path, refs, chapter_num, load_workspace_file):
class TestSuite(unittest.TestCase):
+
+ maxDiff = None
+
def write_md(self, name, refs={}, chapter_num=1, load_workspace_file=lambda _: _):
path = "cases/{}".format(name)
converter = make_converter(path, refs, chapter_num, load_workspace_file)
From f681f9d39cad4c86773a194ebafbc90e04ad1495 Mon Sep 17 00:00:00 2001
From: achetporov
Date: Thu, 7 May 2020 11:55:21 +0300
Subject: [PATCH 07/39] Some more fixes (#41)
* clearing extra spaces in turingwinner
* changed panels config
* fixed bib_content parse
* fixed extra characters in quotation
---
converter/markdown/cite.py | 2 +-
converter/markdown/quotation.py | 3 +++
converter/markdown/saas_specific.py | 2 +-
converter/markdown/turingwinner.py | 1 +
converter/toc.py | 2 +-
tests/unit/toc_cases/toc_simple.yml | 2 +-
6 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/converter/markdown/cite.py b/converter/markdown/cite.py
index 5da62866..301cae24 100644
--- a/converter/markdown/cite.py
+++ b/converter/markdown/cite.py
@@ -34,7 +34,7 @@ def __init__(self, latex_str, load_workspace_file):
def make_bib_content(line):
bib_entry = {}
- for item in line.split(',\n'):
+ for item in re.split(r',\s*\n', line):
item = item.strip()
sub_items = item.split('=', 1)
if len(sub_items) > 1:
diff --git a/converter/markdown/quotation.py b/converter/markdown/quotation.py
index 177a54f7..7f1383a4 100644
--- a/converter/markdown/quotation.py
+++ b/converter/markdown/quotation.py
@@ -1,3 +1,5 @@
+import re
+
from converter.markdown.match_elements import match_elements
from converter.markdown.text_as_paragraph import TextAsParagraph
@@ -16,6 +18,7 @@ def convert(self):
start = out[0:pos]
end_pos = pos + len(search_str) + 1 + index
end = out[end_pos:]
+ matches[0] = re.sub(r"\\\\", "
", matches[0])
out = start + f'{caret_token}> {matches[0]}{caret_token}>' \
f'{caret_token}> __{matches[1]}__{caret_token}{caret_token}' + end
pos = out.find(search_str, end_pos + 1)
diff --git a/converter/markdown/saas_specific.py b/converter/markdown/saas_specific.py
index 4d981d77..4348a5b8 100644
--- a/converter/markdown/saas_specific.py
+++ b/converter/markdown/saas_specific.py
@@ -53,7 +53,7 @@ def convert(self):
output = re.sub(r"\\small{", r"", output)
output = re.sub(r"\\cline{.*?}", "", output)
output = re.sub(r"vs.\\", "vs.", output)
- output = re.sub(r"\\\\\*", "", output)
+ output = re.sub(r"\.\\\\\*\}", ".}", output)
output = re.sub(r"\\textsection", "$", output)
output = re.sub(r"\\fillinblank{}", "_________", output)
output = self._saas_icons_re.sub(self._saas_icons_block, output)
diff --git a/converter/markdown/turingwinner.py b/converter/markdown/turingwinner.py
index 250c2f55..5d68ae9e 100644
--- a/converter/markdown/turingwinner.py
+++ b/converter/markdown/turingwinner.py
@@ -28,6 +28,7 @@ def make_content(self, image, block_name, block_contents, q_content, q_name):
f'{block_contents}{caret_token}{image_src}{caret_token}|||{caret_token}{caret_token}'
quote = ''
+ q_name = q_name.strip()
if q_name and q_content:
quote = f'{caret_token}> {q_content}{caret_token}>' \
f'{caret_token}> __{q_name}__{caret_token}{caret_token}'
diff --git a/converter/toc.py b/converter/toc.py
index 4a79b0ce..01a9a1ac 100644
--- a/converter/toc.py
+++ b/converter/toc.py
@@ -248,7 +248,7 @@ def print_to_yaml(structure, tex, bookdown=False):
yaml_structure += " - name: \"{}\"\n type: {}\n".format(item.section_name, item.section_type)
if first_item:
first_item = False
- yaml_structure += " configuration:\n layout: 2-panels\n"
+ yaml_structure += " configuration:\n layout: 1-panels\n"
return yaml_structure
diff --git a/tests/unit/toc_cases/toc_simple.yml b/tests/unit/toc_cases/toc_simple.yml
index f8ea3b6a..4fb3b9d7 100644
--- a/tests/unit/toc_cases/toc_simple.yml
+++ b/tests/unit/toc_cases/toc_simple.yml
@@ -7,7 +7,7 @@ sections:
- name: "Computer programming"
type: chapter
configuration:
- layout: 2-panels
+ layout: 1-panels
- name: "What is a computer?"
type: section
- name: "What is programming?"
From 9dea71e5c4186200db376f437c4a12f337795531 Mon Sep 17 00:00:00 2001
From: achetporov
Date: Wed, 13 May 2020 11:19:35 +0300
Subject: [PATCH 08/39] fixed parse chapters with line break
---
converter/toc.py | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/converter/toc.py b/converter/toc.py
index 01a9a1ac..810e8744 100644
--- a/converter/toc.py
+++ b/converter/toc.py
@@ -54,7 +54,7 @@ def cleanup_name(name):
l_pos = l_pos - 1
else:
cut_pos += 1
- res = name[0:l_pos] + name[cut_pos:r_pos] + name[r_pos+1:]
+ res = name[0:l_pos] + name[cut_pos:r_pos] + name[r_pos + 1:]
return cleanup_name(res)
return name
@@ -119,14 +119,27 @@ def process_toc_lines(lines, tex_folder, parent_folder):
toc = []
line_pos = 1
item_lines = []
+ chapter_line = ''
+ chapter_line_break = False
for line in lines:
line = line.rstrip('\r\n')
+ if chapter_line_break:
+ if line.endswith('}'):
+ line = chapter_line + line
+ chapter_line_break = False
+ else:
+ chapter_line += line
+ continue
if is_toc(line):
if toc:
if item_lines:
toc[len(toc) - 1].lines = item_lines
item_lines = []
section_type = CHAPTER if is_chapter(line) else SECTION
+ if section_type == CHAPTER and not line.endswith('}'):
+ chapter_line = line
+ chapter_line_break = True
+ continue
section_name, additional_content_in_name = get_name(line)
toc.append(SectionItem(section_name=section_name, section_type=section_type, line_pos=line_pos))
if is_section_file(line):
From 5b694f8dfcb738bdb1a3d2398a0e425fb37b9786 Mon Sep 17 00:00:00 2001
From: achetporov
Date: Wed, 13 May 2020 16:33:00 +0300
Subject: [PATCH 09/39] fixed extra line breaks in self-check question
---
converter/markdown/checkyourself.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/converter/markdown/checkyourself.py b/converter/markdown/checkyourself.py
index d54b9811..a6a036ec 100644
--- a/converter/markdown/checkyourself.py
+++ b/converter/markdown/checkyourself.py
@@ -21,6 +21,7 @@ def make_answer_block(self, matchobj):
def make_block(self, matchobj):
block_contents = matchobj.group('block_contents')
+ block_contents = block_contents.replace("\n", " ")
answer_str = answer_re.sub(self.make_answer_block, block_contents)
caret_token = self._caret_token
return f'{caret_token}|||challenge{caret_token}{answer_str}{caret_token}|||{caret_token}'
From 8926e617d06df0a8dc5126d8cebcd3d17428bc3d Mon Sep 17 00:00:00 2001
From: achetporov
Date: Fri, 15 May 2020 10:11:22 +0300
Subject: [PATCH 10/39] fix checkyourself
---
converter/markdown/checkyourself.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/converter/markdown/checkyourself.py b/converter/markdown/checkyourself.py
index a6a036ec..d54b9811 100644
--- a/converter/markdown/checkyourself.py
+++ b/converter/markdown/checkyourself.py
@@ -21,7 +21,6 @@ def make_answer_block(self, matchobj):
def make_block(self, matchobj):
block_contents = matchobj.group('block_contents')
- block_contents = block_contents.replace("\n", " ")
answer_str = answer_re.sub(self.make_answer_block, block_contents)
caret_token = self._caret_token
return f'{caret_token}|||challenge{caret_token}{answer_str}{caret_token}|||{caret_token}'
From cafd4b97cd5d6298b56957b5c6624050e2e399c5 Mon Sep 17 00:00:00 2001
From: achetporov
Date: Fri, 15 May 2020 12:40:43 +0300
Subject: [PATCH 11/39] 11432 tabularline (#42)
fixed tabulbarline
---
converter/markdown/ignore.py | 5 +++++
converter/markdown/tabular.py | 22 +++++++++++++++++++++-
converter/toc.py | 2 +-
3 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/converter/markdown/ignore.py b/converter/markdown/ignore.py
index dc50035e..e211d977 100644
--- a/converter/markdown/ignore.py
+++ b/converter/markdown/ignore.py
@@ -50,6 +50,11 @@ def convert(self):
output = re.sub(r"\\end{minipage}", "", output)
output = re.sub(r"\\begin{textfigure}", "", output)
output = re.sub(r"\\end{textfigure}", "", output)
+ output = re.sub(r"\\newcommand{.*?}{.*?}", "", output)
+ output = re.sub(r"^\\ifhtmloutput.*?(\\begin{tabular}.*?)\\fi", r"\1", output,
+ flags=re.DOTALL + re.MULTILINE)
+ output = re.sub(r"^\\ifhtmloutput%.*?(\\end{tabular}).*?\\fi", r"\1", output,
+ flags=re.DOTALL + re.MULTILINE)
output = ifhtml_re.sub(self.make_block, output)
output = ifmobile_re.sub(self.make_block, output)
diff --git a/converter/markdown/tabular.py b/converter/markdown/tabular.py
index 8efe7093..af2a7cc1 100644
--- a/converter/markdown/tabular.py
+++ b/converter/markdown/tabular.py
@@ -24,8 +24,8 @@ def safe_list_get(self, list, idx, default):
return default
def _format_table(self, matchobj):
+ caret_token = self._caret_token
block_contents = matchobj.group('block_contents')
-
block_contents = block_contents.strip()
sub_lines = block_contents.split('\n')
size = get_text_in_brackets(sub_lines[0])
@@ -50,6 +50,26 @@ def _format_table(self, matchobj):
row = re.sub(r"\\multicolumn{(.*?)}{(.*?)}{(.*?)}", r"\3", row, flags=re.DOTALL + re.VERBOSE)
row = re.sub(r"\\multirow{(.*?)}{(.*?)}\s?{(.*?)}", r"\3", row, flags=re.DOTALL + re.VERBOSE)
+ tabularline_match = re.search(r"\\tabularline", block_contents, flags=re.DOTALL + re.VERBOSE)
+ if tabularline_match:
+ head = True
+ for line in block_contents.split('\n'):
+ line = line.replace('\\\\', '
').strip()
+ line = line.strip()
+ if not line:
+ continue
+ if '\\tabularline' in line and head:
+ out += f'{caret_token}|{line}|{caret_token}|-|{caret_token}|'
+ head = False
+ continue
+ if '\\tabularline' in line and not head:
+ out += f'|{caret_token}'
+ head = True
+ continue
+ out += f'{line} '
+ out = out.replace('\\tabularline', '')
+ break
+
t_size = len(table_size)
match = self._graphics_re.search(row)
diff --git a/converter/toc.py b/converter/toc.py
index 810e8744..243df6af 100644
--- a/converter/toc.py
+++ b/converter/toc.py
@@ -12,7 +12,7 @@ def is_section(line):
def is_chapter(line):
- return line.startswith('\\chapter')
+ return line.startswith('\\chapter[') or line.startswith('\\chapter{')
def is_toc(line):
From d87b2500ef44d4dc1c9e805c232514da673fff75 Mon Sep 17 00:00:00 2001
From: achetporov
Date: Tue, 19 May 2020 11:02:17 +0300
Subject: [PATCH 12/39] some fixes (#44)
fixed extra line breaks
---
converter/markdown/block.py | 5 ++--
converter/markdown/checkyourself.py | 5 +++-
converter/markdown/cite.py | 14 +++++++--
converter/markdown/saas_specific.py | 4 +++
converter/markdown/tabular.py | 2 +-
tests/unit/cases/checkyourself.md | 4 +--
tests/unit/cases/checkyourself_complex.md | 10 ++-----
tests/unit/cases/html.md | 35 ++++++-----------------
tests/unit/cases/new_line.md | 6 +---
tests/unit/cases/quote.md | 4 +--
tests/unit/cases/saas.md | 13 +++------
tests/unit/cases/saas1.md | 12 +++-----
tests/unit/cases/saas2.md | 6 ++--
tests/unit/cases/sidebar.md | 1 +
tests/unit/cases/tabular.md | 2 +-
tests/unit/cases/tabularx.md | 16 +++++------
16 files changed, 57 insertions(+), 82 deletions(-)
diff --git a/converter/markdown/block.py b/converter/markdown/block.py
index 1b559f9d..815ea836 100644
--- a/converter/markdown/block.py
+++ b/converter/markdown/block.py
@@ -69,9 +69,8 @@ def _format_block_contents(self, block_name, block_contents):
for line in block_contents.lstrip().rstrip().split("\n"):
line = line.lstrip().rstrip()
line = line.replace("\\\\", "
")
- indented_line = line_indent_char + line + self._caret_token
- output_str += indented_line
- return output_str
+ output_str += f'{line} '
+ return line_indent_char + output_str
def _format_block_name(self, block_name, block_title=None):
block_config = self._block_configuration[block_name]
diff --git a/converter/markdown/checkyourself.py b/converter/markdown/checkyourself.py
index d54b9811..8a5ecf5b 100644
--- a/converter/markdown/checkyourself.py
+++ b/converter/markdown/checkyourself.py
@@ -17,10 +17,13 @@ def make_answer_block(self, matchobj):
answer_block_contents = matchobj.group('answer_block_contents')
answer_block_contents = answer_block_contents.replace("\\\\", "
")
answer_block_contents = self.to_paragraph(answer_block_contents)
- return 'Check yourself
{} '.format(answer_block_contents)
+ return '{}Check yourself
{}' \
+ ' '.format(self._caret_token, answer_block_contents)
def make_block(self, matchobj):
block_contents = matchobj.group('block_contents')
+ block_contents = re.sub(r"\s*\n\s*", " ", block_contents).strip()
+ block_contents = block_contents.replace("\\\\", "
")
answer_str = answer_re.sub(self.make_answer_block, block_contents)
caret_token = self._caret_token
return f'{caret_token}|||challenge{caret_token}{answer_str}{caret_token}|||{caret_token}'
diff --git a/converter/markdown/cite.py b/converter/markdown/cite.py
index 301cae24..a5d476c7 100644
--- a/converter/markdown/cite.py
+++ b/converter/markdown/cite.py
@@ -4,11 +4,19 @@
from converter.markdown.block_matcher import match_block
from converter.guides.tools import get_text_in_brackets
-cite_re = re.compile(r"""~?\\cite{(?P[.*?)}""", flags=re.DOTALL + re.VERBOSE)
+cite_re = re.compile(r"""\\cite{(?P][.*?)}""", flags=re.DOTALL + re.VERBOSE)
bib_re = re.compile(r"""@(?P.*?){(?P][.*?),""", flags=re.DOTALL + re.VERBOSE)
+def clean_title(title):
+ title = title.replace("{", "").replace("}", "")
+ title = title.replace("\\&", "&")
+ title = title.replace("`", "'")
+ title = title.replace("---", "-")
+ return title
+
+
class Cite(object):
_bib_file = None
_bib_entries = []
@@ -66,10 +74,10 @@ def get_bib_text(self, ref):
if bib_item:
if bib_item.get('title') and bib_item.get('author'):
author = bib_item.get('author')
- title = bib_item.get('title')
+ title = clean_title(bib_item.get('title'))
return f'{author}'
elif bib_item.get('title'):
- return bib_item.get('title')
+ return clean_title(bib_item.get('title'))
elif bib_item.get('author'):
return bib_item.get('author')
return ref
diff --git a/converter/markdown/saas_specific.py b/converter/markdown/saas_specific.py
index 4348a5b8..bc7e81f7 100644
--- a/converter/markdown/saas_specific.py
+++ b/converter/markdown/saas_specific.py
@@ -54,8 +54,12 @@ def convert(self):
output = re.sub(r"\\cline{.*?}", "", output)
output = re.sub(r"vs.\\", "vs.", output)
output = re.sub(r"\.\\\\\*\}", ".}", output)
+ output = re.sub(r"__~to~__", r" __to__ ", output)
output = re.sub(r"\\textsection", "$", output)
output = re.sub(r"\\fillinblank{}", "_________", output)
+ output = re.sub(r"\\textasciicircum({})?", r"\^", output)
+ output = re.sub(r"\\textbackslash{}", r"\\", output)
+ output = re.sub(r"\\end{(.*?)}\s", r"\\end{\1}\n", output)
output = self._saas_icons_re.sub(self._saas_icons_block, output)
output = self._saas_2icons_re.sub(self._saas_icons_block, output)
output = self._new_re.sub(self.make_block, output)
diff --git a/converter/markdown/tabular.py b/converter/markdown/tabular.py
index af2a7cc1..07f620fd 100644
--- a/converter/markdown/tabular.py
+++ b/converter/markdown/tabular.py
@@ -81,7 +81,7 @@ def _format_table(self, matchobj):
for ind in range(0, t_size):
data = row.split('&')
col = self.safe_list_get(data, ind, '').strip()
- col = col.replace('\n', ']
')
+ col = re.sub(r'\s*\n\s*', ' ', col)
col = col.replace('\\\\', '')
out += "|" + col.replace('|', '|')
if heading:
diff --git a/tests/unit/cases/checkyourself.md b/tests/unit/cases/checkyourself.md
index 437f1d1e..45b1bc1a 100644
--- a/tests/unit/cases/checkyourself.md
+++ b/tests/unit/cases/checkyourself.md
@@ -1,6 +1,4 @@
|||challenge
-
-True or False: User stories on 3x5 cards in BDD play the same role as design requirements in plan-and-document.
+True or False: User stories on 3x5 cards in BDD play the same role as design requirements in plan-and-document.
Check yourself
True.
-
|||
\ No newline at end of file
diff --git a/tests/unit/cases/checkyourself_complex.md b/tests/unit/cases/checkyourself_complex.md
index 1f6ec0d4..9eeda40e 100644
--- a/tests/unit/cases/checkyourself_complex.md
+++ b/tests/unit/cases/checkyourself_complex.md
@@ -1,8 +1,4 @@
|||challenge
-
- Suppose you mix __Enumerable__ into a class __Foo__ that does not
- provide the __each__ method. What error will be raised when you
- call __Foo.new.map { |elt| puts elt }__?
- Check yourself
The __map__ method in __Enumerable__ will attempt to call __each__ on its receiver, but since the new __Foo__ object doesn't define __each__, Ruby will raise an Undefined Method error.
-
-|||
+Suppose you mix __Enumerable__ into a class __Foo__ that does not provide the __each__ method. What error will be raised when you call __Foo.new.map { |elt| puts elt }__?
+Check yourself
The __map__ method in __Enumerable__ will attempt to call __each__ on its receiver, but since the new __Foo__ object doesn't define __each__, Ruby will raise an Undefined Method error.
+|||
\ No newline at end of file
diff --git a/tests/unit/cases/html.md b/tests/unit/cases/html.md
index b56a0475..abe98bc9 100644
--- a/tests/unit/cases/html.md
+++ b/tests/unit/cases/html.md
@@ -104,11 +104,8 @@ SPA vs MPA: Are you building something that's more like a website (transactional
|||challenge
-
- True or false: every HTML element must have an ID.
-
- Check yourself
False---the ID is optional, though must be unique if provided.
-
+True or false: every HTML element must have an ID.
+Check yourself
False---the ID is optional, though must be unique if provided.
|||
@@ -122,39 +119,25 @@ SPA vs MPA: Are you building something that's more like a website (transactional
|||challenge
-
-
- Given the following HTML markup:
-
-
+Given the following HTML markup:
**source:ch_arch/code/htmlexercise.html**
```code
ch_arch/code/htmlexercise.html
```
-
- Write down a CSS selector that will select *only* the word
- *Mondays* for styling.
- Check yourself
Three possibilities, from most specific to least specific, are: __#i span__, __p.x span__, and __.x span__. Other selectors are possible but redundant or over-constrained; for example, __p#i span__ and __p#i.x span__ are redundant with respect to this HTML snippet since at most one element can have the ID __i__.
-
+ Write down a CSS selector that will select *only* the word *Mondays* for styling.
+Check yourself
Three possibilities, from most specific to least specific, are: __#i span__, __p.x span__, and __.x span__. Other selectors are possible but redundant or over-constrained; for example, __p#i span__ and __p#i.x span__ are redundant with respect to this HTML snippet since at most one element can have the ID __i__.
|||
|||challenge
-
- In Self-Check ex:css1, why are __span__
- and __p span__ *not* valid answers?
- Check yourself
Both of those selector also match *Tuesdays*, which is a __span__ inside a __p__.
-
+In Self-Check ex:css1, why are __span__ and __p span__ *not* valid answers?
+Check yourself
Both of those selector also match *Tuesdays*, which is a __span__ inside a __p__.
|||
|||challenge
-
- What is the most common way to associate a CSS stylesheet with an HTML
- or HTML document? (HINT: refer to the earlier screencast example.)
-
- Check yourself
Within the **HEAD** element of the HTML or HTML document, include a **LINK** element with at least the following three attributes: **REL="STYLESHEET"**, **TYPE="text/css"**, and **HREF="*uri*"**, where ***uri*** is the full or partial URI of the stylesheet. That is, the stylesheet must be accessible as a resource named by a URI.
-
+What is the most common way to associate a CSS stylesheet with an HTML or HTML document? (HINT: refer to the earlier screencast example.)
+Check yourself
Within the **HEAD** element of the HTML or HTML document, include a **LINK** element with at least the following three attributes: **REL="STYLESHEET"**, **TYPE="text/css"**, and **HREF="*uri*"**, where ***uri*** is the full or partial URI of the stylesheet. That is, the stylesheet must be accessible as a resource named by a URI.
|||
diff --git a/tests/unit/cases/new_line.md b/tests/unit/cases/new_line.md
index f40a25f8..c09cf8d6 100644
--- a/tests/unit/cases/new_line.md
+++ b/tests/unit/cases/new_line.md
@@ -1,8 +1,4 @@
-> No bottles of beer on the wall,
-> no bottles of beer,
-> ya' can't take one down, ya' can't pass it around,
-> 'cause there are no more bottles of beer on the wall!
-
+> No bottles of beer on the wall,
no bottles of beer,
ya' can't take one down, ya' can't pass it around,
'cause there are no more bottles of beer on the wall!
diff --git a/tests/unit/cases/quote.md b/tests/unit/cases/quote.md
index 7792643b..3f38c2b6 100644
--- a/tests/unit/cases/quote.md
+++ b/tests/unit/cases/quote.md
@@ -1,3 +1 @@
-> A word is said to be a “doubloon” if every letter that appears in the word appears exactly twice.
-> Write a method called `isDoubloon` that takes a string and checks whether it is a doubloon.
-> To ignore case, invoke the `toLowerCase` method before checking.
\ No newline at end of file
+> A word is said to be a “doubloon” if every letter that appears in the word appears exactly twice. Write a method called `isDoubloon` that takes a string and checks whether it is a doubloon. To ignore case, invoke the `toLowerCase` method before checking.
\ No newline at end of file
diff --git a/tests/unit/cases/saas.md b/tests/unit/cases/saas.md
index 43594973..f0449f53 100644
--- a/tests/unit/cases/saas.md
+++ b/tests/unit/cases/saas.md
@@ -51,10 +51,8 @@ Note that frequent upgrades of SaaS---due to only having a single copy of the so
|||challenge
-
-Which of the examples of Google SaaS apps---Search, Maps, News, Gmail, Calendar, YouTube, and Documents---is the *best* match to each of the six arguments given in this section for SaaS, reproduced below.
- Check yourself
While you can argue the mappings, below is our answer. (Note that we cheated and put some apps in multiple categories)
-
+Which of the examples of Google SaaS apps---Search, Maps, News, Gmail, Calendar, YouTube, and Documents---is the *best* match to each of the six arguments given in this section for SaaS, reproduced below.
+Check yourself
While you can argue the mappings, below is our answer. (Note that we cheated and put some apps in multiple categories)
1. No user installation: Documents
1. Can't lose data: Gmail, Calendar.
@@ -64,16 +62,13 @@ Which of the examples of Google SaaS apps---Search, Maps, News, Gmail, Calendar
1. No field upgrades when improve app: Documents.
-
|||
|||challenge
-
- True or False: If you are using the Agile development process to develop SaaS apps, you could use Python and Django or languages based on the Microsoft's .NET framework and ASP.NET instead of Ruby and Rails.
- Check yourself
True. Programming frameworks for Agile and SaaS include Django and ASP.NET.
-
+True or False: If you are using the Agile development process to develop SaaS apps, you could use Python and Django or languages based on the Microsoft's .NET framework and ASP.NET instead of Ruby and Rails.
+Check yourself
True. Programming frameworks for Agile and SaaS include Django and ASP.NET.
|||
diff --git a/tests/unit/cases/saas1.md b/tests/unit/cases/saas1.md
index 79ff865a..d9ac6960 100644
--- a/tests/unit/cases/saas1.md
+++ b/tests/unit/cases/saas1.md
@@ -147,19 +147,15 @@ An unfortunate downside to teaching a Plan-and-Document approach is that student
|||challenge
-
- What are a major similarity and a major difference between processes like Spiral and RUP versus Waterfall?
- Check yourself
All rely on planning and documentation, but Spiral and RUP use iteration and prototypes to improve them over time versus a single long path to the product.
-
+What are a major similarity and a major difference between processes like Spiral and RUP versus Waterfall?
+Check yourself
All rely on planning and documentation, but Spiral and RUP use iteration and prototypes to improve them over time versus a single long path to the product.
|||
|||challenge
-
- What are the differences between the phases of these Plan-and-Document processes?
- Check yourself
Waterfall phases separate planning (requirements and architectural design) from implementation. Testing the product before release is next, followed by a separate operations phase. The Spiral phases are aimed at an iteration: set the goals for an iteration; explore alternatives; develop and verify the prototype for this iteration; and plan the next iteration. RUP phases are tied closer to business objectives: inception makes business case and sets schedule and budget; elaboration works with customers to build an initial prototype; construction builds and test the first version; and transition deploys the product.
-
+What are the differences between the phases of these Plan-and-Document processes?
+Check yourself
Waterfall phases separate planning (requirements and architectural design) from implementation. Testing the product before release is next, followed by a separate operations phase. The Spiral phases are aimed at an iteration: set the goals for an iteration; explore alternatives; develop and verify the prototype for this iteration; and plan the next iteration. RUP phases are tied closer to business objectives: inception makes business case and sets schedule and budget; elaboration works with customers to build an initial prototype; construction builds and test the first version; and transition deploys the product.
|||
## SEI Capability Maturity Model (CMM)
diff --git a/tests/unit/cases/saas2.md b/tests/unit/cases/saas2.md
index 2ae31a29..b7e21964 100644
--- a/tests/unit/cases/saas2.md
+++ b/tests/unit/cases/saas2.md
@@ -10,10 +10,8 @@ While we now see how to build some software successfully, not all projects are s
|||challenge
-
- True or False: A big difference between Spiral and Agile development is building prototypes and interacting with customers during the process.
- Check yourself
False: Both build working but incomplete prototypes that the customer helps evaluate. The difference is that customers are involved every two weeks in Agile versus up to two years in with Spiral.
-
+True or False: A big difference between Spiral and Agile development is building prototypes and interacting with customers during the process.
+Check yourself
False: Both build working but incomplete prototypes that the customer helps evaluate. The difference is that customers are involved every two weeks in Agile versus up to two years in with Spiral.
|||
## Versions of Agile
diff --git a/tests/unit/cases/sidebar.md b/tests/unit/cases/sidebar.md
index 0c1a0de8..6e3d558e 100644
--- a/tests/unit/cases/sidebar.md
+++ b/tests/unit/cases/sidebar.md
@@ -18,3 +18,4 @@
The use of angle brackets for tags comes from ___SGML___ (Standard Generalized Markup Language), a codified standardization of IBM's Generalized Markup Language, developed in the 1960s for encoding computer-readable project documents.
|||
+
diff --git a/tests/unit/cases/tabular.md b/tests/unit/cases/tabular.md
index b23bd696..94c8cc4a 100644
--- a/tests/unit/cases/tabular.md
+++ b/tests/unit/cases/tabular.md
@@ -9,7 +9,7 @@
|**div#message**|The **div** whose ID is **message**|
|**.red**|Any element with class **red**|
|**div.red, h1**|The **div** with class **red**, or any **h1**|
-|**div#message h1**|An **h1** element that's a child of (inside
of) **div#message**|
+|**div#message h1**|An **h1** element that's a child of (inside of) **div#message**|
|**a.lnk**|**a** element with class **lnk**|
|**a.lnk:hover**|**a** element with class **lnk**, when hovered over|
diff --git a/tests/unit/cases/tabularx.md b/tests/unit/cases/tabularx.md
index 0aa45f3c..496d296e 100644
--- a/tests/unit/cases/tabularx.md
+++ b/tests/unit/cases/tabularx.md
@@ -1,14 +1,14 @@
|**Item**|**3 points**|**2 points**|**1 point**|
|-|-|-|-|
-|**Preparation**|Presentation was rehearsed thoroughly, few hiccups|Presentation is mostly fluid, with the exception of maybe 1 or 2
underprepared people|Sloppy presentation, no clear direction or disorganized|
-|**Customer Need**||Included brief statement of customer problem and scope of project|Not clear what the customer really wanted or what problem the group is
trying to solve|
-|**Technical Discussion**|Clearly conveyed some technical details of the app. Discussed a
technical challenge in an understandable way|Attempted to talk about technical aspects of app, mostly successfully.
Either no technical challenge or not able to clearly convey technical
topics|Little or no technical coverage of their app. Implementation details
are unclear.|
-|**Customer Interaction**|Clearly describe relationship with customer. Talk about goods, bads, and
what was learned|Talked about customer interaction to some extent|Mentioned customer interaction, but no details about the experience|
-|**Development Practices**|Explained clearly their implementation of agile in their iterations.
Reflect on what went well and what did not. Had a method to taking on
iterations.|Briefly explain development practices. Give an idea of approaches they
took to iterations/Agile, but don't reflect on their effectiveness|Doesn't appear they took methodology seriously, and/or no evidence of
concrete implementation of agile principles|
+|**Preparation**|Presentation was rehearsed thoroughly, few hiccups|Presentation is mostly fluid, with the exception of maybe 1 or 2 underprepared people|Sloppy presentation, no clear direction or disorganized|
+|**Customer Need**||Included brief statement of customer problem and scope of project|Not clear what the customer really wanted or what problem the group is trying to solve|
+|**Technical Discussion**|Clearly conveyed some technical details of the app. Discussed a technical challenge in an understandable way|Attempted to talk about technical aspects of app, mostly successfully. Either no technical challenge or not able to clearly convey technical topics|Little or no technical coverage of their app. Implementation details are unclear.|
+|**Customer Interaction**|Clearly describe relationship with customer. Talk about goods, bads, and what was learned|Talked about customer interaction to some extent|Mentioned customer interaction, but no details about the experience|
+|**Development Practices**|Explained clearly their implementation of agile in their iterations. Reflect on what went well and what did not. Had a method to taking on iterations.|Briefly explain development practices. Give an idea of approaches they took to iterations/Agile, but don't reflect on their effectiveness|Doesn't appear they took methodology seriously, and/or no evidence of concrete implementation of agile principles|
|**Approach**|**Technologies \& Tools**|**Main Pros**|**Main Cons**||
|-|-|-|-|-|
-|Responsive or mobile-only Web site|HTML5, CSS, JavaScript; any development environment|Portable across devices, so no need to develop/maintain multiple
versions; updates automatically|May not show up in searches; not listed in app stores; may lack
access to certain platform hardware features, such as
biometrics-based identification||
-|Native app|Java (Android) or Objective-C (iOS) with mobile-specific IDE|Best performance; guaranteed access to all platform hardware features|Must rely on users to download and install updates; supporting
multiple platforms requires maintaining multiple codebases||
-|Wrapped app|HTML5, CSS, JavaScript; framework such as PhoneGap required to
“package” app for distribution|Portable, develop with any IDE, but still get installable app that
appears in app stores and searches|Must rely on users to download and install updates||
\ No newline at end of file
+|Responsive or mobile-only Web site|HTML5, CSS, JavaScript; any development environment|Portable across devices, so no need to develop/maintain multiple versions; updates automatically|May not show up in searches; not listed in app stores; may lack access to certain platform hardware features, such as biometrics-based identification||
+|Native app|Java (Android) or Objective-C (iOS) with mobile-specific IDE|Best performance; guaranteed access to all platform hardware features|Must rely on users to download and install updates; supporting multiple platforms requires maintaining multiple codebases||
+|Wrapped app|HTML5, CSS, JavaScript; framework such as PhoneGap required to “package” app for distribution|Portable, develop with any IDE, but still get installable app that appears in app stores and searches|Must rely on users to download and install updates||
\ No newline at end of file
From 38c2fd7696a362082566f590ed99e1740b60f92c Mon Sep 17 00:00:00 2001
From: achetporov
Date: Wed, 20 May 2020 10:30:22 +0300
Subject: [PATCH 13/39] changed dpi for pdf2image converter (#45)
---
converter/assets.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/converter/assets.py b/converter/assets.py
index 711022a5..a1dbf555 100644
--- a/converter/assets.py
+++ b/converter/assets.py
@@ -49,7 +49,7 @@ def _convert_assets(config, generate_dir, pdfs_for_convert, convert_from_path, b
dst_folder.mkdir(exist_ok=True, parents=True)
try:
- pages = convert_from_path(pdf_file, 500)
+ pages = convert_from_path(pdf_file, 400)
if pages:
image = Path(pdf.replace('.pdf', '.jpg'))
page = pages[0]
From b9a8af9e72b3df9e99af1b47ccc1292d47db230c Mon Sep 17 00:00:00 2001
From: achetporov
Date: Thu, 21 May 2020 09:33:33 +0300
Subject: [PATCH 14/39] fixed display equation (#48)
fixed display equation
---
converter/latex2markdown.py | 2 ++
converter/markdown/equation.py | 19 +++++++++++++++++++
tests/unit/cases/equation.md | 7 +++++++
tests/unit/cases/equation.tex | 5 +++++
tests/unit/test_render_markdown.py | 3 +++
5 files changed, 36 insertions(+)
create mode 100644 converter/markdown/equation.py
create mode 100644 tests/unit/cases/equation.md
create mode 100644 tests/unit/cases/equation.tex
diff --git a/converter/latex2markdown.py b/converter/latex2markdown.py
index b414065b..670f1de4 100644
--- a/converter/latex2markdown.py
+++ b/converter/latex2markdown.py
@@ -2,6 +2,7 @@
import re
from converter.markdown.del_icons_description import DelIconsDescription
+from converter.markdown.equation import Equation
from converter.markdown.inline_code_block import InlineCodeBlock
from converter.markdown.code_block import CodeBlock
from converter.markdown.bold import Bold
@@ -89,6 +90,7 @@ def _latex_to_markdown(self):
output = Ignore(output).convert()
output = SaasSpecific(output, self._caret_token).convert()
output = ItalicBold(output).convert()
+ output = Equation(output, self._caret_token).convert()
output, source_codes = CodeBlock(
output, self._percent_token, self._caret_token, self._remove_trinket
).convert()
diff --git a/converter/markdown/equation.py b/converter/markdown/equation.py
new file mode 100644
index 00000000..648fba4d
--- /dev/null
+++ b/converter/markdown/equation.py
@@ -0,0 +1,19 @@
+import re
+
+equation_re = re.compile(r"""\\begin{equation}(?P.*?)\\end{equation}""", flags=re.DOTALL)
+
+
+class Equation(object):
+ def __init__(self, latex_str, caret_token):
+ self._caret_token = caret_token
+ self.str = latex_str
+
+ def make_block(self, matchobj):
+ block_contents = matchobj.group('block_contents')
+ block_contents = block_contents.strip()
+ caret_token = self._caret_token
+ return f'{caret_token}{caret_token}$${caret_token}{block_contents}' \
+ f'{caret_token}$${caret_token}{caret_token}'
+
+ def convert(self):
+ return equation_re.sub(self.make_block, self.str)
diff --git a/tests/unit/cases/equation.md b/tests/unit/cases/equation.md
new file mode 100644
index 00000000..67c7bd79
--- /dev/null
+++ b/tests/unit/cases/equation.md
@@ -0,0 +1,7 @@
+Finally, like performance, reliability can be measured. We can improve availability either taking longer between failures (MTTF) or by making the app reboot faster---___mean time between repairs___ (___MTTR___)---as this equation shows:
+
+$$
+\mbox{unavailability} \approx \frac{\mbox{MTTR}}{\mbox{MTTF}}
+$$
+
+ While it is hard to measure improvements in MTTF, as it can take a long time to record failures, we can easily measure MTTR. We just crash a computer and see how long it takes the app to reboot. And what we can measure, we can improve. Hence, it may be much more cost-effective to try to improve MTTR than to improve MTTF since it is easier to measure progress. However, they are not mutually exclusive, so developers can try to increase dependability by following both paths.
\ No newline at end of file
diff --git a/tests/unit/cases/equation.tex b/tests/unit/cases/equation.tex
new file mode 100644
index 00000000..19651654
--- /dev/null
+++ b/tests/unit/cases/equation.tex
@@ -0,0 +1,5 @@
+Finally, like performance, reliability can be measured. We can improve availability either taking longer between failures (MTTF) or by making the app reboot faster---\w{mean time between repairs} (\w[mean time between repairs]{MTTR})\index{Mean time between repairs (MTTR)}---as this equation shows:
+\begin{equation}
+ \mbox{unavailability} \approx \frac{\mbox{MTTR}}{\mbox{MTTF}}
+\end{equation}
+While it is hard to measure improvements in MTTF, as it can take a long time to record failures, we can easily measure MTTR. We just crash a computer and see how long it takes the app to reboot. And what we can measure, we can improve. Hence, it may be much more cost-effective to try to improve MTTR than to improve MTTF since it is easier to measure progress. However, they are not mutually exclusive, so developers can try to increase dependability by following both paths.
diff --git a/tests/unit/test_render_markdown.py b/tests/unit/test_render_markdown.py
index 3709898c..dbaa9aa7 100644
--- a/tests/unit/test_render_markdown.py
+++ b/tests/unit/test_render_markdown.py
@@ -303,3 +303,6 @@ def test_twoicons(self):
def test_turingwinner(self):
self.run_case("turingwinner")
+
+ def test_equation(self):
+ self.run_case("equation")
From dca0a84d4c07598eea3075a8bb24fedae0a48ddb Mon Sep 17 00:00:00 2001
From: achetporov
Date: Thu, 21 May 2020 14:13:31 +0300
Subject: [PATCH 15/39] 11525 fix self check (#47)
fixed display md-code in self-test blocks
---
converter/markdown/checkyourself.py | 5 +++--
tests/unit/cases/checkyourself.md | 4 +++-
tests/unit/cases/checkyourself_complex.md | 4 +++-
tests/unit/cases/html.md | 16 ++++++++++++----
tests/unit/cases/saas.md | 10 +++++++---
tests/unit/cases/saas1.md | 8 ++++++--
tests/unit/cases/saas2.md | 4 +++-
7 files changed, 37 insertions(+), 14 deletions(-)
diff --git a/converter/markdown/checkyourself.py b/converter/markdown/checkyourself.py
index 8a5ecf5b..59385eb0 100644
--- a/converter/markdown/checkyourself.py
+++ b/converter/markdown/checkyourself.py
@@ -17,8 +17,9 @@ def make_answer_block(self, matchobj):
answer_block_contents = matchobj.group('answer_block_contents')
answer_block_contents = answer_block_contents.replace("\\\\", "
")
answer_block_contents = self.to_paragraph(answer_block_contents)
- return '{}Check yourself
{}' \
- ' '.format(self._caret_token, answer_block_contents)
+ caret_token = self._caret_token
+ return f'{caret_token}Check yourself
' \
+ f'{caret_token}{caret_token}{answer_block_contents}
'
def make_block(self, matchobj):
block_contents = matchobj.group('block_contents')
diff --git a/tests/unit/cases/checkyourself.md b/tests/unit/cases/checkyourself.md
index 45b1bc1a..87d8a9cd 100644
--- a/tests/unit/cases/checkyourself.md
+++ b/tests/unit/cases/checkyourself.md
@@ -1,4 +1,6 @@
|||challenge
True or False: User stories on 3x5 cards in BDD play the same role as design requirements in plan-and-document.
-Check yourself
True.
+Check yourself
+
+True.
|||
\ No newline at end of file
diff --git a/tests/unit/cases/checkyourself_complex.md b/tests/unit/cases/checkyourself_complex.md
index 9eeda40e..08b7ade1 100644
--- a/tests/unit/cases/checkyourself_complex.md
+++ b/tests/unit/cases/checkyourself_complex.md
@@ -1,4 +1,6 @@
|||challenge
Suppose you mix __Enumerable__ into a class __Foo__ that does not provide the __each__ method. What error will be raised when you call __Foo.new.map { |elt| puts elt }__?
-Check yourself
The __map__ method in __Enumerable__ will attempt to call __each__ on its receiver, but since the new __Foo__ object doesn't define __each__, Ruby will raise an Undefined Method error.
+Check yourself
+
+The __map__ method in __Enumerable__ will attempt to call __each__ on its receiver, but since the new __Foo__ object doesn't define __each__, Ruby will raise an Undefined Method error.
|||
\ No newline at end of file
diff --git a/tests/unit/cases/html.md b/tests/unit/cases/html.md
index abe98bc9..0cb11ff0 100644
--- a/tests/unit/cases/html.md
+++ b/tests/unit/cases/html.md
@@ -105,7 +105,9 @@ SPA vs MPA: Are you building something that's more like a website (transactional
|||challenge
True or false: every HTML element must have an ID.
-Check yourself
False---the ID is optional, though must be unique if provided.
+Check yourself
+
+False---the ID is optional, though must be unique if provided.
|||
@@ -125,19 +127,25 @@ Given the following HTML markup:
ch_arch/code/htmlexercise.html
```
Write down a CSS selector that will select *only* the word *Mondays* for styling.
-Check yourself
Three possibilities, from most specific to least specific, are: __#i span__, __p.x span__, and __.x span__. Other selectors are possible but redundant or over-constrained; for example, __p#i span__ and __p#i.x span__ are redundant with respect to this HTML snippet since at most one element can have the ID __i__.
+Check yourself
+
+Three possibilities, from most specific to least specific, are: __#i span__, __p.x span__, and __.x span__. Other selectors are possible but redundant or over-constrained; for example, __p#i span__ and __p#i.x span__ are redundant with respect to this HTML snippet since at most one element can have the ID __i__.
|||
|||challenge
In Self-Check ex:css1, why are __span__ and __p span__ *not* valid answers?
-Check yourself
Both of those selector also match *Tuesdays*, which is a __span__ inside a __p__.
+Check yourself
+
+Both of those selector also match *Tuesdays*, which is a __span__ inside a __p__.
|||
|||challenge
What is the most common way to associate a CSS stylesheet with an HTML or HTML document? (HINT: refer to the earlier screencast example.)
-Check yourself
Within the **HEAD** element of the HTML or HTML document, include a **LINK** element with at least the following three attributes: **REL="STYLESHEET"**, **TYPE="text/css"**, and **HREF="*uri*"**, where ***uri*** is the full or partial URI of the stylesheet. That is, the stylesheet must be accessible as a resource named by a URI.
+Check yourself
+
+Within the **HEAD** element of the HTML or HTML document, include a **LINK** element with at least the following three attributes: **REL="STYLESHEET"**, **TYPE="text/css"**, and **HREF="*uri*"**, where ***uri*** is the full or partial URI of the stylesheet. That is, the stylesheet must be accessible as a resource named by a URI.
|||
diff --git a/tests/unit/cases/saas.md b/tests/unit/cases/saas.md
index f0449f53..c9f39bce 100644
--- a/tests/unit/cases/saas.md
+++ b/tests/unit/cases/saas.md
@@ -52,7 +52,9 @@ Note that frequent upgrades of SaaS---due to only having a single copy of the so
|||challenge
Which of the examples of Google SaaS apps---Search, Maps, News, Gmail, Calendar, YouTube, and Documents---is the *best* match to each of the six arguments given in this section for SaaS, reproduced below.
-Check yourself
While you can argue the mappings, below is our answer. (Note that we cheated and put some apps in multiple categories)
+Check yourself
+
+While you can argue the mappings, below is our answer. (Note that we cheated and put some apps in multiple categories)
1. No user installation: Documents
1. Can't lose data: Gmail, Calendar.
@@ -61,14 +63,16 @@ Which of the examples of Google SaaS apps---Search, Maps, News, Gmail, Calendar
1. Software centralized in single environment: Search.
1. No field upgrades when improve app: Documents.
-
+
|||
|||challenge
True or False: If you are using the Agile development process to develop SaaS apps, you could use Python and Django or languages based on the Microsoft's .NET framework and ASP.NET instead of Ruby and Rails.
-Check yourself
True. Programming frameworks for Agile and SaaS include Django and ASP.NET.
+Check yourself
+
+True. Programming frameworks for Agile and SaaS include Django and ASP.NET.
|||
diff --git a/tests/unit/cases/saas1.md b/tests/unit/cases/saas1.md
index d9ac6960..64b8f96c 100644
--- a/tests/unit/cases/saas1.md
+++ b/tests/unit/cases/saas1.md
@@ -148,14 +148,18 @@ An unfortunate downside to teaching a Plan-and-Document approach is that student
|||challenge
What are a major similarity and a major difference between processes like Spiral and RUP versus Waterfall?
-Check yourself
All rely on planning and documentation, but Spiral and RUP use iteration and prototypes to improve them over time versus a single long path to the product.
+Check yourself
+
+All rely on planning and documentation, but Spiral and RUP use iteration and prototypes to improve them over time versus a single long path to the product.
|||
|||challenge
What are the differences between the phases of these Plan-and-Document processes?
-Check yourself
Waterfall phases separate planning (requirements and architectural design) from implementation. Testing the product before release is next, followed by a separate operations phase. The Spiral phases are aimed at an iteration: set the goals for an iteration; explore alternatives; develop and verify the prototype for this iteration; and plan the next iteration. RUP phases are tied closer to business objectives: inception makes business case and sets schedule and budget; elaboration works with customers to build an initial prototype; construction builds and test the first version; and transition deploys the product.
+Check yourself
+
+Waterfall phases separate planning (requirements and architectural design) from implementation. Testing the product before release is next, followed by a separate operations phase. The Spiral phases are aimed at an iteration: set the goals for an iteration; explore alternatives; develop and verify the prototype for this iteration; and plan the next iteration. RUP phases are tied closer to business objectives: inception makes business case and sets schedule and budget; elaboration works with customers to build an initial prototype; construction builds and test the first version; and transition deploys the product.
|||
## SEI Capability Maturity Model (CMM)
diff --git a/tests/unit/cases/saas2.md b/tests/unit/cases/saas2.md
index b7e21964..9d96ef18 100644
--- a/tests/unit/cases/saas2.md
+++ b/tests/unit/cases/saas2.md
@@ -11,7 +11,9 @@ While we now see how to build some software successfully, not all projects are s
|||challenge
True or False: A big difference between Spiral and Agile development is building prototypes and interacting with customers during the process.
-Check yourself
False: Both build working but incomplete prototypes that the customer helps evaluate. The difference is that customers are involved every two weeks in Agile versus up to two years in with Spiral.
+Check yourself
+
+False: Both build working but incomplete prototypes that the customer helps evaluate. The difference is that customers are involved every two weeks in Agile versus up to two years in with Spiral.
|||
## Versions of Agile
From 429d0c9d4aa3b0017bf40828cf475fa862615ef0 Mon Sep 17 00:00:00 2001
From: achetporov
Date: Fri, 22 May 2020 12:21:48 +0300
Subject: [PATCH 16/39] fixed invalid content (keep escaping slash for some
chars) (#49)
fixed invalid content (missing page)
---
converter/markdown/checkyourself.py | 2 ++
converter/markdown/tablefigure.py | 2 ++
converter/markdown/unescape.py | 2 --
3 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/converter/markdown/checkyourself.py b/converter/markdown/checkyourself.py
index 59385eb0..7bdb9e27 100644
--- a/converter/markdown/checkyourself.py
+++ b/converter/markdown/checkyourself.py
@@ -27,6 +27,8 @@ def make_block(self, matchobj):
block_contents = block_contents.replace("\\\\", "
")
answer_str = answer_re.sub(self.make_answer_block, block_contents)
caret_token = self._caret_token
+ answer_str = re.sub(r"\\{", r"{", answer_str)
+ answer_str = re.sub(r"\\}", r"}", answer_str)
return f'{caret_token}|||challenge{caret_token}{answer_str}{caret_token}|||{caret_token}'
def convert(self):
diff --git a/converter/markdown/tablefigure.py b/converter/markdown/tablefigure.py
index 0832e6ae..59392342 100644
--- a/converter/markdown/tablefigure.py
+++ b/converter/markdown/tablefigure.py
@@ -51,6 +51,8 @@ def remove_matched_token(self, output, chars):
caret_token = self._caret_token
content = output[pos + token_len:index - 1]
content = content.strip()
+ content = re.sub(r"\\{", r"{", content)
+ content = re.sub(r"\\}", r"}", content)
output = output[0:pos] + content + "**" + caret_token + output[index + 1:]
break
else:
diff --git a/converter/markdown/unescape.py b/converter/markdown/unescape.py
index 91ee7e1d..2a1a4b02 100644
--- a/converter/markdown/unescape.py
+++ b/converter/markdown/unescape.py
@@ -8,8 +8,6 @@ def __init__(self, latex_str):
def convert(self):
output = self.str
- output = re.sub(r"\\{", r"{", output)
- output = re.sub(r"\\}", r"}", output)
output = re.sub(r"\\#", "#", output)
output = re.sub(r"\\_", "_", output)
output = re.sub(r"\\-", "-", output)
From 6eccecce3bf48304c8627206fd014c849a9feda8 Mon Sep 17 00:00:00 2001
From: achetporov
Date: Tue, 26 May 2020 16:23:10 +0300
Subject: [PATCH 17/39] 11533 numbered list addcounter (#51)
* fixed numbered list with "addcounter" (list start number)
* changed format for numbering lists
---
converter/markdown/ignore.py | 1 -
converter/markdown/lists.py | 18 ++++++++++++--
converter/markdown/saas_specific.py | 1 -
tests/unit/cases/enumerate.md | 30 +++++++++++++++++++++--
tests/unit/cases/enumerate.tex | 21 ++++++++++++++++
tests/unit/cases/nested_list.md | 8 +++---
tests/unit/cases/saas.md | 22 ++++++++---------
tests/unit/cases/saas1.md | 38 ++++++++++++++---------------
8 files changed, 99 insertions(+), 40 deletions(-)
diff --git a/converter/markdown/ignore.py b/converter/markdown/ignore.py
index e211d977..5935d381 100644
--- a/converter/markdown/ignore.py
+++ b/converter/markdown/ignore.py
@@ -40,7 +40,6 @@ def convert(self):
output = self.remove_chars(output, "\\index{")
output = self.remove_chars(output, "\\label{")
output = self.remove_chars(output, "\\vspace{")
- output = self.remove_chars(output, "\\addtocounter{")
output = re.sub(r"\\noindent", "", output)
output = re.sub(r"\\prereq", "", output)
output = re.sub(r"\\relax", "", output)
diff --git a/converter/markdown/lists.py b/converter/markdown/lists.py
index 7e6b06ee..842a78be 100644
--- a/converter/markdown/lists.py
+++ b/converter/markdown/lists.py
@@ -10,6 +10,7 @@ def __init__(self, latex_str, caret_token):
self._block_counter = defaultdict(lambda: 1)
self._lists_re = re.compile(r"""\\begin{(?Penumerate|itemize|description)} # list name
+ (\s\\addtocounter{.*?}{(?P\d)})? # list start number
(\[.*?\])? # Optional enumerate settings i.e. (a)
(?P.*?) # Non-greedy list contents
\\end{(?P=block_name)}""", # closing list
@@ -38,9 +39,17 @@ def __init__(self, latex_str, caret_token):
}
}
- def _format_list_contents(self, block_name, block_contents):
+ def _format_list_contents(self, block_name, block_contents, start_number):
block_config = self._block_configuration[block_name]
list_heading = block_config["list_heading"]
+ enum = False
+
+ if block_name == 'enumerate':
+ enum = True
+ if start_number is not None:
+ start_number = int(start_number)
+ else:
+ start_number = 0
output_str = ""
for line in block_contents.lstrip().rstrip().split("\\item"):
@@ -49,6 +58,10 @@ def _format_list_contents(self, block_name, block_contents):
if not line:
continue
+ if enum:
+ start_number += 1
+ list_heading = f'{start_number}. '
+
cline = ""
for sub_str in line.split("\n"):
if not sub_str:
@@ -86,12 +99,13 @@ def _format_block_name(self, block_name, block_title=None):
def _replace_block(self, matchobj):
block_name = matchobj.group('block_name')
block_contents = matchobj.group('block_contents')
+ start_number_str = matchobj.group('start_number')
block_title = matchobj.groupdict().get('block_title')
if '\\begin{enumerate' in block_contents or '\\begin{itemize' in block_contents:
block_contents = self._lists_re.sub(self._replace_block, block_contents)
- formatted_contents = self._format_list_contents(block_name, block_contents)
+ formatted_contents = self._format_list_contents(block_name, block_contents, start_number_str)
formatted_contents = self.to_paragraph(formatted_contents)
header = self._format_block_name(block_name, block_title)
diff --git a/converter/markdown/saas_specific.py b/converter/markdown/saas_specific.py
index bc7e81f7..e4a42e27 100644
--- a/converter/markdown/saas_specific.py
+++ b/converter/markdown/saas_specific.py
@@ -49,7 +49,6 @@ def convert(self):
output = re.sub(r"\\textbar({\})?", r"|", output)
output = re.sub(r"\\hrule", "
", output)
output = re.sub(r"\\hfill", "", output)
- output = re.sub(r"\\addtocounter{.*?}{.*?}", r"", output)
output = re.sub(r"\\small{", r"", output)
output = re.sub(r"\\cline{.*?}", "", output)
output = re.sub(r"vs.\\", "vs.", output)
diff --git a/tests/unit/cases/enumerate.md b/tests/unit/cases/enumerate.md
index fe540cc8..627984d7 100644
--- a/tests/unit/cases/enumerate.md
+++ b/tests/unit/cases/enumerate.md
@@ -1,3 +1,29 @@
1. Type in the hello world program, then compile and run it.
-1. Add a print statement that displays a second message after the “Hello, World!”. Say something witty like, “How are you?” Compile and run the program again.
-1. Add a comment to the program (anywhere), recompile, and run it again. The new comment should not affect the result.
\ No newline at end of file
+2. Add a print statement that displays a second message after the “Hello, World!”. Say something witty like, “How are you?” Compile and run the program again.
+3. Add a comment to the program (anywhere), recompile, and run it again. The new comment should not affect the result.
+
+
+
+Recall that the hope for plan-and-document methods is to make software engineering as predictable in budget and schedule as civil engineering. Remarkably, user stories, points, and velocity correspond to *seven* major tasks of the plan-and-document methodologies. They include:
+
+
+1. Requirements Elicitation
+2. Requirements Documentation
+3. Cost Estimation
+4. Scheduling and Monitoring Progress
+
+
+These are done up front for the Waterfall model and at the beginning of each major iteration for the Spiral and RUP models. As requirements change over time, these items above imply other tasks:
+
+
+5. Change Management for Requirements, Cost, and Schedule
+6. Ensuring Implementation Matches Requirement Features
+
+
+Finally, since accuracy of the budget estimate and the schedule is vital to the success of the plan-and-document process, there is another task not found in BDD:
+
+
+7. Risk Analysis and Management
+
+
+The hope is that by imagining all the risks to the budget and schedule in advance, the project can make plans to avoid or overcome them.
diff --git a/tests/unit/cases/enumerate.tex b/tests/unit/cases/enumerate.tex
index c63e3ece..62c26f29 100644
--- a/tests/unit/cases/enumerate.tex
+++ b/tests/unit/cases/enumerate.tex
@@ -8,3 +8,24 @@
\item Add a comment to the program (anywhere), recompile, and run it again.
The new comment should not affect the result.
\end{enumerate}
+
+Recall that the hope for plan-and-document methods is to make software engineering as predictable in budget and schedule as civil engineering. Remarkably, user stories, points, and velocity correspond to \emph{seven} major tasks of the plan-and-document methodologies. They include:
+\index{Plan-and-Document!major tasks}%
+\begin{enumerate}
+ \item Requirements Elicitation
+ \item Requirements Documentation
+ \item Cost Estimation
+ \item Scheduling and Monitoring Progress
+\end{enumerate}
+\index{Waterfall lifecycle!tasks}\index{Spiral lifecycle!tasks}%
+\index{Rational Unified Process (RUP)!tasks}%
+These are done up front for the Waterfall model and at the beginning of each major iteration for the Spiral and RUP models. As requirements change over time, these items above imply other tasks:
+\begin{enumerate} \addtocounter{enumi}{4}
+\item Change Management for Requirements, Cost, and Schedule
+\item Ensuring Implementation Matches Requirement Features
+\end{enumerate}
+Finally, since accuracy of the budget estimate and the schedule is vital to the success of the plan-and-document process, there is another task not found in BDD:
+\begin{enumerate} \addtocounter{enumi}{6}
+\item Risk Analysis and Management
+\end{enumerate}
+The hope is that by imagining all the risks to the budget and schedule in advance, the project can make plans to avoid or overcome them.
diff --git a/tests/unit/cases/nested_list.md b/tests/unit/cases/nested_list.md
index 101dc46e..0d464907 100644
--- a/tests/unit/cases/nested_list.md
+++ b/tests/unit/cases/nested_list.md
@@ -14,10 +14,10 @@ ch_bdd/code/unmeasurablefeature.rb
* *Relevant.* A user story must have business value to one or more stakeholders. To drill down to the real business value, one technique is to keep asking “Why.” Using as an example a ticket-selling app for a regional theater, suppose the proposal is to add a Facebook linking feature. Here are the “Five Whys” in action with their recursive questions and answers:
1. Why add the Facebook feature? As box office manager, I think more people will go with friends and enjoy the show more.
-1. Why does it matter if they enjoy the show more? I think we will sell more tickets.
-1. Why do you want to sell more tickets? Because then the theater makes more money.
-1. Why does theater want to make more money? We want to make more money so that we don't go out of business.
-1. Why does it matter that theater is in business next year? If not, I have no job.
+2. Why does it matter if they enjoy the show more? I think we will sell more tickets.
+3. Why do you want to sell more tickets? Because then the theater makes more money.
+4. Why does theater want to make more money? We want to make more money so that we don't go out of business.
+5. Why does it matter that theater is in business next year? If not, I have no job.
(We're pretty sure the business value is now apparent to at least one stakeholder!)
* *Timeboxed.* Timeboxing means that you stop developing a story once you've exceeded the time budget. Either you give up, divide the user story into smaller ones, or reschedule what is left according to a new estimate. If dividing looks like it won't help, then you go back to the customers to find the highest value part of the story that you can do quickly. The reason for a time budget per user story is that it is extremely easy to underestimate the length of a software project. Without careful accounting of each iteration, the whole project could be late, and thus fail. Learning to budget a software project is a critical skill, and exceeding a story budget and then refactoring it is one way to acquire that skill.
diff --git a/tests/unit/cases/saas.md b/tests/unit/cases/saas.md
index c9f39bce..845e825f 100644
--- a/tests/unit/cases/saas.md
+++ b/tests/unit/cases/saas.md
@@ -6,18 +6,18 @@ The power of SOA combined with the power of the Internet led to a special case o
1. Since customers do not need to install the application, they don't have to worry whether their hardware is the right brand or fast enough, nor whether they have the correct version of the operating system.
-1. The data associated with the service is generally kept with the service, so customers need not worry about backing it up, losing it due to a local hardware malfunction, or even losing the whole device, such as a phone or tablet.
-1. When a group of users wants to collectively interact with the same data, SaaS is a natural vehicle.
-1. When data is large and/or updated frequently, it may make more sense to centralize data and offer remote access via SaaS.
-1. Only a single copy of the server software runs in a uniform, tightly-controlled hardware and operating system environment selected by the developer, which avoids the compatibility hassles of distributing binaries that must run on wide-ranging computers and operating systems. In addition, developers can test new versions of the application on a small fraction of the real customers temporarily without disturbing most customers. (If the SaaS client runs in a browser, there still are compatibility challenges, which we describe in Chapter chap:arch.)
+2. The data associated with the service is generally kept with the service, so customers need not worry about backing it up, losing it due to a local hardware malfunction, or even losing the whole device, such as a phone or tablet.
+3. When a group of users wants to collectively interact with the same data, SaaS is a natural vehicle.
+4. When data is large and/or updated frequently, it may make more sense to centralize data and offer remote access via SaaS.
+5. Only a single copy of the server software runs in a uniform, tightly-controlled hardware and operating system environment selected by the developer, which avoids the compatibility hassles of distributing binaries that must run on wide-ranging computers and operating systems. In addition, developers can test new versions of the application on a small fraction of the real customers temporarily without disturbing most customers. (If the SaaS client runs in a browser, there still are compatibility challenges, which we describe in Chapter chap:arch.)
|||info
**SaaS: Innovate or Die?** Lest you think the perceived need to improve a successful service is just software engineering paranoia, the most popular search engine used to be AltaVista and the most popular social networking site used to be MySpace.
|||
-1. SaaS companies compete regularly on bringing out new features to help ensure that their customers do not abandon them for a competitor who offers a better service.
-1. Since only developers have a copy of the software, they can upgrade the software and underlying hardware frequently as long as they don't violate the external application program interfaces (API). Moreover, developers don't need to annoy users with the seemingly endless requests for permission to upgrade their applications.
+6. SaaS companies compete regularly on bringing out new features to help ensure that their customers do not abandon them for a competitor who offers a better service.
+7. Since only developers have a copy of the software, they can upgrade the software and underlying hardware frequently as long as they don't violate the external application program interfaces (API). Moreover, developers don't need to annoy users with the seemingly endless requests for permission to upgrade their applications.
@@ -57,11 +57,11 @@ Which of the examples of Google SaaS apps---Search, Maps, News, Gmail, Calendar
While you can argue the mappings, below is our answer. (Note that we cheated and put some apps in multiple categories)
1. No user installation: Documents
-1. Can't lose data: Gmail, Calendar.
-1. Users cooperating: Documents.
-1. Large/changing datasets: Search, Maps, News, and YouTube.
-1. Software centralized in single environment: Search.
-1. No field upgrades when improve app: Documents.
+2. Can't lose data: Gmail, Calendar.
+3. Users cooperating: Documents.
+4. Large/changing datasets: Search, Maps, News, and YouTube.
+5. Software centralized in single environment: Search.
+6. No field upgrades when improve app: Documents.
|||
diff --git a/tests/unit/cases/saas1.md b/tests/unit/cases/saas1.md
index 64b8f96c..86810a10 100644
--- a/tests/unit/cases/saas1.md
+++ b/tests/unit/cases/saas1.md
@@ -47,10 +47,10 @@ An early version of this Plan-and-Document software development process was deve
1. Requirements analysis and specification
-1. Architectural design
-1. Implementation and Integration
-1. Verification
-1. Operation and Maintenance
+2. Architectural design
+3. Implementation and Integration
+4. Verification
+5. Operation and Maintenance
@@ -82,9 +82,9 @@ This observation led to a software development lifecycle developed in the 1980s
1. Determine objectives and constraints of this iteration
-1. Evaluate alternatives and identify and resolve risks
-1. Develop and verify the prototype for this iteration
-1. Plan the next iteration
+2. Evaluate alternatives and identify and resolve risks
+3. Develop and verify the prototype for this iteration
+4. Plan the next iteration
@@ -108,9 +108,9 @@ Like Waterfall and Spiral, RUP has phases:
1. Inception: makes the business case for the software and scopes the project to set the schedule and budget, which is used to judge progress and justify expenditures, and initial assessment of risks to schedule and budget.
-1. Elaboration: works with stakeholders to identify use cases, designs a software architecture, sets the development plan, and builds an initial prototype.
-1. Construction: codes and tests the product, resulting in the first external release.
-1. Transition: moves the product from development to production in the real environment, including customer acceptance testing and user training.
+2. Elaboration: works with stakeholders to identify use cases, designs a software architecture, sets the development plan, and builds an initial prototype.
+3. Construction: codes and tests the product, resulting in the first external release.
+4. Transition: moves the product from development to production in the real environment, including customer acceptance testing and user training.
@@ -121,11 +121,11 @@ In addition to the dynamically changing phases of the project, RUP identifies si
1. Business Modeling
-1. Requirements
-1. Analysis and Design
-1. Implementation
-1. Test
-1. Deployment
+2. Requirements
+3. Analysis and Design
+4. Implementation
+5. Test
+6. Deployment
@@ -167,10 +167,10 @@ The Software Engineering Institute at Carnegie Mellon University proposed the __
1. Initial or Chaotic---undocumented/*ad hoc*/unstable software development.
-1. Repeatable---not following rigorous discipline, but some processes repeatable with consistent results.
-1. Defined---Defined and documented standard processes that improve over time.
-1. Managed---Management can control software development using process metrics, adapting the process to different projects successfully.
-1. Optimizing---Deliberate process optimization improvements as part of management process.
+2. Repeatable---not following rigorous discipline, but some processes repeatable with consistent results.
+3. Defined---Defined and documented standard processes that improve over time.
+4. Managed---Management can control software development using process metrics, adapting the process to different projects successfully.
+5. Optimizing---Deliberate process optimization improvements as part of management process.
CMM implicitly encourages an organization to move up the CMM levels. While not proposed as a software development methodology, many consider it one. For example, (Nawrocki02) compares CMM Level 2 to the Agile software methodology (see next section).
From b2d7220fd380762969a976c93b18b26a27f49971 Mon Sep 17 00:00:00 2001
From: achetporov
Date: Tue, 2 Jun 2020 14:33:42 +0300
Subject: [PATCH 18/39] 11534 some more random tags (#50)
---
converter/markdown/chips.py | 11 +++++++----
converter/markdown/fallacy.py | 1 +
converter/markdown/ignore.py | 14 +++++++++++---
converter/markdown/links.py | 20 ++++++++++----------
converter/markdown/newline.py | 4 +---
converter/markdown/pitfall.py | 1 +
converter/markdown/saas_specific.py | 8 +++++++-
tests/unit/cases/chips.md | 4 +++-
tests/unit/cases/comments.md | 5 -----
tests/unit/cases/dedicationwithpic.md | 4 ++--
tests/unit/cases/href.md | 2 +-
tests/unit/cases/href.tex | 7 ++++++-
tests/unit/cases/href_simple.md | 2 +-
tests/unit/cases/href_simple.tex | 7 ++++++-
tests/unit/cases/html.md | 3 +--
tests/unit/cases/html.tex | 6 +++---
tests/unit/cases/saas1.md | 1 -
tests/unit/cases/tabular.md | 1 -
18 files changed, 61 insertions(+), 40 deletions(-)
diff --git a/converter/markdown/chips.py b/converter/markdown/chips.py
index eb1c370c..6a7affee 100644
--- a/converter/markdown/chips.py
+++ b/converter/markdown/chips.py
@@ -2,8 +2,8 @@
from converter.markdown.text_as_paragraph import TextAsParagraph
-chips_re = re.compile(r"""\\begin{chips}{(?P.*?)}(?P.*?)\\end{chips}""",
- flags=re.DOTALL + re.VERBOSE)
+chips_re = re.compile(r"""\\begin{chips}{(?P.*?)}({(?P[.*?)})?(?P.*?)\\end{chips}""",
+ flags=re.DOTALL)
class Chips(TextAsParagraph):
@@ -11,12 +11,15 @@ def __init__(self, latex_str, caret_token):
super().__init__(latex_str, caret_token)
def make_block(self, matchobj):
+ caret_token = self._caret_token
block_contents = matchobj.group('block_contents')
block_contents = self.to_paragraph(block_contents)
title = matchobj.group('title')
title = self.to_paragraph(title)
- caret_token = self._caret_token
- return f'## {title}{caret_token}{block_contents}{caret_token}'
+ ref = matchobj.group('ref')
+ if ref is not None:
+ return f'## {title}{caret_token}{ref}{caret_token}{caret_token}{block_contents}{caret_token}'
+ return f'## {title}{caret_token}{caret_token}{block_contents}{caret_token}'
def convert(self):
return chips_re.sub(self.make_block, self.str)
diff --git a/converter/markdown/fallacy.py b/converter/markdown/fallacy.py
index 8768595b..6ef567e3 100644
--- a/converter/markdown/fallacy.py
+++ b/converter/markdown/fallacy.py
@@ -13,6 +13,7 @@ def __init__(self, latex_str, caret_token):
def make_block(self, matchobj):
block_contents = matchobj.group('block_contents')
block_contents = self.to_paragraph(block_contents)
+ block_contents = block_contents.replace('\n', ' ')
title = matchobj.group('title')
title = self.to_paragraph(title)
caret_token = self._caret_token
diff --git a/converter/markdown/ignore.py b/converter/markdown/ignore.py
index 5935d381..a073bbc8 100644
--- a/converter/markdown/ignore.py
+++ b/converter/markdown/ignore.py
@@ -22,7 +22,7 @@ def remove_chars(self, output, chars):
ch = output[index]
if ch == '}':
if level == 0:
- output = output[0:pos] + output[index + 1:]
+ output = output[0:pos].strip('\n') + output[index + 1:]
break
else:
level += 1
@@ -37,23 +37,31 @@ def make_block(self, group):
def convert(self):
output = self.str
+ output = re.sub(r"\\index\n{(.*?)}", r"\\index{\1}", output, flags=re.DOTALL)
output = self.remove_chars(output, "\\index{")
output = self.remove_chars(output, "\\label{")
output = self.remove_chars(output, "\\vspace{")
output = re.sub(r"\\noindent", "", output)
output = re.sub(r"\\prereq", "", output)
output = re.sub(r"\\relax", "", output)
+ output = re.sub(r"\\vfill", "", output)
+ output = re.sub(r"\\indent", "", output)
+ output = re.sub(r"\\fallaciesandpitfalls", "", output)
+ output = re.sub(r"\\makebox\[.*?\]{}", "]
", output)
+ output = re.sub(r"\\hspace{.*?}", "", output)
output = re.sub(r"\s\\n\n", "", output)
- output = re.sub(r"\\fbox{(.*?\\end{minipage}\n)}\n", r"\1", output, flags=re.DOTALL + re.VERBOSE)
+ output = re.sub(r"\\fbox{(.*?\\end{minipage}\n)}\n", r"\1", output, flags=re.DOTALL)
output = re.sub(r"\\begin{minipage}{.*?}", "", output)
output = re.sub(r"\\end{minipage}", "", output)
output = re.sub(r"\\begin{textfigure}", "", output)
output = re.sub(r"\\end{textfigure}", "", output)
output = re.sub(r"\\newcommand{.*?}{.*?}", "", output)
- output = re.sub(r"^\\ifhtmloutput.*?(\\begin{tabular}.*?)\\fi", r"\1", output,
+ output = re.sub(r"^\\ifhtmloutput.*?(\\hfill\\begin{tabular}{\|.*?\|}).*?\\fi", r"\1", output,
flags=re.DOTALL + re.MULTILINE)
output = re.sub(r"^\\ifhtmloutput%.*?(\\end{tabular}).*?\\fi", r"\1", output,
flags=re.DOTALL + re.MULTILINE)
+ output = re.sub(r"^\\ifhtmloutput.*?(\\begin{tabular}.*?)\\else(.*?)\\fi", r"\2", output,
+ flags=re.DOTALL + re.MULTILINE)
output = ifhtml_re.sub(self.make_block, output)
output = ifmobile_re.sub(self.make_block, output)
diff --git a/converter/markdown/links.py b/converter/markdown/links.py
index ccf99efb..7fd996bd 100644
--- a/converter/markdown/links.py
+++ b/converter/markdown/links.py
@@ -1,23 +1,23 @@
import re
+def _clean_block(matchobj):
+ block_link = matchobj.group(1)
+ block_name = matchobj.group(2)
+ block_link = re.sub(r"[~]", "", block_link)
+ return f"[{block_name}]({block_link})"
+
+
class Links(object):
def __init__(self, latex_str):
self.str = latex_str
- def _clean_block(self, matchobj):
- block_link = matchobj.group(1)
- block_name = matchobj.group(3)
- block_link = re.sub(r"[~]", "", block_link)
- return f"[{block_name}]({block_link})"
-
def convert(self):
output = self.str
- output = re.sub(r"\\weblink{(.*?)}(.*?)?{(.*?)}", self._clean_block, output, flags=re.DOTALL + re.VERBOSE)
- output = re.sub(r"\\weblink{(.*?)}", r"[\1](\1)", output, flags=re.MULTILINE)
+ output = re.sub(r"\\weblink{(.*?)}\s*?{((.*?\n*.*?)*)}", _clean_block, output)
+ output = re.sub(r"\\weblink{(.*?)}", r"[\1](\1)", output)
output = re.sub(r"\\url{(.*?)}", r"[\1](\1)", output)
- output = re.sub(r"\\href{(.*?)}{(\\[a-z]+)?\s?(.*?)}", r"[\1](\3)", output)
- output = re.sub(r"\\href{(.*?)}`(\\[a-z]+)?\s?(.*?)`", r"[\1](\3)", output)
+ output = re.sub(r"\\href{(.*?)}{(\\[a-z]+)?\s?(.*?)}", r"[\3](\1)", output)
return output
diff --git a/converter/markdown/newline.py b/converter/markdown/newline.py
index 7849ee84..bbd232c7 100644
--- a/converter/markdown/newline.py
+++ b/converter/markdown/newline.py
@@ -8,8 +8,6 @@ def __init__(self, latex_str):
def convert(self):
output = self.str
output = re.sub(r"^\\\\ ", "
", output, flags=re.MULTILINE)
- output = re.sub(r"\\newline ", "
", output, flags=re.MULTILINE)
- output = re.sub(r"\\newline<", "
<", output, flags=re.MULTILINE)
- output = re.sub(r"\\newline$", "
", output, flags=re.MULTILINE)
+ output = re.sub(r"\\newline", "
", output, flags=re.MULTILINE)
return output
diff --git a/converter/markdown/pitfall.py b/converter/markdown/pitfall.py
index 2283f764..bbcb8069 100644
--- a/converter/markdown/pitfall.py
+++ b/converter/markdown/pitfall.py
@@ -13,6 +13,7 @@ def __init__(self, latex_str, caret_token):
def make_block(self, matchobj):
block_contents = matchobj.group('block_contents')
block_contents = self.to_paragraph(block_contents)
+ block_contents = block_contents.replace('\n', ' ')
title = matchobj.group('title')
title = self.to_paragraph(title)
caret_token = self._caret_token
diff --git a/converter/markdown/saas_specific.py b/converter/markdown/saas_specific.py
index e4a42e27..026065eb 100644
--- a/converter/markdown/saas_specific.py
+++ b/converter/markdown/saas_specific.py
@@ -49,10 +49,16 @@ def convert(self):
output = re.sub(r"\\textbar({\})?", r"|", output)
output = re.sub(r"\\hrule", "
", output)
output = re.sub(r"\\hfill", "", output)
- output = re.sub(r"\\small{", r"", output)
+ output = re.sub(r"\\small{(.*?(?=^\}$))}", r"\1", output,
+ flags=re.DOTALL + re.MULTILINE)
+ output = re.sub(r"\\raggedright{(.*?(?=^\}$))}", r"\1", output,
+ flags=re.DOTALL + re.MULTILINE)
output = re.sub(r"\\cline{.*?}", "", output)
+ output = re.sub(r"\\c{(.*?)}", r"\1", output)
output = re.sub(r"vs.\\", "vs.", output)
output = re.sub(r"\.\\\\\*\}", ".}", output)
+ output = re.sub(r"\\/", "", output)
+ output = re.sub(r"\(([a-z])\)", r"( \1 )", output)
output = re.sub(r"__~to~__", r" __to__ ", output)
output = re.sub(r"\\textsection", "$", output)
output = re.sub(r"\\fillinblank{}", "_________", output)
diff --git a/tests/unit/cases/chips.md b/tests/unit/cases/chips.md
index 6147a572..a64c3fc3 100644
--- a/tests/unit/cases/chips.md
+++ b/tests/unit/cases/chips.md
@@ -1,2 +1,4 @@
## ActiveRecord Basics
-{https://github.com/saasbook/hw-activerecord-practice} Although ActiveRecord is part of Rails, the ActiveRecord subsystem can be used outside of Rails apps. In this assignment, you will write various ActiveRecord operations to manipulate a database of (fictional) customers for whom we store names, email addresses, and birthdays. In a typical Rails app, such queries usually appear in the model code, but working on these simple examples will help familiarize you with ActiveRecord's basic features before writing such code yourself
\ No newline at end of file
+https://github.com/saasbook/hw-activerecord-practice
+
+Although ActiveRecord is part of Rails, the ActiveRecord subsystem can be used outside of Rails apps. In this assignment, you will write various ActiveRecord operations to manipulate a database of (fictional) customers for whom we store names, email addresses, and birthdays. In a typical Rails app, such queries usually appear in the model code, but working on these simple examples will help familiarize you with ActiveRecord's basic features before writing such code yourself
diff --git a/tests/unit/cases/comments.md b/tests/unit/cases/comments.md
index abff8f21..6b07c2df 100644
--- a/tests/unit/cases/comments.md
+++ b/tests/unit/cases/comments.md
@@ -3,9 +3,6 @@ Many people (and textbooks) incorrectly refer to `%` as the “modulus operator
The remainder operator looks like a percent sign, but you might find it helpful to think of it as a division sign ($\div$) rotated to the left.
-
-
-
Modular arithmetic turns out to be surprisingly useful. For example, you can check whether one number is divisible by another: if `x % y` is zero, then `x` is divisible by `y`. You can use remainder to “extract” digits from a number: `x % 10` yields the rightmost digit of `x`, and `x % 100` yields the last two digits. And many encryption algorithms use the remainder operator extensively.
@@ -30,8 +27,6 @@ Addition, subtraction, and multiplication all do what you expect, but you might
At this point, you have seen enough Java to write useful programs that solve everyday problems. You can (1) import Java library classes, (2) create a `Scanner`, (3) get input from the keyboard, (4) format output with `printf`, and (5) divide and mod integers. Now we will put everything together in a complete program:
-
-
```code
import java.util.Scanner;
diff --git a/tests/unit/cases/dedicationwithpic.md b/tests/unit/cases/dedicationwithpic.md
index b50a72ec..d681ba55 100644
--- a/tests/unit/cases/dedicationwithpic.md
+++ b/tests/unit/cases/dedicationwithpic.md
@@ -1,3 +1,3 @@
-
+
-David Patterson dedicates this book to his parents and all their descendants:
---To my father David, from whom I inherited inventiveness, athleticism, and the courage to fight for what is right;
---To my mother Lucie, from whom I inherited intelligence, optimism, and my temperament;
---To our sons David and Michael, who are friends, athletic companions, and inspirations for me to be a good man;
---To our daughters-in-law Heather and Zackary, who are smart, funny, and caring mothers to our grandchildren;
---To our grandchildren Andrew, Grace, and Owyn, who give us our chance at immortality (and who helped with marketing for this book);
---To my younger siblings Linda, Don, and Sue, who gave me my first chance to teach;
---To their descendants, who make the Patterson clan both large and fun to be with;
---And to my beautiful and understanding wife Linda, who is my best friend and the love of my life.
\ No newline at end of file
+David Patterson dedicates this book to his parents and all their descendants:
---To my father David, from whom I inherited inventiveness, athleticism, and the courage to fight for what is right;
---To my mother Lucie, from whom I inherited intelligence, optimism, and my temperament;
---To our sons David and Michael, who are friends, athletic companions, and inspirations for me to be a good man;
---To our daughters-in-law Heather and Zackary, who are smart, funny, and caring mothers to our grandchildren;
---To our grandchildren Andrew, Grace, and Owyn, who give us our chance at immortality (and who helped with marketing for this book);
---To my younger siblings Linda, Don, and Sue, who gave me my first chance to teach;
---To their descendants, who make the Patterson clan both large and fun to be with;
---And to my beautiful and understanding wife Linda, who is my best friend and the love of my life.
\ No newline at end of file
diff --git a/tests/unit/cases/href.md b/tests/unit/cases/href.md
index af79e25d..b969236f 100644
--- a/tests/unit/cases/href.md
+++ b/tests/unit/cases/href.md
@@ -1 +1 @@
-If you have additional comments or ideas about the text, please send them to: [mailto:feedback@greenteapress.com](feedback@greenteapress.com).
\ No newline at end of file
+Despite design patterns' popularity as a tool, they have been the subject of some critique; for example, Peter Norvig, currently Google's Director of Research, [has argued](http://www.norvig.com/design-patterns) that some design patterns just compensate for deficiencies in statically-typed programming languages such as C++ and Java
\ No newline at end of file
diff --git a/tests/unit/cases/href.tex b/tests/unit/cases/href.tex
index 4c90b312..74c7ba8f 100644
--- a/tests/unit/cases/href.tex
+++ b/tests/unit/cases/href.tex
@@ -1 +1,6 @@
-If you have additional comments or ideas about the text, please send them to: \href{mailto:feedback@greenteapress.com}{\tt feedback@greenteapress.com}.
+Despite design patterns' popularity as a tool,
+they have been the subject of some critique; for example, Peter
+Norvig, currently Google's Director of Research,
+\href{http://www.norvig.com/design-patterns}{has argued} that some design
+patterns just compensate for deficiencies in statically-typed
+programming languages such as C++ and Java
\ No newline at end of file
diff --git a/tests/unit/cases/href_simple.md b/tests/unit/cases/href_simple.md
index c5a589f6..b969236f 100644
--- a/tests/unit/cases/href_simple.md
+++ b/tests/unit/cases/href_simple.md
@@ -1 +1 @@
-If you have additional comments or ideas about the text, please send them to: [mailto:feedback@greenteapress.com](feedback@greenteapress.com).
+Despite design patterns' popularity as a tool, they have been the subject of some critique; for example, Peter Norvig, currently Google's Director of Research, [has argued](http://www.norvig.com/design-patterns) that some design patterns just compensate for deficiencies in statically-typed programming languages such as C++ and Java
\ No newline at end of file
diff --git a/tests/unit/cases/href_simple.tex b/tests/unit/cases/href_simple.tex
index 80d965e2..74c7ba8f 100644
--- a/tests/unit/cases/href_simple.tex
+++ b/tests/unit/cases/href_simple.tex
@@ -1 +1,6 @@
-If you have additional comments or ideas about the text, please send them to: \href{mailto:feedback@greenteapress.com}{feedback@greenteapress.com}.
+Despite design patterns' popularity as a tool,
+they have been the subject of some critique; for example, Peter
+Norvig, currently Google's Director of Research,
+\href{http://www.norvig.com/design-patterns}{has argued} that some design
+patterns just compensate for deficiencies in statically-typed
+programming languages such as C++ and Java
\ No newline at end of file
diff --git a/tests/unit/cases/html.md b/tests/unit/cases/html.md
index 0cb11ff0..82864b4b 100644
--- a/tests/unit/cases/html.md
+++ b/tests/unit/cases/html.md
@@ -8,7 +8,6 @@ If the Web browser is the universal client, ___HTML___, the HyperText Markup Lan
HTML consists of a hierarchy of nested elements, each of which consists of an opening tag such as **\**, a content part (in some cases), and a closing tag such as **\
**. Most opening tags can also have attributes, as in **$<$a href="http://..."$>$**. Some tags that don't have a content part are self-closing, such as **\
** for a line break that clears both left and right margins.
-
|||info
@@ -18,7 +17,7 @@ The use of angle brackets for tags comes from ___SGML___ (Standard Generalized M
-There is an unfortunate and confusing mess of terminology surrounding the [lineage of HTML](http://www.w3.org/TR/html5/introduction.html#history-1). HTML 5 includes features of both its predecessors (HTML versions 1 through 4) and XHTML (eXtended HyperText Markup Language), which is a subset of ___XML___, an eXtensible Markup Language that can be used both to represent data and to describe other markup languages. Indeed, XML is a common data representation for exchanging information *between* two services in a Service-Oriented Architecture, as we'll see in Chapter chap:tdd when we extend RottenPotatoes to retrieve movie information from a separate movie database service. The differences among the variants of XHTML and HTML are difficult to keep straight, and not all browsers support all versions. Unless otherwise noted, from now on when we say HTML we mean HTML 5, and we will try to avoid using features that aren't widely supported.
+There is an unfortunate and confusing mess of terminology surrounding the [lineage of HTML](http://www.w3.org/TR/html5/introduction.html#history-1) HTML 5 includes features of both its predecessors (HTML versions 1 through 4) and XHTML (eXtended HyperText Markup Language), which is a subset of ___XML___, an eXtensible Markup Language that can be used both to represent data and to describe other markup languages. Indeed, XML is a common data representation for exchanging information *between* two services in a Service-Oriented Architecture, as we'll see in Chapter chap:tdd when we extend RottenPotatoes to retrieve movie information from a separate movie database service. The differences among the variants of XHTML and HTML are difficult to keep straight, and not all browsers support all versions. Unless otherwise noted, from now on when we say HTML we mean HTML 5, and we will try to avoid using features that aren't widely supported.
Of particular interest are the HTML tag attributes **id** and **class**, because they figure heavily into connecting the HTML structure of a page with its visual appearance. The following screencast illustrates the use of Firefox's Web Developer toolbar to quickly identify the ID's and Classes of HTML elements on a page.
diff --git a/tests/unit/cases/html.tex b/tests/unit/cases/html.tex
index b5108b51..d2b7cfe6 100644
--- a/tests/unit/cases/html.tex
+++ b/tests/unit/cases/html.tex
@@ -64,9 +64,9 @@
\index{Standard Generalized Markup Language (SGML)|textit}%
There is an unfortunate and confusing mess of terminology surrounding the
-\weblink{http://www.w3.org/TR/html5/introduction.html\#history-1}%
-{lineage of HTML}. HTML~5\index{HyperText Markup Language (HTML)!HTML 5 features}
-includes features of both its predecessors
+\weblink{http://www.w3.org/TR/html5/introduction.html\#history-1}{lineage of HTML}
+\index{HyperText Markup Language (HTML)!HTML 5 features}
+HTML 5 includes features of both its predecessors
(HTML versions 1 through 4) and XHTML\index{eXtended HyperText Markup Language (XHTML)!HTML 5}
(eXtended HyperText Markup Language)\index{eXtensible Markup Language (XML)!HTML 5},
which is a subset of \w{XML}, an eXtensible Markup Language
diff --git a/tests/unit/cases/saas1.md b/tests/unit/cases/saas1.md
index 86810a10..7ad17444 100644
--- a/tests/unit/cases/saas1.md
+++ b/tests/unit/cases/saas1.md
@@ -2,7 +2,6 @@
-
> If builders built buildings the way programmers wrote programs, then the first woodpecker that came along would destroy civilization.
>
> __Gerald Weinberg, *Weinberg's Second Law*__
diff --git a/tests/unit/cases/tabular.md b/tests/unit/cases/tabular.md
index 94c8cc4a..f7385291 100644
--- a/tests/unit/cases/tabular.md
+++ b/tests/unit/cases/tabular.md
@@ -14,7 +14,6 @@
|**a.lnk:hover**|**a** element with class **lnk**, when hovered over|
-
|**Attribute**|**Example values**|**Attribute**|**Example values**|
|-|-|-|-|
|font-family|**"Times, serif"**|background-color|**red**, **#c2eed6** (RGB values)|
From 08a96613d1d61725a2fb3063fb7d5c46ad9e5545 Mon Sep 17 00:00:00 2001
From: achetporov
Date: Wed, 3 Jun 2020 13:16:52 +0300
Subject: [PATCH 19/39] added ref for num-list items (#52)
---
converter/markdown/refs.py | 6 ++++--
converter/refs.py | 15 ++++++++++++++-
2 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/converter/markdown/refs.py b/converter/markdown/refs.py
index fda627f5..e64256ba 100644
--- a/converter/markdown/refs.py
+++ b/converter/markdown/refs.py
@@ -12,8 +12,10 @@ def __init__(self, latex_str, refs):
def _refs_block(self, matchobj):
ref_name = matchobj.group('ref_name')
- refs = self._refs.get(ref_name, {'ref': ref_name})
- return '{}'.format(refs.get('ref', ''))
+ ref = self._refs.get(ref_name, {'ref': ref_name})
+ if ref.get('item_num') is not None:
+ return '{}'.format(ref.get('item_num', ''))
+ return '{}'.format(ref.get('ref', ''))
def _page_refs_block(self, matchobj):
ref_name = matchobj.group('ref_name')
diff --git a/converter/refs.py b/converter/refs.py
index 618290e5..834d9193 100644
--- a/converter/refs.py
+++ b/converter/refs.py
@@ -112,7 +112,20 @@ def make_refs(toc, chapter_counter_from=1):
}
refs[ref]["ref"] = f'{chapter_counter}.{figs_counter}'
line_break = False
- elif "\\label{" in line:
+ elif "\\begin{enumerate}" in line:
+ items_counter = 0
+ for ln in item.lines:
+ if "\\item" in ln:
+ items_counter += 1
+ result = re.search(r'\\item\\label{(?P[item:.*?)}', ln)
+ if result:
+ ref = result.group('ref')
+ refs[ref] = {
+ 'item_num': items_counter
+ }
+ if "\\end{enumerate}" in ln:
+ items_counter = 0
+ elif "\\label{" in line and not line.startswith("\\item"):
start_pos = line.find("\\label{")
end_pos = line.find("}", start_pos)
label = line[start_pos + 7:end_pos]
From 94f35e156bab1fd14be70c1711b2b0f36a5871ab Mon Sep 17 00:00:00 2001
From: achetporov
Date: Wed, 3 Jun 2020 16:21:27 +0300
Subject: [PATCH 20/39] changed dpi for pdf2image
---
converter/assets.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/converter/assets.py b/converter/assets.py
index a1dbf555..97a8af9f 100644
--- a/converter/assets.py
+++ b/converter/assets.py
@@ -49,7 +49,7 @@ def _convert_assets(config, generate_dir, pdfs_for_convert, convert_from_path, b
dst_folder.mkdir(exist_ok=True, parents=True)
try:
- pages = convert_from_path(pdf_file, 400)
+ pages = convert_from_path(pdf_file, 300)
if pages:
image = Path(pdf.replace('.pdf', '.jpg'))
page = pages[0]
From 9d68e6d002fd76bb5269e9cb933ea9c299c205d5 Mon Sep 17 00:00:00 2001
From: achetporov
Date: Sat, 6 Jun 2020 11:38:51 +0300
Subject: [PATCH 21/39] 11409 fonts (#54)
---
converter/markdown/bold.py | 12 ++++-----
converter/markdown/italic.py | 6 ++---
converter/markdown/saas_specific.py | 5 ++--
tests/unit/cases/T.md | 2 +-
tests/unit/cases/bc.md | 8 +++---
tests/unit/cases/bf_bracket.md | 2 +-
tests/unit/cases/checkyourself_complex.md | 4 +--
tests/unit/cases/comments.md | 2 +-
tests/unit/cases/concepts.md | 2 +-
tests/unit/cases/em_bracket.md | 2 +-
tests/unit/cases/emph.md | 4 +--
tests/unit/cases/enumerate.md | 2 +-
tests/unit/cases/eqnarray.md | 4 +--
tests/unit/cases/html.md | 32 +++++++++++------------
tests/unit/cases/it_bracket.md | 2 +-
tests/unit/cases/ldots.md | 2 +-
tests/unit/cases/makequotation.md | 2 +-
tests/unit/cases/math_runtime.md | 2 +-
tests/unit/cases/nested_list.md | 10 +++----
tests/unit/cases/pitfall.md | 2 +-
tests/unit/cases/saas.md | 4 +--
tests/unit/cases/saas1.md | 6 ++---
tests/unit/cases/saas2.md | 2 +-
tests/unit/cases/screencast.md | 6 ++---
tests/unit/cases/sf_bracket.md | 2 +-
tests/unit/cases/sidebargraphic.md | 2 +-
tests/unit/cases/summary.md | 2 +-
tests/unit/cases/tablefigure.md | 8 +++---
tests/unit/cases/tabular.md | 30 ++++++++++-----------
tests/unit/cases/tabularx.md | 14 +++++-----
tests/unit/cases/textbf.md | 2 +-
tests/unit/cases/w.md | 2 +-
32 files changed, 94 insertions(+), 93 deletions(-)
diff --git a/converter/markdown/bold.py b/converter/markdown/bold.py
index b0a27421..f0ac8615 100644
--- a/converter/markdown/bold.py
+++ b/converter/markdown/bold.py
@@ -9,12 +9,12 @@ def __init__(self, latex_str):
def convert(self):
output = self.str
- output = re.sub(r"\\textbf{(.*?)}", r"**\1**", output, flags=re.DOTALL + re.VERBOSE)
- output = re.sub(r"{\\bf[ ](.*?)}", r"**\1**", output, flags=re.DOTALL + re.VERBOSE)
- output = re.sub(r"{\\sf[ ](.*?)}", r"**\1**", output, flags=re.DOTALL + re.VERBOSE)
+ output = re.sub(r"\\textbf{(.*?)}", r"\1", output, flags=re.DOTALL + re.VERBOSE)
+ output = re.sub(r"{\\bf[ ](.*?)}", r"\1", output, flags=re.DOTALL + re.VERBOSE)
+ output = re.sub(r"{\\sf[ ](.*?)}", r"\1", output, flags=re.DOTALL + re.VERBOSE)
- output = match_block("\\B{", output, lambda match: f"**{match}**")
- output = match_block("\\C{", output, lambda match: f"__{match}__")
- output = match_block("\\T{", output, lambda match: f"**{match}**")
+ output = match_block("\\B{", output, lambda match: f"{match}")
+ output = match_block("\\C{", output, lambda match: f"{match}")
+ output = match_block("\\T{", output, lambda match: f"{match}")
return output
diff --git a/converter/markdown/italic.py b/converter/markdown/italic.py
index 4c019e3c..060c63de 100644
--- a/converter/markdown/italic.py
+++ b/converter/markdown/italic.py
@@ -7,8 +7,8 @@ def __init__(self, latex_str):
def convert(self):
output = self.str
- output = re.sub(r"\\emph{(.*?)}", r"*\1*", output, flags=re.DOTALL + re.VERBOSE)
- output = re.sub(r"{\\em[ ](.*?)}", r"*\1*", output, flags=re.DOTALL + re.VERBOSE)
- output = re.sub(r"{\\it[ ](.*?)}", r"*\1*", output, flags=re.DOTALL + re.VERBOSE)
+ output = re.sub(r"\\emph{(.*?)}", r"\1", output, flags=re.DOTALL)
+ output = re.sub(r"{\\em[ ](.*?)}", r"\1", output, flags=re.DOTALL)
+ output = re.sub(r"{\\it[ ](.*?)}", r"\1", output, flags=re.DOTALL)
return output
diff --git a/converter/markdown/saas_specific.py b/converter/markdown/saas_specific.py
index 026065eb..6502b58d 100644
--- a/converter/markdown/saas_specific.py
+++ b/converter/markdown/saas_specific.py
@@ -43,8 +43,8 @@ def convert(self):
output = re.sub(r"\\\"{(.*?)\}", r"\1", output)
output = re.sub(r"\\spaceship({\})?", r"<=>", output)
output = re.sub(r"\\thinspace({\})?", r" ", output)
- output = re.sub(r"\\tl({\})?", r"\<", output)
- output = re.sub(r"\\tg({\})?", r"\>", output)
+ output = re.sub(r"\\tl({\})?", r"<", output)
+ output = re.sub(r"\\tg({\})?", r">", output)
output = re.sub(r"\\ttil({\})?", r"~", output)
output = re.sub(r"\\textbar({\})?", r"|", output)
output = re.sub(r"\\hrule", "]
", output)
@@ -60,6 +60,7 @@ def convert(self):
output = re.sub(r"\\/", "", output)
output = re.sub(r"\(([a-z])\)", r"( \1 )", output)
output = re.sub(r"__~to~__", r" __to__ ", output)
+ output = re.sub(r"-{}-", r"- - ", output)
output = re.sub(r"\\textsection", "$", output)
output = re.sub(r"\\fillinblank{}", "_________", output)
output = re.sub(r"\\textasciicircum({})?", r"\^", output)
diff --git a/tests/unit/cases/T.md b/tests/unit/cases/T.md
index 5c92f5fb..1601404e 100644
--- a/tests/unit/cases/T.md
+++ b/tests/unit/cases/T.md
@@ -1 +1 @@
-HTTP methods---**GET**, **POST**, **PUT** and **DELETE**---and even use
\ No newline at end of file
+HTTP methods---GET, POST, PUT and DELETE---and even use
\ No newline at end of file
diff --git a/tests/unit/cases/bc.md b/tests/unit/cases/bc.md
index a8940168..17692bff 100644
--- a/tests/unit/cases/bc.md
+++ b/tests/unit/cases/bc.md
@@ -1,11 +1,11 @@
-**Summary of legacy code exploration**
+Summary of legacy code exploration
-__Voucher__
+Voucher
-jQuery defines a global function __jQuery()__ (aliased as __\$()__) that, when passed a CSS selector (examples of which we saw in Figure fig:css_cheat), returns all of the current page's DOM elements matching that selector. For example, __jQuery('#movies')__ or __\$('#movies')__ would return the single element whose ID is **movies**, if one exists on the page; __\$('h1.title')__ would return all the **h1** elements whose CSS class is **title**. A more general version of this functionality is __.find(__*selector*__)__, which only searches the DOM subtree rooted at the target. To illustrate the distinction, __\$('p span')__ finds *any* **span** element that is contained inside a **p** element, whereas if __elt__ already refers to a *particular* **p** element, then __elt.find('span')__ only finds **span** elements that are descendants of __elt__.
+jQuery defines a global function jQuery() (aliased as \$()) that, when passed a CSS selector (examples of which we saw in Figure fig:css_cheat), returns all of the current page's DOM elements matching that selector. For example, jQuery('#movies') or \$('#movies') would return the single element whose ID is movies, if one exists on the page; \$('h1.title') would return all the h1 elements whose CSS class is title. A more general version of this functionality is .find(selector), which only searches the DOM subtree rooted at the target. To illustrate the distinction, \$('p span') finds any span element that is contained inside a p element, whereas if elt already refers to a particular p element, then elt.find('span') only finds span elements that are descendants of elt.
|||info
-The call __jQuery.noConflict()__ “undefines” the __\$__ alias, in case your app uses the browser's built-in __\$__ (usually an alias for __document.-getElementById__) or loads another JavaScript library such as [Prototype](http://prototypejs.org) that also tries to define __\$__.
+The call jQuery.noConflict() “undefines” the \$ alias, in case your app uses the browser's built-in \$ (usually an alias for document.-getElementById) or loads another JavaScript library such as [Prototype](http://prototypejs.org) that also tries to define \$.
|||
diff --git a/tests/unit/cases/bf_bracket.md b/tests/unit/cases/bf_bracket.md
index 735697f2..49f1daf0 100644
--- a/tests/unit/cases/bf_bracket.md
+++ b/tests/unit/cases/bf_bracket.md
@@ -1 +1 @@
-An important skill for a computer scientist is **problem solving**.
\ No newline at end of file
+An important skill for a computer scientist is problem solving.
\ No newline at end of file
diff --git a/tests/unit/cases/checkyourself_complex.md b/tests/unit/cases/checkyourself_complex.md
index 08b7ade1..3aeb3394 100644
--- a/tests/unit/cases/checkyourself_complex.md
+++ b/tests/unit/cases/checkyourself_complex.md
@@ -1,6 +1,6 @@
|||challenge
-Suppose you mix __Enumerable__ into a class __Foo__ that does not provide the __each__ method. What error will be raised when you call __Foo.new.map { |elt| puts elt }__?
+Suppose you mix Enumerable into a class Foo that does not provide the each method. What error will be raised when you call Foo.new.map { |elt| puts elt }?
Check yourself
-The __map__ method in __Enumerable__ will attempt to call __each__ on its receiver, but since the new __Foo__ object doesn't define __each__, Ruby will raise an Undefined Method error.
+The map method in Enumerable will attempt to call each on its receiver, but since the new Foo object doesn't define each, Ruby will raise an Undefined Method error.
|||
\ No newline at end of file
diff --git a/tests/unit/cases/comments.md b/tests/unit/cases/comments.md
index 6b07c2df..3419899f 100644
--- a/tests/unit/cases/comments.md
+++ b/tests/unit/cases/comments.md
@@ -1,4 +1,4 @@
-Many people (and textbooks) incorrectly refer to `%` as the “modulus operator”. In mathematics, however, **modulus** is the number you're dividing by. In the previous example, the modulus is 12. The Java language specification refers to `%` as the “remainder operator”.
+Many people (and textbooks) incorrectly refer to `%` as the “modulus operator”. In mathematics, however, modulus is the number you're dividing by. In the previous example, the modulus is 12. The Java language specification refers to `%` as the “remainder operator”.
The remainder operator looks like a percent sign, but you might find it helpful to think of it as a division sign ($\div$) rotated to the left.
diff --git a/tests/unit/cases/concepts.md b/tests/unit/cases/concepts.md
index 70e334b5..f1b82b8b 100644
--- a/tests/unit/cases/concepts.md
+++ b/tests/unit/cases/concepts.md
@@ -5,6 +5,6 @@ ___JavaScript___ is a dynamic, interpreted scripting language built into modern
* A browser represents a web page as a data structure called the ___Document Object Model___ (DOM). JavaScript code running in the browser can inspect and modify this data structure, causing the browser to redraw the modified page elements.
* When a user interacts with the browser (for example, by typing, clicking, or moving the mouse) or the browser makes progress in an interaction with a server, the browser generates an ___event___ indicating what happened. Your JavaScript code can take app-specific actions to modify the DOM when such events occur.
-* Using ___AJAX___, or Asynchronous JavaScript And XML, JavaScript code can make HTTP requests to a Web server *without* triggering a page reload. The information in the response can then be used to modify page elements in place, giving a richer and often more responsive user experience than traditional Web pages. Rails partials and controller actions can be readily used to handle AJAX interactions.
+* Using ___AJAX___, or Asynchronous JavaScript And XML, JavaScript code can make HTTP requests to a Web server without triggering a page reload. The information in the response can then be used to modify page elements in place, giving a richer and often more responsive user experience than traditional Web pages. Rails partials and controller actions can be readily used to handle AJAX interactions.
* Just as we use the highly-productive Rails framework (Chapter chap:rails_intro) and RSpec TDD tool (Chapter chap:tdd) for server-side SaaS code, here we use the highly-productive ___jQuery___ framework and [Jasmine](http://pivotal.github.com/jasmine) TDD tool to develop client-side code.
* We follow the best practice of “graceful degradation,” also referred to as “progressive enhancement”: legacy browsers lacking JavaScript support will still provide a good user experience, while JavaScript-enabled browsers will provide an even better experience.
diff --git a/tests/unit/cases/em_bracket.md b/tests/unit/cases/em_bracket.md
index 8ab4dd1a..0055b221 100644
--- a/tests/unit/cases/em_bracket.md
+++ b/tests/unit/cases/em_bracket.md
@@ -1 +1 @@
-*One concept at a time.*
\ No newline at end of file
+One concept at a time.
\ No newline at end of file
diff --git a/tests/unit/cases/emph.md b/tests/unit/cases/emph.md
index 2332926a..75288264 100644
--- a/tests/unit/cases/emph.md
+++ b/tests/unit/cases/emph.md
@@ -1,3 +1,3 @@
-and *controllers* that mediate the interaction between views and
+and controllers that mediate the interaction between views and
-*(This book uses sidebars to include what your authors think are interesting asides or short biographies of computing pioneers that supplement the primary text. We hope readers will enjoy them.)*
\ No newline at end of file
+(This book uses sidebars to include what your authors think are interesting asides or short biographies of computing pioneers that supplement the primary text. We hope readers will enjoy them.)
\ No newline at end of file
diff --git a/tests/unit/cases/enumerate.md b/tests/unit/cases/enumerate.md
index 627984d7..cbe75726 100644
--- a/tests/unit/cases/enumerate.md
+++ b/tests/unit/cases/enumerate.md
@@ -4,7 +4,7 @@
-Recall that the hope for plan-and-document methods is to make software engineering as predictable in budget and schedule as civil engineering. Remarkably, user stories, points, and velocity correspond to *seven* major tasks of the plan-and-document methodologies. They include:
+Recall that the hope for plan-and-document methods is to make software engineering as predictable in budget and schedule as civil engineering. Remarkably, user stories, points, and velocity correspond to seven major tasks of the plan-and-document methodologies. They include:
1. Requirements Elicitation
diff --git a/tests/unit/cases/eqnarray.md b/tests/unit/cases/eqnarray.md
index 602a6f21..90e7830e 100644
--- a/tests/unit/cases/eqnarray.md
+++ b/tests/unit/cases/eqnarray.md
@@ -9,12 +9,12 @@ $$
Write a recursive method called `ack` that takes two `int`s as parameters and that computes and returns the value of the Ackermann function.
-For example, the **factorial** of an integer $n$, which is written $n!$, is defined like this:
+For example, the factorial of an integer $n$, which is written $n!$, is defined like this:
$$
0! = 1 \\
n! = n \cdot(n-1)!
$$
-Don't confuse the mathematical symbol $!$, which means *factorial*, with the Java operator `!`, which means *not*.
+Don't confuse the mathematical symbol $!$, which means factorial, with the Java operator `!`, which means not.
$$
\sin \frac{\pi}{4} + \frac{\cos \frac{\pi}{4}}{2} \\
diff --git a/tests/unit/cases/html.md b/tests/unit/cases/html.md
index 82864b4b..4dd2ffff 100644
--- a/tests/unit/cases/html.md
+++ b/tests/unit/cases/html.md
@@ -1,4 +1,4 @@
-In contrast to a native app, which is designed to render a particular user interface associated with only one SaaS service, we can think of a desktop or mobile browser as a *universal client*, because any site the browser visits can deliver all the information necessary to render that site's user interface. Both browsers and native apps are used by millions of people, so we call them *production clients*.
+In contrast to a native app, which is designed to render a particular user interface associated with only one SaaS service, we can think of a desktop or mobile browser as a universal client, because any site the browser visits can deliver all the information necessary to render that site's user interface. Both browsers and native apps are used by millions of people, so we call them production clients.
Indeed, modern practice suggests that even when creating a user-facing SaaS app designed to be used via a browser, we should design the app as a collection of resources accessible via RESTful APIs, but then provide a Web browser-based user interface “on top of” those API calls.
@@ -6,7 +6,7 @@ Indeed, modern practice suggests that even when creating a user-facing SaaS app
If the Web browser is the universal client, ___HTML___, the HyperText Markup Language, is the universal language. A ___markup language___ combines text with markup (annotations about the text) in a way that makes it easy to syntactically distinguish the two.
-HTML consists of a hierarchy of nested elements, each of which consists of an opening tag such as **\**, a content part (in some cases), and a closing tag such as **\
**. Most opening tags can also have attributes, as in **$<$a href="http://..."$>$**. Some tags that don't have a content part are self-closing, such as **\
** for a line break that clears both left and right margins.
+HTML consists of a hierarchy of nested elements, each of which consists of an opening tag such as <p>, a content part (in some cases), and a closing tag such as </p>. Most opening tags can also have attributes, as in $<$a href="http://..."$>$. Some tags that don't have a content part are self-closing, such as <br clear="both"/> for a line break that clears both left and right margins.
@@ -17,10 +17,10 @@ The use of angle brackets for tags comes from ___SGML___ (Standard Generalized M
-There is an unfortunate and confusing mess of terminology surrounding the [lineage of HTML](http://www.w3.org/TR/html5/introduction.html#history-1) HTML 5 includes features of both its predecessors (HTML versions 1 through 4) and XHTML (eXtended HyperText Markup Language), which is a subset of ___XML___, an eXtensible Markup Language that can be used both to represent data and to describe other markup languages. Indeed, XML is a common data representation for exchanging information *between* two services in a Service-Oriented Architecture, as we'll see in Chapter chap:tdd when we extend RottenPotatoes to retrieve movie information from a separate movie database service. The differences among the variants of XHTML and HTML are difficult to keep straight, and not all browsers support all versions. Unless otherwise noted, from now on when we say HTML we mean HTML 5, and we will try to avoid using features that aren't widely supported.
+There is an unfortunate and confusing mess of terminology surrounding the [lineage of HTML](http://www.w3.org/TR/html5/introduction.html#history-1) HTML 5 includes features of both its predecessors (HTML versions 1 through 4) and XHTML (eXtended HyperText Markup Language), which is a subset of ___XML___, an eXtensible Markup Language that can be used both to represent data and to describe other markup languages. Indeed, XML is a common data representation for exchanging information between two services in a Service-Oriented Architecture, as we'll see in Chapter chap:tdd when we extend RottenPotatoes to retrieve movie information from a separate movie database service. The differences among the variants of XHTML and HTML are difficult to keep straight, and not all browsers support all versions. Unless otherwise noted, from now on when we say HTML we mean HTML 5, and we will try to avoid using features that aren't widely supported.
-Of particular interest are the HTML tag attributes **id** and **class**, because they figure heavily into connecting the HTML structure of a page with its visual appearance. The following screencast illustrates the use of Firefox's Web Developer toolbar to quickly identify the ID's and Classes of HTML elements on a page.
+Of particular interest are the HTML tag attributes id and class, because they figure heavily into connecting the HTML structure of a page with its visual appearance. The following screencast illustrates the use of Firefox's Web Developer toolbar to quickly identify the ID's and Classes of HTML elements on a page.
@@ -29,7 +29,7 @@ Of particular interest are the HTML tag attributes **id** and **class**, because
-CSS uses ___selector notations___ such as **div#***name* to indicate a **div** element whose **id** is *name* and **div.***name* to indicate a **div** element with class *name*. Only one element in an HTML document can have a given **id**, whereas many elements (even of different tag types) can share the same **class**. All three aspects of an element---its tag type, its **id** (if it has one), and its **class** attributes (if it has any)---can be used to identify an element as a candidate for visual formatting.
+CSS uses ___selector notations___ such as div#name to indicate a div element whose id is name and div.name to indicate a div element with class name. Only one element in an HTML document can have a given id, whereas many elements (even of different tag types) can share the same class. All three aspects of an element---its tag type, its id (if it has one), and its class attributes (if it has any)---can be used to identify an element as a candidate for visual formatting.
@@ -53,7 +53,7 @@ As the next screencast shows, the ___CSS___ (___Cascading Style Sheets___) stand
-There are four basic mechanisms by which a selector in a CSS file can match an HTML element: by tag name, by class, by ID, and by hierarchy. If multiple selectors match a given element, the rules for which properties to apply are complex, so most designers try to avoid such ambiguities by keeping their CSS simple. A useful way to see the “bones” of a page is to select \Sf{CSS\>-Disable Styles\>-All Styles} from the Firefox Web Developer toolbar; most developer-friendly browsers offer a “developer mode” featuring similar behaviors. Disabling styles will display the page with all CSS formatting turned off, showing the extent to which CSS can be used to separate visual appearance from logical structure.
+There are four basic mechanisms by which a selector in a CSS file can match an HTML element: by tag name, by class, by ID, and by hierarchy. If multiple selectors match a given element, the rules for which properties to apply are complex, so most designers try to avoid such ambiguities by keeping their CSS simple. A useful way to see the “bones” of a page is to select \Sf{CSS>-Disable Styles>-All Styles} from the Firefox Web Developer toolbar; most developer-friendly browsers offer a “developer mode” featuring similar behaviors. Disabling styles will display the page with all CSS formatting turned off, showing the extent to which CSS can be used to separate visual appearance from logical structure.
@@ -61,7 +61,7 @@ There are four basic mechanisms by which a selector in a CSS file can match an H
ch_arch/tables/css_cheat
-**Figure 1.1: A few CSS constructs, including those explained in Screencast css-intro. The top table shows some CSS *selectors*, which identify the elements to be styled; the bottom table shows a few of the many attributes, whose names are usually self-explanatory, and example values they can be assigned. Not all attributes are valid on all elements.
**
+**Figure 1.1: A few CSS constructs, including those explained in Screencast css-intro. The top table shows some CSS selectors, which identify the elements to be styled; the bottom table shows a few of the many attributes, whose names are usually self-explanatory, and example values they can be assigned. Not all attributes are valid on all elements.
**
@@ -88,12 +88,12 @@ SPA vs MPA: Are you building something that's more like a website (transactional
---
-**Summary**
+Summary
-* An ___HTML___ (HyperText Markup Language) document consists of a hierarchically nested collection of elements. Each element begins with a ___tag___ in \ that may have optional ___attributes___. Some elements enclose content.
-* A ___selector___ is an expression that identifies one or more HTML elements in a document by using a combination of the element name (such as **body**), element **id** (an element attribute that must be unique on a page), and element **class** (an attribute that need not be unique on a page).
-* ___Cascading Style Sheets___ (CSS) is a stylesheet language describing visual attributes of elements on a Web page. A stylesheet associates sets of visual properties with selectors. A special **link** element inside the **head** element of an HTML document associates a stylesheet with that document.
+* An ___HTML___ (HyperText Markup Language) document consists of a hierarchically nested collection of elements. Each element begins with a ___tag___ in <angle brackets> that may have optional ___attributes___. Some elements enclose content.
+* A ___selector___ is an expression that identifies one or more HTML elements in a document by using a combination of the element name (such as body), element id (an element attribute that must be unique on a page), and element class (an attribute that need not be unique on a page).
+* ___Cascading Style Sheets___ (CSS) is a stylesheet language describing visual attributes of elements on a Web page. A stylesheet associates sets of visual properties with selectors. A special link element inside the head element of an HTML document associates a stylesheet with that document.
* The “developer tools” in each browser, such as the Firefox Web Developer toolbar, are invaluable in peeking under the hood to examine both the structure of a page and its stylesheets.
@@ -125,19 +125,19 @@ Given the following HTML markup:
```code
ch_arch/code/htmlexercise.html
```
- Write down a CSS selector that will select *only* the word *Mondays* for styling.
+ Write down a CSS selector that will select only the word Mondays for styling.
Check yourself
-Three possibilities, from most specific to least specific, are: __#i span__, __p.x span__, and __.x span__. Other selectors are possible but redundant or over-constrained; for example, __p#i span__ and __p#i.x span__ are redundant with respect to this HTML snippet since at most one element can have the ID __i__.
+Three possibilities, from most specific to least specific, are: #i span, p.x span, and .x span. Other selectors are possible but redundant or over-constrained; for example, p#i span and p#i.x span are redundant with respect to this HTML snippet since at most one element can have the ID i.
|||
|||challenge
-In Self-Check ex:css1, why are __span__ and __p span__ *not* valid answers?
+In Self-Check ex:css1, why are span and p span not valid answers?
Check yourself
-Both of those selector also match *Tuesdays*, which is a __span__ inside a __p__.
+Both of those selector also match Tuesdays, which is a span inside a p.
|||
@@ -146,5 +146,5 @@ Both of those selector also match *Tuesdays*, which is a __span__ inside a __p__
What is the most common way to associate a CSS stylesheet with an HTML or HTML document? (HINT: refer to the earlier screencast example.)
Check yourself
-Within the **HEAD** element of the HTML or HTML document, include a **LINK** element with at least the following three attributes: **REL="STYLESHEET"**, **TYPE="text/css"**, and **HREF="*uri*"**, where ***uri*** is the full or partial URI of the stylesheet. That is, the stylesheet must be accessible as a resource named by a URI.
+Within the HEAD element of the HTML or HTML document, include a LINK element with at least the following three attributes: REL="STYLESHEET", TYPE="text/css", and HREF="uri", where uri is the full or partial URI of the stylesheet. That is, the stylesheet must be accessible as a resource named by a URI.
|||
diff --git a/tests/unit/cases/it_bracket.md b/tests/unit/cases/it_bracket.md
index bdaf5532..0108bc55 100644
--- a/tests/unit/cases/it_bracket.md
+++ b/tests/unit/cases/it_bracket.md
@@ -1 +1 @@
-*Think Java* is an introduction to computer science and programming intended for readers with little or no experience.
\ No newline at end of file
+Think Java is an introduction to computer science and programming intended for readers with little or no experience.
\ No newline at end of file
diff --git a/tests/unit/cases/ldots.md b/tests/unit/cases/ldots.md
index 3517d6cc..8c865326 100644
--- a/tests/unit/cases/ldots.md
+++ b/tests/unit/cases/ldots.md
@@ -1 +1 @@
-Beware of overusing *Then I should not see...*. Because it
\ No newline at end of file
+Beware of overusing Then I should not see.... Because it
\ No newline at end of file
diff --git a/tests/unit/cases/makequotation.md b/tests/unit/cases/makequotation.md
index 5d46d3f3..6c92923b 100644
--- a/tests/unit/cases/makequotation.md
+++ b/tests/unit/cases/makequotation.md
@@ -1,6 +1,6 @@
> It is a pleasure to see a student text that emphasizes the production of real useful software. I also applaud the emphasis on getting results early in the process. Nothing stimulates student morale and activity more.
>
-> __Prof. Frederick P. Brooks, Jr., Turing Award winner and author of *The Mythical Man-Month*__
+> __Prof. Frederick P. Brooks, Jr., Turing Award winner and author of The Mythical Man-Month__
diff --git a/tests/unit/cases/math_runtime.md b/tests/unit/cases/math_runtime.md
index 046b3265..3b94c297 100644
--- a/tests/unit/cases/math_runtime.md
+++ b/tests/unit/cases/math_runtime.md
@@ -6,4 +6,4 @@ On the other hand, if `add` is linear, the total time for $n$ adds would be quad
$ runtime = a + b n + c n^2 $
-With perfect data, we might be able to tell the difference between a straight line and a parabola, but if the measurements are noisy, it can be hard to tell. A better way to interpret noisy measurements is to plot runtime and problem size on a **log-log** scale.
\ No newline at end of file
+With perfect data, we might be able to tell the difference between a straight line and a parabola, but if the measurements are noisy, it can be hard to tell. A better way to interpret noisy measurements is to plot runtime and problem size on a log-log scale.
\ No newline at end of file
diff --git a/tests/unit/cases/nested_list.md b/tests/unit/cases/nested_list.md
index 0d464907..001ae8e8 100644
--- a/tests/unit/cases/nested_list.md
+++ b/tests/unit/cases/nested_list.md
@@ -1,17 +1,17 @@
-* *Specific.* Here are examples of a vague feature paired with a specific version:
+* Specific. Here are examples of a vague feature paired with a specific version:
**source:ch_bdd/code/vaguefeature.rb**
```code
ch_bdd/code/vaguefeature.rb
```
-* *Measurable.* Adding Measurable to Specific means that each story should be testable, which implies that there are known expected results for some good inputs. An example of a pair of an unmeasurable versus measurable feature is
+* Measurable. Adding Measurable to Specific means that each story should be testable, which implies that there are known expected results for some good inputs. An example of a pair of an unmeasurable versus measurable feature is
**source:ch_bdd/code/unmeasurablefeature.rb**
```code
ch_bdd/code/unmeasurablefeature.rb
```
Only the second case can be tested to see if the system fulfills the requirement.
-* *Achievable.* Ideally, you implement the user story in one Agile iteration. If you are getting less than one story per iteration, then they are too big and you need to subdivide these stories into smaller ones. As mentioned above, the tool ___Pivotal Tracker___ measures ___Velocity___, which is the rate of completing stories of varying difficulty.
-* *Relevant.* A user story must have business value to one or more stakeholders. To drill down to the real business value, one technique is to keep asking “Why.” Using as an example a ticket-selling app for a regional theater, suppose the proposal is to add a Facebook linking feature. Here are the “Five Whys” in action with their recursive questions and answers:
+* Achievable. Ideally, you implement the user story in one Agile iteration. If you are getting less than one story per iteration, then they are too big and you need to subdivide these stories into smaller ones. As mentioned above, the tool ___Pivotal Tracker___ measures ___Velocity___, which is the rate of completing stories of varying difficulty.
+* Relevant. A user story must have business value to one or more stakeholders. To drill down to the real business value, one technique is to keep asking “Why.” Using as an example a ticket-selling app for a regional theater, suppose the proposal is to add a Facebook linking feature. Here are the “Five Whys” in action with their recursive questions and answers:
1. Why add the Facebook feature? As box office manager, I think more people will go with friends and enjoy the show more.
2. Why does it matter if they enjoy the show more? I think we will sell more tickets.
@@ -20,4 +20,4 @@ ch_bdd/code/unmeasurablefeature.rb
5. Why does it matter that theater is in business next year? If not, I have no job.
(We're pretty sure the business value is now apparent to at least one stakeholder!)
-* *Timeboxed.* Timeboxing means that you stop developing a story once you've exceeded the time budget. Either you give up, divide the user story into smaller ones, or reschedule what is left according to a new estimate. If dividing looks like it won't help, then you go back to the customers to find the highest value part of the story that you can do quickly. The reason for a time budget per user story is that it is extremely easy to underestimate the length of a software project. Without careful accounting of each iteration, the whole project could be late, and thus fail. Learning to budget a software project is a critical skill, and exceeding a story budget and then refactoring it is one way to acquire that skill.
+* Timeboxed. Timeboxing means that you stop developing a story once you've exceeded the time budget. Either you give up, divide the user story into smaller ones, or reschedule what is left according to a new estimate. If dividing looks like it won't help, then you go back to the customers to find the highest value part of the story that you can do quickly. The reason for a time budget per user story is that it is extremely easy to underestimate the length of a software project. Without careful accounting of each iteration, the whole project could be late, and thus fail. Learning to budget a software project is a critical skill, and exceeding a story budget and then refactoring it is one way to acquire that skill.
diff --git a/tests/unit/cases/pitfall.md b/tests/unit/cases/pitfall.md
index 04b8105a..f94ea463 100644
--- a/tests/unit/cases/pitfall.md
+++ b/tests/unit/cases/pitfall.md
@@ -1,2 +1,2 @@
## Customers who confuse mock-ups with completed features.
-As a developer, this pitfall may seem ridiculous to you. But nontechnical customers sometimes have difficulty distinguishing a highly polished digital mock-up from a working feature! The solution is simple: use paper-and-pencil techniques such as hand-drawn sketches and storyboards to reach agreement with the customer---there can be no doubt that such Lo-Fi mockups represent *proposed* rather than implemented functionality.
\ No newline at end of file
+As a developer, this pitfall may seem ridiculous to you. But nontechnical customers sometimes have difficulty distinguishing a highly polished digital mock-up from a working feature! The solution is simple: use paper-and-pencil techniques such as hand-drawn sketches and storyboards to reach agreement with the customer---there can be no doubt that such Lo-Fi mockups represent proposed rather than implemented functionality.
\ No newline at end of file
diff --git a/tests/unit/cases/saas.md b/tests/unit/cases/saas.md
index 845e825f..87cfd725 100644
--- a/tests/unit/cases/saas.md
+++ b/tests/unit/cases/saas.md
@@ -44,14 +44,14 @@ Note that frequent upgrades of SaaS---due to only having a single copy of the so
---
-**Summary:** ___Software as a Service (SaaS)___ is attractive to both customers and providers because the universal client (the Web browser) makes it easier for customers to use the service and the single version of the software at a centralized site makes it easier for the provider to deliver and improve the service. Given the ability and desire to frequently upgrade SaaS, the Agile software development process is popular for SaaS, and so there are many frameworks to support Agile and SaaS. This book uses Ruby on Rails.
+Summary: ___Software as a Service (SaaS)___ is attractive to both customers and providers because the universal client (the Web browser) makes it easier for customers to use the service and the single version of the software at a centralized site makes it easier for the provider to deliver and improve the service. Given the ability and desire to frequently upgrade SaaS, the Agile software development process is popular for SaaS, and so there are many frameworks to support Agile and SaaS. This book uses Ruby on Rails.
---
|||challenge
-Which of the examples of Google SaaS apps---Search, Maps, News, Gmail, Calendar, YouTube, and Documents---is the *best* match to each of the six arguments given in this section for SaaS, reproduced below.
+Which of the examples of Google SaaS apps---Search, Maps, News, Gmail, Calendar, YouTube, and Documents---is the best match to each of the six arguments given in this section for SaaS, reproduced below.
Check yourself
While you can argue the mappings, below is our answer. (Note that we cheated and put some apps in multiple categories)
diff --git a/tests/unit/cases/saas1.md b/tests/unit/cases/saas1.md
index 7ad17444..3430e209 100644
--- a/tests/unit/cases/saas1.md
+++ b/tests/unit/cases/saas1.md
@@ -4,7 +4,7 @@
> If builders built buildings the way programmers wrote programs, then the first woodpecker that came along would destroy civilization.
>
-> __Gerald Weinberg, *Weinberg's Second Law*__
+> __Gerald Weinberg, Weinberg's Second Law__
@@ -139,7 +139,7 @@ An unfortunate downside to teaching a Plan-and-Document approach is that student
---
-**Summary:** The basic *activities* of software engineering are the same in all the software development process or ___lifecycles___, but their interaction over time relative to product releases differs among the models. The Waterfall lifecycle is characterized by much of the design being done in advance of coding, completing each phase before going on to the next one. The Spiral lifecycle iterates through all the development phases to produce prototypes, but like Waterfall, the customers may only get involved every 6 to 24 months. The more recent Rational Unified Process lifecycle includes phases, iterations, and prototypes, while identifying the people skills needed for the project. All rely on careful planning and thorough documentation, and all measure progress against a plan.
+Summary: The basic activities of software engineering are the same in all the software development process or ___lifecycles___, but their interaction over time relative to product releases differs among the models. The Waterfall lifecycle is characterized by much of the design being done in advance of coding, completing each phase before going on to the next one. The Spiral lifecycle iterates through all the development phases to produce prototypes, but like Waterfall, the customers may only get involved every 6 to 24 months. The more recent Rational Unified Process lifecycle includes phases, iterations, and prototypes, while identifying the people skills needed for the project. All rely on careful planning and thorough documentation, and all measure progress against a plan.
---
@@ -165,7 +165,7 @@ Waterfall phases separate planning (requirements and architectural design) from
The Software Engineering Institute at Carnegie Mellon University proposed the ___Capability Maturity Model___ (CMM) (Paulk05) to evaluate organizations' software-development processes based on Plan-and-Document methodologies. The idea is that by modeling the software development process, an organization can improve them. SEI studies observed five levels of software practice:
-1. Initial or Chaotic---undocumented/*ad hoc*/unstable software development.
+1. Initial or Chaotic---undocumented/ad hoc/unstable software development.
2. Repeatable---not following rigorous discipline, but some processes repeatable with consistent results.
3. Defined---Defined and documented standard processes that improve over time.
4. Managed---Management can control software development using process metrics, adapting the process to different projects successfully.
diff --git a/tests/unit/cases/saas2.md b/tests/unit/cases/saas2.md
index 9d96ef18..eb702e2f 100644
--- a/tests/unit/cases/saas2.md
+++ b/tests/unit/cases/saas2.md
@@ -3,7 +3,7 @@ Thus, we concentrate on Agile in the six software development chapters in Part I
While we now see how to build some software successfully, not all projects are small. We next show how to design software to enable composition into services like Amazon.com.
---
-**Summary:** In contrast to the Plan-and-Document lifecycles, the Agile lifecycle works with customers to continuously add features to working prototypes until the customer is satisfied, allowing customers to change what they want as the project develops. Documentation is primarily through user stories and test cases, and it does not measure progress against a predefined plan. Progress is gauged instead by recording ___velocity___, which essentially is the rate that a project completes features.
+Summary: In contrast to the Plan-and-Document lifecycles, the Agile lifecycle works with customers to continuously add features to working prototypes until the customer is satisfied, allowing customers to change what they want as the project develops. Documentation is primarily through user stories and test cases, and it does not measure progress against a predefined plan. Progress is gauged instead by recording ___velocity___, which essentially is the rate that a project completes features.
---
diff --git a/tests/unit/cases/screencast.md b/tests/unit/cases/screencast.md
index a8965fae..07d4c671 100644
--- a/tests/unit/cases/screencast.md
+++ b/tests/unit/cases/screencast.md
@@ -5,7 +5,7 @@
-CSS uses ___selector notations___ such as **div#***name* to indicate a **div** element whose **id** is *name* and **div.***name* to indicate a **div** element with class *name*. Only one element in an HTML document can have a given **id**, whereas many elements (even of different tag types) can share the same **class**. All three aspects of an element---its tag type, its **id** (if it has one), and its **class** attributes (if it has any)---can be used to identify an element as a candidate for visual formatting.
+CSS uses ___selector notations___ such as div#name to indicate a div element whose id is name and div.name to indicate a div element with class name. Only one element in an HTML document can have a given id, whereas many elements (even of different tag types) can share the same class. All three aspects of an element---its tag type, its id (if it has one), and its class attributes (if it has any)---can be used to identify an element as a candidate for visual formatting.
@@ -17,7 +17,7 @@ CSS uses ___selector notations___ such as **div#***name* to indicate a **div** e
-In a Haml template, lines beginning with **%** expand into the corresponding HTML opening tag, with no closing tag needed since Haml uses indentation to determine structure. Ruby-like hashes following a tag become HTML attributes. Lines \mbox{__--beginning with a dash__} are executed as Ruby code with the result discarded, and lines \mbox{__=beginning with an equals sign__} are executed as Ruby code with the result interpolated into the HTML output.
+In a Haml template, lines beginning with % expand into the corresponding HTML opening tag, with no closing tag needed since Haml uses indentation to determine structure. Ruby-like hashes following a tag become HTML attributes. Lines \mbox{--beginning with a dash} are executed as Ruby code with the result discarded, and lines \mbox{=beginning with an equals sign} are executed as Ruby code with the result interpolated into the HTML output.
@@ -29,6 +29,6 @@ In a Haml template, lines beginning with **%** expand into the corresponding HTM
-CSS uses ___selector notations___ such as **div#***name* to indicate a **div** element whose **id** is *name* and **div.***name* to indicate a **div** element with class *name*. Only one element in an HTML document can have a given **id**, whereas many elements (even of different tag types) can share the same **class**. All three aspects of an element---its tag type, its **id** (if it has one), and its **class** attributes (if it has any)---can be used to identify an element as a candidate for visual formatting.
+CSS uses ___selector notations___ such as div#name to indicate a div element whose id is name and div.name to indicate a div element with class name. Only one element in an HTML document can have a given id, whereas many elements (even of different tag types) can share the same class. All three aspects of an element---its tag type, its id (if it has one), and its class attributes (if it has any)---can be used to identify an element as a candidate for visual formatting.
diff --git a/tests/unit/cases/sf_bracket.md b/tests/unit/cases/sf_bracket.md
index 49f87800..c7b39653 100644
--- a/tests/unit/cases/sf_bracket.md
+++ b/tests/unit/cases/sf_bracket.md
@@ -1 +1 @@
-If you don't want to use Git at all, you can download the code in a ZIP archive using the **Download ZIP** button on the GitHub page
\ No newline at end of file
+If you don't want to use Git at all, you can download the code in a ZIP archive using the Download ZIP button on the GitHub page
\ No newline at end of file
diff --git a/tests/unit/cases/sidebargraphic.md b/tests/unit/cases/sidebargraphic.md
index fb73c2b1..63256a74 100644
--- a/tests/unit/cases/sidebargraphic.md
+++ b/tests/unit/cases/sidebargraphic.md
@@ -9,4 +9,4 @@
-**David Patterson** recently retired from a 40-year career as a Professor of Computer Science at UC Berkeley. In the
+David Patterson recently retired from a 40-year career as a Professor of Computer Science at UC Berkeley. In the
diff --git a/tests/unit/cases/summary.md b/tests/unit/cases/summary.md
index e7ee8795..37a4ad36 100644
--- a/tests/unit/cases/summary.md
+++ b/tests/unit/cases/summary.md
@@ -1,4 +1,4 @@
---
-**Summary:** Following the Agile Manifesto's emphasis on customer cooperation over contracts, an Agile team's notion of “cost estimation” is therefore more about advising the client on what team size can provide the maximum efficiency, following Brooks's Law that there is a point of diminishing returns on team size (see Section sec:bdd_idea_FnP). The Agile team's goal in the scoping process is to identify that point, then ramp the team up to that size over time. Agile companies bid costs for time and materials based on short discussions with external customers. As we shall see in Section sec:BDD_P_and_D, this approach is in sharp contrast with companies that follow plan-and-document processes, which promise customers a set of features for an agreed upon cost by an agreed upon date.
+Summary: Following the Agile Manifesto's emphasis on customer cooperation over contracts, an Agile team's notion of “cost estimation” is therefore more about advising the client on what team size can provide the maximum efficiency, following Brooks's Law that there is a point of diminishing returns on team size (see Section sec:bdd_idea_FnP). The Agile team's goal in the scoping process is to identify that point, then ramp the team up to that size over time. Agile companies bid costs for time and materials based on short discussions with external customers. As we shall see in Section sec:BDD_P_and_D, this approach is in sharp contrast with companies that follow plan-and-document processes, which promise customers a set of features for an agreed upon cost by an agreed upon date.
---
\ No newline at end of file
diff --git a/tests/unit/cases/tablefigure.md b/tests/unit/cases/tablefigure.md
index 04de2267..6943a776 100644
--- a/tests/unit/cases/tablefigure.md
+++ b/tests/unit/cases/tablefigure.md
@@ -1,15 +1,15 @@
-We can therefore say that the expression __3+2__ results in calling __Fixnum#+__ on the receiver __3__.
+We can therefore say that the expression 3+2 results in calling Fixnum#+ on the receiver 3.
file content content
-**Figure 1.1: The first column is Ruby's syntactic sugar for common operations, the second column shows the explicit method call, and the third column shows how to perform the same method call using Ruby's __send__, which accepts either a string or (more idiomatically) a symbol for the method name.
**
+**Figure 1.1: The first column is Ruby's syntactic sugar for common operations, the second column shows the explicit method call, and the third column shows how to perform the same method call using Ruby's send, which accepts either a string or (more idiomatically) a symbol for the method name.
**
file content content
-**Figure 1.2: Comparing Amazon.com and Healthcare.gov during its first three months. (Thorp13) After its stumbling start, the deadline was extended from December 15, 2013 to March 31, 2014, which explains the lower goal in customers per day in December. Note that availability for ACA does *not* include time for “scheduled maintenance,” which Amazon does include (Zients13). The error rate was for significant errors on the forms sent to insurance companies (Horsley13). The site was widely labeled by security experts as insecure, as the developers were under tremendous pressure to get proper functionality, and little attention was paid to security (Harrington13)
**
+**Figure 1.2: Comparing Amazon.com and Healthcare.gov during its first three months. (Thorp13) After its stumbling start, the deadline was extended from December 15, 2013 to March 31, 2014, which explains the lower goal in customers per day in December. Note that availability for ACA does not include time for “scheduled maintenance,” which Amazon does include (Zients13). The error rate was for significant errors on the forms sent to insurance companies (Horsley13). The site was widely labeled by security experts as insecure, as the developers were under tremendous pressure to get proper functionality, and little attention was paid to security (Harrington13)
**
file content content
-**Figure 1.3: Some common Ruby methods on collections. For those that expect a block, the “Block” column shows the number of arguments expected by the block; if blank, the method doesn't expect a block. For example, a call to __sort__, whose block expects 2 arguments, might look like: __c.sort { |a,b| a $<=>$ b }__. These methods all return a new object rather than modifying the receiver, but some methods also have a *destructive* variant ending in __!__, for example __sort!__, that modify their argument in place (and also return the new value). Use destructive methods with extreme care, if at all.
**
+**Figure 1.3: Some common Ruby methods on collections. For those that expect a block, the “Block” column shows the number of arguments expected by the block; if blank, the method doesn't expect a block. For example, a call to sort, whose block expects 2 arguments, might look like: c.sort { |a,b| a $<=>$ b }. These methods all return a new object rather than modifying the receiver, but some methods also have a destructive variant ending in !, for example sort!, that modify their argument in place (and also return the new value). Use destructive methods with extreme care, if at all.
**
diff --git a/tests/unit/cases/tabular.md b/tests/unit/cases/tabular.md
index f7385291..ae41da8d 100644
--- a/tests/unit/cases/tabular.md
+++ b/tests/unit/cases/tabular.md
@@ -3,22 +3,22 @@
|$2^4$|$2^3$|$2^2$|$2^1$|$2^0$|
-|**Selector**|**What is selected**|
+|Selector|What is selected|
|-|-|
-|**h1**|Any **h1** element|
-|**div#message**|The **div** whose ID is **message**|
-|**.red**|Any element with class **red**|
-|**div.red, h1**|The **div** with class **red**, or any **h1**|
-|**div#message h1**|An **h1** element that's a child of (inside of) **div#message**|
-|**a.lnk**|**a** element with class **lnk**|
-|**a.lnk:hover**|**a** element with class **lnk**, when hovered over|
+|h1|Any h1 element|
+|div#message|The div whose ID is message|
+|.red|Any element with class red|
+|div.red, h1|The div with class red, or any h1|
+|div#message h1|An h1 element that's a child of (inside of) div#message|
+|a.lnk|a element with class lnk|
+|a.lnk:hover|a element with class lnk, when hovered over|
-|**Attribute**|**Example values**|**Attribute**|**Example values**|
+|Attribute|Example values|Attribute|Example values|
|-|-|-|-|
-|font-family|**"Times, serif"**|background-color|**red**, **#c2eed6** (RGB values)|
-|font-weight|**bold**|border|**1px solid blue**|
-|font-size|**14pt**, **125%**, **12px**|text-align|**right**|
-|font-style|**italic**|text-decoration|**underline**|
-|color|**black**|vertical-align|**middle**|
-|margin|**4px**|padding|**1cm**|
\ No newline at end of file
+|font-family|"Times, serif"|background-color|red, #c2eed6 (RGB values)|
+|font-weight|bold|border|1px solid blue|
+|font-size|14pt, 125%, 12px|text-align|right|
+|font-style|italic|text-decoration|underline|
+|color|black|vertical-align|middle|
+|margin|4px|padding|1cm|
\ No newline at end of file
diff --git a/tests/unit/cases/tabularx.md b/tests/unit/cases/tabularx.md
index 496d296e..1a397f11 100644
--- a/tests/unit/cases/tabularx.md
+++ b/tests/unit/cases/tabularx.md
@@ -1,13 +1,13 @@
-|**Item**|**3 points**|**2 points**|**1 point**|
+|Item|3 points|2 points|1 point|
|-|-|-|-|
-|**Preparation**|Presentation was rehearsed thoroughly, few hiccups|Presentation is mostly fluid, with the exception of maybe 1 or 2 underprepared people|Sloppy presentation, no clear direction or disorganized|
-|**Customer Need**||Included brief statement of customer problem and scope of project|Not clear what the customer really wanted or what problem the group is trying to solve|
-|**Technical Discussion**|Clearly conveyed some technical details of the app. Discussed a technical challenge in an understandable way|Attempted to talk about technical aspects of app, mostly successfully. Either no technical challenge or not able to clearly convey technical topics|Little or no technical coverage of their app. Implementation details are unclear.|
-|**Customer Interaction**|Clearly describe relationship with customer. Talk about goods, bads, and what was learned|Talked about customer interaction to some extent|Mentioned customer interaction, but no details about the experience|
-|**Development Practices**|Explained clearly their implementation of agile in their iterations. Reflect on what went well and what did not. Had a method to taking on iterations.|Briefly explain development practices. Give an idea of approaches they took to iterations/Agile, but don't reflect on their effectiveness|Doesn't appear they took methodology seriously, and/or no evidence of concrete implementation of agile principles|
+|Preparation|Presentation was rehearsed thoroughly, few hiccups|Presentation is mostly fluid, with the exception of maybe 1 or 2 underprepared people|Sloppy presentation, no clear direction or disorganized|
+|Customer Need||Included brief statement of customer problem and scope of project|Not clear what the customer really wanted or what problem the group is trying to solve|
+|Technical Discussion|Clearly conveyed some technical details of the app. Discussed a technical challenge in an understandable way|Attempted to talk about technical aspects of app, mostly successfully. Either no technical challenge or not able to clearly convey technical topics|Little or no technical coverage of their app. Implementation details are unclear.|
+|Customer Interaction|Clearly describe relationship with customer. Talk about goods, bads, and what was learned|Talked about customer interaction to some extent|Mentioned customer interaction, but no details about the experience|
+|Development Practices|Explained clearly their implementation of agile in their iterations. Reflect on what went well and what did not. Had a method to taking on iterations.|Briefly explain development practices. Give an idea of approaches they took to iterations/Agile, but don't reflect on their effectiveness|Doesn't appear they took methodology seriously, and/or no evidence of concrete implementation of agile principles|
-|**Approach**|**Technologies \& Tools**|**Main Pros**|**Main Cons**||
+|Approach|Technologies \& Tools|Main Pros|Main Cons||
|-|-|-|-|-|
|Responsive or mobile-only Web site|HTML5, CSS, JavaScript; any development environment|Portable across devices, so no need to develop/maintain multiple versions; updates automatically|May not show up in searches; not listed in app stores; may lack access to certain platform hardware features, such as biometrics-based identification||
|Native app|Java (Android) or Objective-C (iOS) with mobile-specific IDE|Best performance; guaranteed access to all platform hardware features|Must rely on users to download and install updates; supporting multiple platforms requires maintaining multiple codebases||
diff --git a/tests/unit/cases/textbf.md b/tests/unit/cases/textbf.md
index 5302c863..f27237db 100644
--- a/tests/unit/cases/textbf.md
+++ b/tests/unit/cases/textbf.md
@@ -1 +1 @@
-**Recursion-1 noX**
\ No newline at end of file
+Recursion-1 noX
\ No newline at end of file
diff --git a/tests/unit/cases/w.md b/tests/unit/cases/w.md
index 67bfaee0..e4c08217 100644
--- a/tests/unit/cases/w.md
+++ b/tests/unit/cases/w.md
@@ -2,4 +2,4 @@ Many SaaS apps, including those based on Rails, follow the ___Model-View-Control
-* Using ___AJAX___, or Asynchronous JavaScript And XML, JavaScript code can make HTTP requests to a Web server *without* triggering a page reload. The information in the response can then be used to modify page elements in place, giving a richer and often more responsive user experience than traditional Web pages. Rails partials and controller actions can be readily used to handle AJAX interactions.
+* Using ___AJAX___, or Asynchronous JavaScript And XML, JavaScript code can make HTTP requests to a Web server without triggering a page reload. The information in the response can then be used to modify page elements in place, giving a richer and often more responsive user experience than traditional Web pages. Rails partials and controller actions can be readily used to handle AJAX interactions.
From ef77dc5d8695515345445bc2d3917022cb2a3c94 Mon Sep 17 00:00:00 2001
From: achetporov
Date: Mon, 8 Jun 2020 10:33:01 +0300
Subject: [PATCH 22/39] Small fixes (#55)
---
converter/markdown/block_matcher.py | 5 +++--
converter/markdown/cleanup.py | 6 +++---
converter/markdown/elaboration.py | 2 +-
converter/markdown/ignore.py | 12 +++++-------
converter/markdown/saas_specific.py | 13 ++++++-------
converter/markdown/sidebar.py | 1 +
tests/unit/cases/comments.md | 5 +++++
tests/unit/cases/html.md | 6 +++++-
tests/unit/cases/saas1.md | 1 +
tests/unit/cases/saas2.md | 1 +
tests/unit/cases/tabular.md | 1 +
11 files changed, 32 insertions(+), 21 deletions(-)
diff --git a/converter/markdown/block_matcher.py b/converter/markdown/block_matcher.py
index 7e32791f..f5b429b0 100644
--- a/converter/markdown/block_matcher.py
+++ b/converter/markdown/block_matcher.py
@@ -4,14 +4,15 @@ def match_block(chars, output, repl_func):
level = 0 if '{' in chars else 1
for index in range(pos + len(chars), len(output), 1):
ch = output[index]
- if ch == '}':
+ prev_char = output[index - 1]
+ if ch == '}' and prev_char != '\\':
if level == 0:
start_position = pos+len(chars) if '{' in chars else output.find("{", pos) + 1
output = output[0:pos] + repl_func(output[start_position:index]) + output[index + 1:]
break
else:
level += 1
- elif ch == '{':
+ elif ch == '{' and prev_char != '\\':
level -= 1
pos = output.find(chars)
return output
diff --git a/converter/markdown/cleanup.py b/converter/markdown/cleanup.py
index 873a62ff..d5f0fef3 100644
--- a/converter/markdown/cleanup.py
+++ b/converter/markdown/cleanup.py
@@ -18,8 +18,8 @@ def convert(self):
output = re.sub(r"\\'{(.*?)}", r"\1́", output)
- output = re.sub(r"(.*?)(~)(.*?)", r"\1 \3", output)
- output = re.sub(r"(~)(.*?)", r" \2", output)
- output = re.sub(r"(.*?)(~)", r"\1 ", output)
+ output = re.sub(r"(.*?)(?:(?", output)
output = re.sub(r"\\hfill", "", output)
- output = re.sub(r"\\small{(.*?(?=^\}$))}", r"\1", output,
- flags=re.DOTALL + re.MULTILINE)
- output = re.sub(r"\\raggedright{(.*?(?=^\}$))}", r"\1", output,
- flags=re.DOTALL + re.MULTILINE)
+ output = re.sub(r"\\small{(?:(.*?)^\s*}(?=\s*\n))", r"\1", output, flags=re.DOTALL + re.MULTILINE)
+ output = re.sub(r"\\raggedright{(.*?(?=^\}$))}", r"\1", output, flags=re.DOTALL + re.MULTILINE)
output = re.sub(r"\\cline{.*?}", "", output)
output = re.sub(r"\\c{(.*?)}", r"\1", output)
output = re.sub(r"vs.\\", "vs.", output)
output = re.sub(r"\.\\\\\*\}", ".}", output)
output = re.sub(r"\\/", "", output)
- output = re.sub(r"\(([a-z])\)", r"( \1 )", output)
+ output = re.sub(r"\\_\\-", r"_", output)
+ output = re.sub(r"\((?:(?![s])([a-z]))\)", r"( \1 )", output)
output = re.sub(r"__~to~__", r" __to__ ", output)
output = re.sub(r"-{}-", r"- - ", output)
output = re.sub(r"\\textsection", "$", output)
diff --git a/converter/markdown/sidebar.py b/converter/markdown/sidebar.py
index ffc419e4..6cf99918 100644
--- a/converter/markdown/sidebar.py
+++ b/converter/markdown/sidebar.py
@@ -55,6 +55,7 @@ def _sidebargraphic_block(self, matchobj):
block_contents = matchobj.group('block_contents')
image = matchobj.group('block_graphics')
block_name = matchobj.group('block_name')
+ block_name = block_name.replace('\n', ' ')
if '.' not in image:
ext = self._detect_asset_ext(image)
diff --git a/tests/unit/cases/comments.md b/tests/unit/cases/comments.md
index 3419899f..2312afa9 100644
--- a/tests/unit/cases/comments.md
+++ b/tests/unit/cases/comments.md
@@ -3,6 +3,9 @@ Many people (and textbooks) incorrectly refer to `%` as the “modulus operator
The remainder operator looks like a percent sign, but you might find it helpful to think of it as a division sign ($\div$) rotated to the left.
+
+
+
Modular arithmetic turns out to be surprisingly useful. For example, you can check whether one number is divisible by another: if `x % y` is zero, then `x` is divisible by `y`. You can use remainder to “extract” digits from a number: `x % 10` yields the rightmost digit of `x`, and `x % 100` yields the last two digits. And many encryption algorithms use the remainder operator extensively.
@@ -27,6 +30,8 @@ Addition, subtraction, and multiplication all do what you expect, but you might
At this point, you have seen enough Java to write useful programs that solve everyday problems. You can (1) import Java library classes, (2) create a `Scanner`, (3) get input from the keyboard, (4) format output with `printf`, and (5) divide and mod integers. Now we will put everything together in a complete program:
+
+
```code
import java.util.Scanner;
diff --git a/tests/unit/cases/html.md b/tests/unit/cases/html.md
index 4dd2ffff..036a069f 100644
--- a/tests/unit/cases/html.md
+++ b/tests/unit/cases/html.md
@@ -8,6 +8,7 @@ If the Web browser is the universal client, ___HTML___, the HyperText Markup Lan
HTML consists of a hierarchy of nested elements, each of which consists of an opening tag such as <p>, a content part (in some cases), and a closing tag such as </p>. Most opening tags can also have attributes, as in $<$a href="http://..."$>$. Some tags that don't have a content part are self-closing, such as <br clear="both"/> for a line break that clears both left and right margins.
+
|||info
@@ -17,7 +18,9 @@ The use of angle brackets for tags comes from ___SGML___ (Standard Generalized M
-There is an unfortunate and confusing mess of terminology surrounding the [lineage of HTML](http://www.w3.org/TR/html5/introduction.html#history-1) HTML 5 includes features of both its predecessors (HTML versions 1 through 4) and XHTML (eXtended HyperText Markup Language), which is a subset of ___XML___, an eXtensible Markup Language that can be used both to represent data and to describe other markup languages. Indeed, XML is a common data representation for exchanging information between two services in a Service-Oriented Architecture, as we'll see in Chapter chap:tdd when we extend RottenPotatoes to retrieve movie information from a separate movie database service. The differences among the variants of XHTML and HTML are difficult to keep straight, and not all browsers support all versions. Unless otherwise noted, from now on when we say HTML we mean HTML 5, and we will try to avoid using features that aren't widely supported.
+There is an unfortunate and confusing mess of terminology surrounding the [lineage of HTML](http://www.w3.org/TR/html5/introduction.html#history-1)
+
+HTML 5 includes features of both its predecessors (HTML versions 1 through 4) and XHTML (eXtended HyperText Markup Language), which is a subset of ___XML___, an eXtensible Markup Language that can be used both to represent data and to describe other markup languages. Indeed, XML is a common data representation for exchanging information between two services in a Service-Oriented Architecture, as we'll see in Chapter chap:tdd when we extend RottenPotatoes to retrieve movie information from a separate movie database service. The differences among the variants of XHTML and HTML are difficult to keep straight, and not all browsers support all versions. Unless otherwise noted, from now on when we say HTML we mean HTML 5, and we will try to avoid using features that aren't widely supported.
Of particular interest are the HTML tag attributes id and class, because they figure heavily into connecting the HTML structure of a page with its visual appearance. The following screencast illustrates the use of Firefox's Web Developer toolbar to quickly identify the ID's and Classes of HTML elements on a page.
@@ -87,6 +90,7 @@ SPA vs MPA: Are you building something that's more like a website (transactional
+
---
Summary
diff --git a/tests/unit/cases/saas1.md b/tests/unit/cases/saas1.md
index 3430e209..235914da 100644
--- a/tests/unit/cases/saas1.md
+++ b/tests/unit/cases/saas1.md
@@ -2,6 +2,7 @@
+
> If builders built buildings the way programmers wrote programs, then the first woodpecker that came along would destroy civilization.
>
> __Gerald Weinberg, Weinberg's Second Law__
diff --git a/tests/unit/cases/saas2.md b/tests/unit/cases/saas2.md
index eb702e2f..a6dd6f21 100644
--- a/tests/unit/cases/saas2.md
+++ b/tests/unit/cases/saas2.md
@@ -18,6 +18,7 @@ False: Both build working but incomplete prototypes that the customer helps eval
## Versions of Agile
There is not just a single Agile lifecycle. We are following ___Extreme Programming___ (XP), which includes one- to two-week iterations, behavior driven design (see Chapter chap:bdd), test-driven development (see Chapter chap:tdd), and pair programming (see Section sec:Pair). Another popular version is ___Scrum___ (see Section sec:Scrum), where self-organizing teams use two- to four-week iterations called ___sprints___, and then regroup to plan the next sprint. A key feature is daily standup meetings to identify and overcome obstacles. While there are multiple roles in the scrum team, the norm is to rotate the roles over time. The ___Kanban___ approach is derived from Toyota's just-in-time manufacturing process, which in this case treats software development as a pipeline. Here the team members have fixed roles, and the goal is to balance the number of team members so that there are no bottlenecks with tasks stacking up waiting for processing. One common feature is a wall of cards that to illustrate the state of all tasks in the pipeline. There are also hybrid lifecycles that try to combine the best of two worlds. For example, ___ScrumBan___ uses the daily meetings and sprints of Scrum but replaces the planning phase with the more dynamic pipeline control of the wall of cards from Kanban.
+
## Reforming Acquisition Regulations
Long before the ACA website, there were calls to reform software acquisition, as in this US National Academies study of the Department of Defense (DOD):
diff --git a/tests/unit/cases/tabular.md b/tests/unit/cases/tabular.md
index ae41da8d..ee3059bf 100644
--- a/tests/unit/cases/tabular.md
+++ b/tests/unit/cases/tabular.md
@@ -14,6 +14,7 @@
|a.lnk:hover|a element with class lnk, when hovered over|
+
|Attribute|Example values|Attribute|Example values|
|-|-|-|-|
|font-family|"Times, serif"|background-color|red, #c2eed6 (RGB values)|
From db0b479b04ac2c380486400b359687b5b0645a04 Mon Sep 17 00:00:00 2001
From: achetporov
Date: Mon, 8 Jun 2020 12:03:17 +0300
Subject: [PATCH 23/39] 11545 book name (#53)
---
converter/convert.py | 2 +-
converter/toc.py | 3 ++-
tests/unit/toc_cases/toc_simple.yml | 1 +
3 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/converter/convert.py b/converter/convert.py
index 936038cb..86a8b02a 100644
--- a/converter/convert.py
+++ b/converter/convert.py
@@ -185,7 +185,7 @@ def prepare_structure(generate_dir):
def make_metadata_items(config):
book = {
- "name": "TODO: book name",
+ "name": config.get("name"),
"children": []
}
metadata = {
diff --git a/converter/toc.py b/converter/toc.py
index 243df6af..82cb772e 100644
--- a/converter/toc.py
+++ b/converter/toc.py
@@ -249,7 +249,8 @@ def get_bookdown_toc(folder, name):
def print_to_yaml(structure, tex, bookdown=False):
file_format = "bookdown: {}".format(tex.name) if bookdown else "tex: {}".format(tex.name)
- yaml_structure = """workspace:
+ yaml_structure = """name: "TODO: book name"
+workspace:
directory: {}
{}
assets:
diff --git a/tests/unit/toc_cases/toc_simple.yml b/tests/unit/toc_cases/toc_simple.yml
index 4fb3b9d7..c68cb8ee 100644
--- a/tests/unit/toc_cases/toc_simple.yml
+++ b/tests/unit/toc_cases/toc_simple.yml
@@ -1,3 +1,4 @@
+name: "TODO: book name"
workspace:
directory: toc_cases
tex: toc_simple.tex
From d4a55152fb418be7e01a26c06edb7e1dbd6482ae Mon Sep 17 00:00:00 2001
From: achetporov
Date: Wed, 10 Jun 2020 15:31:40 +0300
Subject: [PATCH 24/39] fix broken references (looks like sec:ruby:ruby_idioms)
(#56)
---
converter/latex2markdown.py | 2 ++
converter/markdown/cite.py | 22 ++++++++++++----------
converter/markdown/italic.py | 4 +++-
converter/markdown/refs.py | 3 +++
converter/markdown/saas_specific.py | 13 ++++++++++---
converter/markdown/tags.py | 14 ++++++++++++++
converter/refs.py | 8 ++++++++
tests/unit/cases/bc.md | 2 +-
tests/unit/cases/verbatim.md | 4 ++--
9 files changed, 55 insertions(+), 17 deletions(-)
create mode 100644 converter/markdown/tags.py
diff --git a/converter/latex2markdown.py b/converter/latex2markdown.py
index 670f1de4..d1b61da4 100644
--- a/converter/latex2markdown.py
+++ b/converter/latex2markdown.py
@@ -44,6 +44,7 @@
from converter.markdown.screencast import Screencast
from converter.markdown.tabularx import Tabularx
from converter.markdown.tabular import Tabular
+from converter.markdown.tags import Tags
from converter.markdown.unescape import UnEscape
from converter.markdown.turingwinner import TuringWinner
@@ -172,6 +173,7 @@ def _latex_to_markdown(self):
output = Center(output, self._caret_token).convert()
output = UnEscape(output).convert()
+ output = Tags(output).convert()
output = NewLine(output).convert()
# convert all matched % back
diff --git a/converter/markdown/cite.py b/converter/markdown/cite.py
index a5d476c7..991e2962 100644
--- a/converter/markdown/cite.py
+++ b/converter/markdown/cite.py
@@ -9,12 +9,14 @@
bib_re = re.compile(r"""@(?P.*?){(?P[.*?),""", flags=re.DOTALL + re.VERBOSE)
-def clean_title(title):
- title = title.replace("{", "").replace("}", "")
- title = title.replace("\\&", "&")
- title = title.replace("`", "'")
- title = title.replace("---", "-")
- return title
+def clean_text(string):
+ string = string.replace("{", "").replace("}", "")
+ string = string.replace("\\&", "&")
+ string = string.replace("`", "'")
+ string = string.replace("---", "-")
+ string = string.replace("\\", "")
+ string = string.replace("o{}", "o")
+ return string
class Cite(object):
@@ -73,13 +75,13 @@ def get_bib_text(self, ref):
bib_item = Cite._bib_file.get(ref.lower(), {})
if bib_item:
if bib_item.get('title') and bib_item.get('author'):
- author = bib_item.get('author')
- title = clean_title(bib_item.get('title'))
+ author = clean_text(bib_item.get('author'))
+ title = clean_text(bib_item.get('title'))
return f'{author}'
elif bib_item.get('title'):
- return clean_title(bib_item.get('title'))
+ return clean_text(bib_item.get('title'))
elif bib_item.get('author'):
- return bib_item.get('author')
+ return clean_text(bib_item.get('author'))
return ref
def make_block(self, matchobj):
diff --git a/converter/markdown/italic.py b/converter/markdown/italic.py
index 060c63de..3ac98af5 100644
--- a/converter/markdown/italic.py
+++ b/converter/markdown/italic.py
@@ -1,5 +1,7 @@
import re
+from converter.markdown.block_matcher import match_block
+
class Italic(object):
def __init__(self, latex_str):
@@ -7,7 +9,7 @@ def __init__(self, latex_str):
def convert(self):
output = self.str
- output = re.sub(r"\\emph{(.*?)}", r"\1", output, flags=re.DOTALL)
+ output = match_block("\\emph{", output, lambda match: f"{match}")
output = re.sub(r"{\\em[ ](.*?)}", r"\1", output, flags=re.DOTALL)
output = re.sub(r"{\\it[ ](.*?)}", r"\1", output, flags=re.DOTALL)
diff --git a/converter/markdown/refs.py b/converter/markdown/refs.py
index e64256ba..9f26d486 100644
--- a/converter/markdown/refs.py
+++ b/converter/markdown/refs.py
@@ -12,6 +12,9 @@ def __init__(self, latex_str, refs):
def _refs_block(self, matchobj):
ref_name = matchobj.group('ref_name')
+ sec_match = re.search(r'sec:.*?:(.*)', ref_name)
+ if sec_match:
+ ref_name = sec_match.group(1)
ref = self._refs.get(ref_name, {'ref': ref_name})
if ref.get('item_num') is not None:
return '{}'.format(ref.get('item_num', ''))
diff --git a/converter/markdown/saas_specific.py b/converter/markdown/saas_specific.py
index 43dc6ef4..7b717ef5 100644
--- a/converter/markdown/saas_specific.py
+++ b/converter/markdown/saas_specific.py
@@ -36,6 +36,8 @@ def convert(self):
output = re.sub(r"\\putbib", "", output)
output = re.sub(r"\\ig({\})?", "Instructors' Manual", output)
output = re.sub(r"\\js({\})?", "JavaScript", output)
+ output = re.sub(r"\\tl({\})?", r"\\tl", output)
+ output = re.sub(r"\\tg({\})?", r"\\tg", output)
output = re.sub(r"\\slash({\})?", "/", output)
output = re.sub(r"\\ldots({\})?", r"...", output)
output = re.sub(r"\\LaTeX({\})?", r"LaTeX", output)
@@ -43,8 +45,6 @@ def convert(self):
output = re.sub(r"\\\"{(.*?)\}", r"\1", output)
output = re.sub(r"\\spaceship({\})?", r"<=>", output)
output = re.sub(r"\\thinspace({\})?", r" ", output)
- output = re.sub(r"\\tl({\})?", r"<", output)
- output = re.sub(r"\\tg({\})?", r">", output)
output = re.sub(r"\\ttil({\})?", r"\\~", output)
output = re.sub(r"\\textbar({\})?", r"|", output)
output = re.sub(r"\\hrule", "]
", output)
@@ -52,11 +52,18 @@ def convert(self):
output = re.sub(r"\\small{(?:(.*?)^\s*}(?=\s*\n))", r"\1", output, flags=re.DOTALL + re.MULTILINE)
output = re.sub(r"\\raggedright{(.*?(?=^\}$))}", r"\1", output, flags=re.DOTALL + re.MULTILINE)
output = re.sub(r"\\cline{.*?}", "", output)
+ output = re.sub(r"\\bs{}", r"\\", output)
+ output = re.sub(r"==", r"\\=\\=", output)
+ output = re.sub(r"\\o{}", r"o", output)
+ output = re.sub(r"\\v{s}", r"vs", output)
output = re.sub(r"\\c{(.*?)}", r"\1", output)
output = re.sub(r"vs.\\", "vs.", output)
output = re.sub(r"\.\\\\\*\}", ".}", output)
output = re.sub(r"\\/", "", output)
- output = re.sub(r"\\_\\-", r"_", output)
+ output = re.sub(r"\\_\\-", "_", output)
+ output = re.sub(r"\\-\\_", "_", output)
+ output = re.sub(r"\.\\-", ".", output)
+ output = re.sub(r"\\#\\-", "\\#", output)
output = re.sub(r"\((?:(?![s])([a-z]))\)", r"( \1 )", output)
output = re.sub(r"__~to~__", r" __to__ ", output)
output = re.sub(r"-{}-", r"- - ", output)
diff --git a/converter/markdown/tags.py b/converter/markdown/tags.py
new file mode 100644
index 00000000..94b7665f
--- /dev/null
+++ b/converter/markdown/tags.py
@@ -0,0 +1,14 @@
+import re
+
+
+class Tags(object):
+ def __init__(self, latex_str):
+ self.str = latex_str
+
+ def convert(self):
+ output = self.str
+
+ output = re.sub(r"\\tl", r"<", output)
+ output = re.sub(r"\\tg", r">", output)
+
+ return output
diff --git a/converter/refs.py b/converter/refs.py
index 834d9193..6ba49771 100644
--- a/converter/refs.py
+++ b/converter/refs.py
@@ -78,6 +78,14 @@ def make_refs(toc, chapter_counter_from=1):
else:
section_counter += 1
for line in item.lines:
+ if line.startswith("\\sectionfile"):
+ result = re.search(r"\\sectionfile{(?P.*?)}{(?P.*?)}", line)
+ label = result.group("block_path")
+ if label:
+ refs[label] = {
+ 'pageref': item.section_name
+ }
+ refs[label]["ref"] = f'{chapter_counter}.{section_counter}'
if line.startswith("\\begin{figure}"):
figs_counter += 1
is_figure = True
diff --git a/tests/unit/cases/bc.md b/tests/unit/cases/bc.md
index 17692bff..aabcbfac 100644
--- a/tests/unit/cases/bc.md
+++ b/tests/unit/cases/bc.md
@@ -6,6 +6,6 @@ jQuery defines a global function jQuery() (aliased as \$(
|||info
-The call jQuery.noConflict() “undefines” the \$ alias, in case your app uses the browser's built-in \$ (usually an alias for document.-getElementById) or loads another JavaScript library such as [Prototype](http://prototypejs.org) that also tries to define \$.
+The call jQuery.noConflict() “undefines” the \$ alias, in case your app uses the browser's built-in \$ (usually an alias for document.getElementById) or loads another JavaScript library such as [Prototype](http://prototypejs.org) that also tries to define \$.
|||
diff --git a/tests/unit/cases/verbatim.md b/tests/unit/cases/verbatim.md
index bd031650..25b6b3c5 100644
--- a/tests/unit/cases/verbatim.md
+++ b/tests/unit/cases/verbatim.md
@@ -12,9 +12,9 @@ public final class Integer extends Number implements Comparable {
public int compareTo(Integer anotherInteger) {
int thisVal = this.value;
int anotherVal = anotherInteger.value;
- return (thisVal
Date: Tue, 14 Jul 2020 14:49:26 +0300
Subject: [PATCH 25/39] removed extra whitespace in author quotation (#57)
---
converter/markdown/quotation.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/converter/markdown/quotation.py b/converter/markdown/quotation.py
index 7f1383a4..b5b664e8 100644
--- a/converter/markdown/quotation.py
+++ b/converter/markdown/quotation.py
@@ -19,6 +19,7 @@ def convert(self):
end_pos = pos + len(search_str) + 1 + index
end = out[end_pos:]
matches[0] = re.sub(r"\\\\", "
", matches[0])
+ matches[1] = matches[1].strip('~')
out = start + f'{caret_token}> {matches[0]}{caret_token}>' \
f'{caret_token}> __{matches[1]}__{caret_token}{caret_token}' + end
pos = out.find(search_str, end_pos + 1)
From f0766b3f1f71b6aefc81e816aaf3afe57465cf8e Mon Sep 17 00:00:00 2001
From: achetporov
Date: Tue, 14 Jul 2020 14:51:28 +0300
Subject: [PATCH 26/39] changes for sectionfile regex (#58)
---
converter/refs.py | 2 +-
converter/toc.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/converter/refs.py b/converter/refs.py
index 6ba49771..64597ef0 100644
--- a/converter/refs.py
+++ b/converter/refs.py
@@ -79,7 +79,7 @@ def make_refs(toc, chapter_counter_from=1):
section_counter += 1
for line in item.lines:
if line.startswith("\\sectionfile"):
- result = re.search(r"\\sectionfile{(?P.*?)}{(?P.*?)}", line)
+ result = re.search(r"\\sectionfile(\[.*?\])?{(?P.*?)}{(?P.*?)}", line)
label = result.group("block_path")
if label:
refs[label] = {
diff --git a/converter/toc.py b/converter/toc.py
index 82cb772e..291ba189 100644
--- a/converter/toc.py
+++ b/converter/toc.py
@@ -99,7 +99,7 @@ def is_section_file(line):
def get_section_lines(line, tex_folder):
- section_line_re = re.compile(r"""\\sectionfile{(?P.*?)}{(?P.*?)}""")
+ section_line_re = re.compile(r"""\\sectionfile(\[.*?\])?{(?P.*?)}{(?P.*?)}""")
result = section_line_re.search(line)
if result:
file = result.group("block_path")
From 6f27203a7f0ff614bffb5b832e87f32e55ee69d5 Mon Sep 17 00:00:00 2001
From: achetporov
Date: Mon, 20 Jul 2020 10:09:44 +0300
Subject: [PATCH 27/39] clear extra tags
---
converter/markdown/ignore.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/converter/markdown/ignore.py b/converter/markdown/ignore.py
index a86c3f02..d5351061 100644
--- a/converter/markdown/ignore.py
+++ b/converter/markdown/ignore.py
@@ -42,7 +42,8 @@ def convert(self):
output = self.remove_chars(output, "\\label{")
output = self.remove_chars(output, "\\vspace{")
output = re.sub(r"\\noindent", "", output)
- output = re.sub(r"\\prereq", "", output)
+ output = re.sub(r"\\bigconcepts", "", output)
+ output = re.sub(r"\\prereqs?", "", output)
output = re.sub(r"\\relax", "", output)
output = re.sub(r"\\vfill", "", output)
output = re.sub(r"\\indent", "", output)
From 2640c5027b3426191245c2be3dce6a0789160ee3 Mon Sep 17 00:00:00 2001
From: achetporov
Date: Thu, 23 Jul 2020 18:31:47 +0300
Subject: [PATCH 28/39] 11719 some fixes (#59)
---
converter/latex2markdown.py | 2 ++
converter/markdown/ignore.py | 2 --
converter/markdown/lists.py | 1 +
converter/markdown/saas_specific.py | 2 +-
converter/markdown/sidebar.py | 29 ++++++++++-------------------
converter/markdown/textfigure.py | 23 +++++++++++++++++++++++
6 files changed, 37 insertions(+), 22 deletions(-)
create mode 100644 converter/markdown/textfigure.py
diff --git a/converter/latex2markdown.py b/converter/latex2markdown.py
index d1b61da4..36b9403f 100644
--- a/converter/latex2markdown.py
+++ b/converter/latex2markdown.py
@@ -45,6 +45,7 @@
from converter.markdown.tabularx import Tabularx
from converter.markdown.tabular import Tabular
from converter.markdown.tags import Tags
+from converter.markdown.textfigure import Textfigure
from converter.markdown.unescape import UnEscape
from converter.markdown.turingwinner import TuringWinner
@@ -112,6 +113,7 @@ def _latex_to_markdown(self):
self._source_codes.extend(source_codes)
output = re.sub(r"\\%", self._percent_token, output)
output = InlineCodeBlock(output, self._percent_token).convert()
+ output = Textfigure(output, self._caret_token).convert()
# remove comments
output = RemoveComments(output).convert()
diff --git a/converter/markdown/ignore.py b/converter/markdown/ignore.py
index d5351061..009321cd 100644
--- a/converter/markdown/ignore.py
+++ b/converter/markdown/ignore.py
@@ -54,8 +54,6 @@ def convert(self):
output = re.sub(r"\\fbox{(.*?\\end{minipage}\n)}\n", r"\1", output, flags=re.DOTALL)
output = re.sub(r"\\begin{minipage}{.*?}", "", output)
output = re.sub(r"\\end{minipage}", "", output)
- output = re.sub(r"\\begin{textfigure}", "", output)
- output = re.sub(r"\\end{textfigure}", "", output)
output = re.sub(r"\\newcommand{.*?}{.*?}", "", output)
output = re.sub(r"\\ifhtmloutput.*?(\\hfill\\begin{tabular}{\|.*?\|}).*?\\fi", r"\1", output, flags=re.DOTALL)
output = re.sub(r"\\ifhtmloutput%.*?(\\end{tabular}).*?\\fi", r"\1", output, flags=re.DOTALL)
diff --git a/converter/markdown/lists.py b/converter/markdown/lists.py
index 842a78be..962ee9d0 100644
--- a/converter/markdown/lists.py
+++ b/converter/markdown/lists.py
@@ -55,6 +55,7 @@ def _format_list_contents(self, block_name, block_contents, start_number):
for line in block_contents.lstrip().rstrip().split("\\item"):
line = line.lstrip().rstrip()
line = line.replace("\\\\", "
")
+ line = re.sub(r" {4,}", " ", line)
if not line:
continue
diff --git a/converter/markdown/saas_specific.py b/converter/markdown/saas_specific.py
index 7b717ef5..e84366bf 100644
--- a/converter/markdown/saas_specific.py
+++ b/converter/markdown/saas_specific.py
@@ -57,7 +57,7 @@ def convert(self):
output = re.sub(r"\\o{}", r"o", output)
output = re.sub(r"\\v{s}", r"vs", output)
output = re.sub(r"\\c{(.*?)}", r"\1", output)
- output = re.sub(r"vs.\\", "vs.", output)
+ output = re.sub(r"\.\\ ", ". ", output)
output = re.sub(r"\.\\\\\*\}", ".}", output)
output = re.sub(r"\\/", "", output)
output = re.sub(r"\\_\\-", "_", output)
diff --git a/converter/markdown/sidebar.py b/converter/markdown/sidebar.py
index 6cf99918..f85cee3a 100644
--- a/converter/markdown/sidebar.py
+++ b/converter/markdown/sidebar.py
@@ -13,31 +13,21 @@ def __init__(self, latex_str, detect_asset_ext, caret_token):
self._sidebargraphic_re = re.compile(r"""\\begin{sidebargraphic}(\[(?P.*?)])?
{(?P.*?)}(.*?)
- {(?P.*?)}
+ (?:{(?P.*?)})?
(?P.*?)
\\end{sidebargraphic}""", flags=re.DOTALL + re.VERBOSE)
- self._sidebar_re = re.compile(r"""\\begin{sidebar}
- (?P.*?)
- \\end{sidebar}""", flags=re.DOTALL + re.VERBOSE)
+ self._sidebar_re = re.compile(r"""\\begin{sidebar}(\[.*?\])?(?:{(?P.*?)})?
+ (?P.*?)\\end{sidebar}""",
+ flags=re.DOTALL + re.VERBOSE)
def _sidebar_block(self, matchobj):
block_contents = matchobj.group('block_contents')
lines = block_contents.split('\n')
- head = lines[0]
- title = ''
- additional = ''
-
- lines = lines[1:]
-
- matches = re.match(r"(\[.*\])?({.*?\})(.*)?", head)
- if matches:
- title = matches.group(2).strip()
- title = get_text_in_brackets(title).strip('*')
- additional = matches.group(3).strip()
-
- if additional:
- lines.insert(0, additional)
+ title = matchobj.group('title')
+ if title:
+ title = title.replace("\n", " ").strip()
+ title = get_text_in_brackets(title)
lines = map(lambda line: line.strip(), lines)
block_contents = '\n'.join(lines)
@@ -55,7 +45,8 @@ def _sidebargraphic_block(self, matchobj):
block_contents = matchobj.group('block_contents')
image = matchobj.group('block_graphics')
block_name = matchobj.group('block_name')
- block_name = block_name.replace('\n', ' ')
+ if block_name:
+ block_name = block_name.replace('\n', ' ')
if '.' not in image:
ext = self._detect_asset_ext(image)
diff --git a/converter/markdown/textfigure.py b/converter/markdown/textfigure.py
new file mode 100644
index 00000000..e496b4c0
--- /dev/null
+++ b/converter/markdown/textfigure.py
@@ -0,0 +1,23 @@
+import re
+
+from converter.markdown.text_as_paragraph import TextAsParagraph
+
+
+class Textfigure(TextAsParagraph):
+ def __init__(self, latex_str, caret_token):
+ super().__init__(latex_str, caret_token)
+ self.str = latex_str
+ self._textfigure_re = re.compile(r"""\\begin{textfigure}(?P.*?)\\end{textfigure}""",
+ flags=re.DOTALL)
+
+ def _textfigure_block(self, matchobj):
+ block_contents = matchobj.group('block_contents')
+ block_contents = self.to_paragraph(block_contents)
+
+ return f'{block_contents}'
+
+ def convert(self):
+ output = self.str
+ output = self._textfigure_re.sub(self._textfigure_block, output)
+
+ return output
From 319c3b5c50ed5e827660dae3a17989febe3ffe39 Mon Sep 17 00:00:00 2001
From: achetporov
Date: Wed, 16 Sep 2020 11:22:37 +0300
Subject: [PATCH 29/39] added escaping for specific chars (#67)
---
converter/markdown/saas_specific.py | 1 +
requirements.txt | 6 +++---
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/converter/markdown/saas_specific.py b/converter/markdown/saas_specific.py
index e84366bf..ce6ff93c 100644
--- a/converter/markdown/saas_specific.py
+++ b/converter/markdown/saas_specific.py
@@ -67,6 +67,7 @@ def convert(self):
output = re.sub(r"\((?:(?![s])([a-z]))\)", r"( \1 )", output)
output = re.sub(r"__~to~__", r" __to__ ", output)
output = re.sub(r"-{}-", r"- - ", output)
+ output = re.sub(r"\[\]\((.*?)\)", r"[\\](\1)", output)
output = re.sub(r"\\textsection", "$", output)
output = re.sub(r"\\fillinblank{}", "_________", output)
output = re.sub(r"\\textasciicircum({})?", r"\^", output)
diff --git a/requirements.txt b/requirements.txt
index 73af3c7b..976dea9e 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,3 +1,3 @@
-pdf2image==1.4.1
-PyYAML==4.2b1
-Pillow==5.4.0
+pdf2image==1.13.1
+Pillow==7.2.0
+PyYAML==5.3.1
\ No newline at end of file
From f14780b6ebf5103433569b2dca14f42aed85cf2f Mon Sep 17 00:00:00 2001
From: achetporov
Date: Wed, 16 Sep 2020 18:04:19 +0300
Subject: [PATCH 30/39] fix \small
---
converter/markdown/saas_specific.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/converter/markdown/saas_specific.py b/converter/markdown/saas_specific.py
index ce6ff93c..ebda6330 100644
--- a/converter/markdown/saas_specific.py
+++ b/converter/markdown/saas_specific.py
@@ -49,7 +49,7 @@ def convert(self):
output = re.sub(r"\\textbar({\})?", r"|", output)
output = re.sub(r"\\hrule", "
", output)
output = re.sub(r"\\hfill", "", output)
- output = re.sub(r"\\small{(?:(.*?)^\s*}(?=\s*\n))", r"\1", output, flags=re.DOTALL + re.MULTILINE)
+ output = re.sub(r"(?:{\\small|\\small{)(?:(.*?)^\s*}(?=\s*\n))", r"\1", output, flags=re.DOTALL + re.MULTILINE)
output = re.sub(r"\\raggedright{(.*?(?=^\}$))}", r"\1", output, flags=re.DOTALL + re.MULTILINE)
output = re.sub(r"\\cline{.*?}", "", output)
output = re.sub(r"\\bs{}", r"\\", output)
From 3f89eb7274751c662849faf47fe11bcbd128c634 Mon Sep 17 00:00:00 2001
From: achetporov
Date: Fri, 18 Sep 2020 15:48:26 +0300
Subject: [PATCH 31/39] replace \index{} (#60)
---
converter/markdown/ignore.py | 8 +++++---
converter/markdown/saas_specific.py | 1 +
converter/markdown/sidebar.py | 3 ++-
converter/toc.py | 1 +
tests/unit/cases/comments.md | 3 ---
tests/unit/cases/html.md | 5 +----
6 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/converter/markdown/ignore.py b/converter/markdown/ignore.py
index 009321cd..a88f08ba 100644
--- a/converter/markdown/ignore.py
+++ b/converter/markdown/ignore.py
@@ -22,7 +22,7 @@ def remove_chars(self, output, chars):
ch = output[index]
if ch == '}':
if level == 0:
- output = output[0:pos].lstrip('\n') + output[index + 1:]
+ output = output[0:pos] + output[index + 1:]
break
else:
level += 1
@@ -37,10 +37,12 @@ def make_block(self, group):
def convert(self):
output = self.str
- output = re.sub(r"\\index\n{(.*?)}", r"\\index{\1}", output, flags=re.DOTALL)
- output = self.remove_chars(output, "\\index{")
output = self.remove_chars(output, "\\label{")
output = self.remove_chars(output, "\\vspace{")
+ output = re.sub(r"\\textit{.*?}", "", output)
+ output = re.sub(r"\\index\n{(.*?)}", r"\\index{\1}", output, flags=re.DOTALL)
+ output = re.sub(r"\n? *\\index{.*?\n?.*?}%", "", output)
+ output = re.sub(r"(?![ ])\n? *\\index{.*?\n?.*?}", "", output)
output = re.sub(r"\\noindent", "", output)
output = re.sub(r"\\bigconcepts", "", output)
output = re.sub(r"\\prereqs?", "", output)
diff --git a/converter/markdown/saas_specific.py b/converter/markdown/saas_specific.py
index ebda6330..a41cf3f3 100644
--- a/converter/markdown/saas_specific.py
+++ b/converter/markdown/saas_specific.py
@@ -68,6 +68,7 @@ def convert(self):
output = re.sub(r"__~to~__", r" __to__ ", output)
output = re.sub(r"-{}-", r"- - ", output)
output = re.sub(r"\[\]\((.*?)\)", r"[\\](\1)", output)
+ output = re.sub(r"{(name_with_rating)}", r"\1", output)
output = re.sub(r"\\textsection", "$", output)
output = re.sub(r"\\fillinblank{}", "_________", output)
output = re.sub(r"\\textasciicircum({})?", r"\^", output)
diff --git a/converter/markdown/sidebar.py b/converter/markdown/sidebar.py
index f85cee3a..644d7b98 100644
--- a/converter/markdown/sidebar.py
+++ b/converter/markdown/sidebar.py
@@ -12,7 +12,7 @@ def __init__(self, latex_str, detect_asset_ext, caret_token):
self._pdfs = []
self._sidebargraphic_re = re.compile(r"""\\begin{sidebargraphic}(\[(?P.*?)])?
- {(?P.*?)}(.*?)
+ {(?P.*?)}(?:%?[]*\n[ ]*)?
(?:{(?P.*?)})?
(?P.*?)
\\end{sidebargraphic}""", flags=re.DOTALL + re.VERBOSE)
@@ -32,6 +32,7 @@ def _sidebar_block(self, matchobj):
lines = map(lambda line: line.strip(), lines)
block_contents = '\n'.join(lines)
block_contents = self.to_paragraph(block_contents)
+ block_contents = block_contents.replace("\n", " ")
caret_token = self._caret_token
if title:
diff --git a/converter/toc.py b/converter/toc.py
index 291ba189..18ba17f2 100644
--- a/converter/toc.py
+++ b/converter/toc.py
@@ -64,6 +64,7 @@ def convert_name(name):
name = re.sub("``", "“", name)
name = re.sub("''", "”", name)
name = re.sub(r"--", "-", name)
+ name = re.sub(r" vs.\\", " vs.", name)
return name
diff --git a/tests/unit/cases/comments.md b/tests/unit/cases/comments.md
index 2312afa9..dc2d670a 100644
--- a/tests/unit/cases/comments.md
+++ b/tests/unit/cases/comments.md
@@ -4,8 +4,6 @@ The remainder operator looks like a percent sign, but you might find it helpful
-
-
Modular arithmetic turns out to be surprisingly useful. For example, you can check whether one number is divisible by another: if `x % y` is zero, then `x` is divisible by `y`. You can use remainder to “extract” digits from a number: `x % 10` yields the rightmost digit of `x`, and `x % 100` yields the last two digits. And many encryption algorithms use the remainder operator extensively.
@@ -31,7 +29,6 @@ At this point, you have seen enough Java to write useful programs that solve eve
-
```code
import java.util.Scanner;
diff --git a/tests/unit/cases/html.md b/tests/unit/cases/html.md
index 036a069f..ebf28f35 100644
--- a/tests/unit/cases/html.md
+++ b/tests/unit/cases/html.md
@@ -8,7 +8,6 @@ If the Web browser is the universal client, ___HTML___, the HyperText Markup Lan
HTML consists of a hierarchy of nested elements, each of which consists of an opening tag such as <p>, a content part (in some cases), and a closing tag such as </p>. Most opening tags can also have attributes, as in $<$a href="http://..."$>$. Some tags that don't have a content part are self-closing, such as <br clear="both"/> for a line break that clears both left and right margins.
-
|||info
@@ -18,9 +17,7 @@ The use of angle brackets for tags comes from ___SGML___ (Standard Generalized M
-There is an unfortunate and confusing mess of terminology surrounding the [lineage of HTML](http://www.w3.org/TR/html5/introduction.html#history-1)
-
-HTML 5 includes features of both its predecessors (HTML versions 1 through 4) and XHTML (eXtended HyperText Markup Language), which is a subset of ___XML___, an eXtensible Markup Language that can be used both to represent data and to describe other markup languages. Indeed, XML is a common data representation for exchanging information between two services in a Service-Oriented Architecture, as we'll see in Chapter chap:tdd when we extend RottenPotatoes to retrieve movie information from a separate movie database service. The differences among the variants of XHTML and HTML are difficult to keep straight, and not all browsers support all versions. Unless otherwise noted, from now on when we say HTML we mean HTML 5, and we will try to avoid using features that aren't widely supported.
+There is an unfortunate and confusing mess of terminology surrounding the [lineage of HTML](http://www.w3.org/TR/html5/introduction.html#history-1) HTML 5 includes features of both its predecessors (HTML versions 1 through 4) and XHTML (eXtended HyperText Markup Language), which is a subset of ___XML___, an eXtensible Markup Language that can be used both to represent data and to describe other markup languages. Indeed, XML is a common data representation for exchanging information between two services in a Service-Oriented Architecture, as we'll see in Chapter chap:tdd when we extend RottenPotatoes to retrieve movie information from a separate movie database service. The differences among the variants of XHTML and HTML are difficult to keep straight, and not all browsers support all versions. Unless otherwise noted, from now on when we say HTML we mean HTML 5, and we will try to avoid using features that aren't widely supported.
Of particular interest are the HTML tag attributes id and class, because they figure heavily into connecting the HTML structure of a page with its visual appearance. The following screencast illustrates the use of Firefox's Web Developer toolbar to quickly identify the ID's and Classes of HTML elements on a page.
From beafd77c63200ca3ec5f48564d5efc44adf30b1a Mon Sep 17 00:00:00 2001
From: achetporov
Date: Tue, 20 Oct 2020 10:24:25 +0300
Subject: [PATCH 32/39] fixed some specific cases (#70)
---
converter/markdown/checkyourself.py | 2 +-
converter/markdown/figure.py | 2 +-
converter/markdown/saas_specific.py | 2 ++
converter/toc.py | 20 ++++++++++++++++++++
tests/unit/cases/checkyourself.md | 1 +
tests/unit/cases/checkyourself_complex.md | 1 +
tests/unit/cases/html.md | 4 ++++
tests/unit/cases/saas.md | 2 ++
tests/unit/cases/saas1.md | 2 ++
tests/unit/cases/saas2.md | 1 +
10 files changed, 35 insertions(+), 2 deletions(-)
diff --git a/converter/markdown/checkyourself.py b/converter/markdown/checkyourself.py
index 7bdb9e27..d993b5b2 100644
--- a/converter/markdown/checkyourself.py
+++ b/converter/markdown/checkyourself.py
@@ -29,7 +29,7 @@ def make_block(self, matchobj):
caret_token = self._caret_token
answer_str = re.sub(r"\\{", r"{", answer_str)
answer_str = re.sub(r"\\}", r"}", answer_str)
- return f'{caret_token}|||challenge{caret_token}{answer_str}{caret_token}|||{caret_token}'
+ return f'{caret_token}|||challenge{caret_token}{answer_str}{caret_token}{caret_token}|||{caret_token}'
def convert(self):
return checkyourself_re.sub(self.make_block, self.str)
diff --git a/converter/markdown/figure.py b/converter/markdown/figure.py
index 7986b66c..4eb91e4b 100644
--- a/converter/markdown/figure.py
+++ b/converter/markdown/figure.py
@@ -68,7 +68,7 @@ def _figure_block(self, matchobj):
block_contents = block_contents.replace('\\label{.*?}', '')
block_contents = re.sub(r"\\caption{(.*?)}", r"", block_contents, flags=re.DOTALL + re.VERBOSE)
- return f'{block_contents}**{caption}
**{caret_token}'
+ return f'{block_contents}{caret_token}**{caption}
**{caret_token}'
def convert(self):
output = self.str
diff --git a/converter/markdown/saas_specific.py b/converter/markdown/saas_specific.py
index a41cf3f3..1de895c5 100644
--- a/converter/markdown/saas_specific.py
+++ b/converter/markdown/saas_specific.py
@@ -51,6 +51,8 @@ def convert(self):
output = re.sub(r"\\hfill", "", output)
output = re.sub(r"(?:{\\small|\\small{)(?:(.*?)^\s*}(?=\s*\n))", r"\1", output, flags=re.DOTALL + re.MULTILINE)
output = re.sub(r"\\raggedright{(.*?(?=^\}$))}", r"\1", output, flags=re.DOTALL + re.MULTILINE)
+ output = re.sub(r"\\Beta{.*?}", "", output, flags=re.DOTALL)
+ output = re.sub(r"\\times{}", r"\\times", output)
output = re.sub(r"\\cline{.*?}", "", output)
output = re.sub(r"\\bs{}", r"\\", output)
output = re.sub(r"==", r"\\=\\=", output)
diff --git a/converter/toc.py b/converter/toc.py
index 18ba17f2..a556ce61 100644
--- a/converter/toc.py
+++ b/converter/toc.py
@@ -116,6 +116,25 @@ def get_section_lines(line, tex_folder):
return []
+def cleanup_ifoddpage(lines):
+ updated = []
+ ifoddpage = False
+ for line in lines:
+ if "\\checkoddpage" in line:
+ continue
+ if ifoddpage and "\\fi" in line:
+ ifoddpage = False
+ continue
+ if ifoddpage:
+ continue
+ if "\\ifoddpage{" in line:
+ line = re.sub(r"\\ifoddpage{\\small(\\input{.*?})}", r"\1", line, flags=re.DOTALL)
+ line = line.strip()
+ ifoddpage = True
+ updated.append(line)
+ return updated
+
+
def process_toc_lines(lines, tex_folder, parent_folder):
toc = []
line_pos = 1
@@ -145,6 +164,7 @@ def process_toc_lines(lines, tex_folder, parent_folder):
toc.append(SectionItem(section_name=section_name, section_type=section_type, line_pos=line_pos))
if is_section_file(line):
section_lines = get_section_lines(line, parent_folder)
+ section_lines = cleanup_ifoddpage(section_lines)
for sub_line in section_lines:
if is_input(sub_line):
sub_content = get_include_lines(tex_folder, input_file(sub_line))
diff --git a/tests/unit/cases/checkyourself.md b/tests/unit/cases/checkyourself.md
index 87d8a9cd..89b20505 100644
--- a/tests/unit/cases/checkyourself.md
+++ b/tests/unit/cases/checkyourself.md
@@ -3,4 +3,5 @@ True or False: User stories on 3x5 cards in BDD play the same role as design req
Check yourself
True.
+
|||
\ No newline at end of file
diff --git a/tests/unit/cases/checkyourself_complex.md b/tests/unit/cases/checkyourself_complex.md
index 3aeb3394..77169fe5 100644
--- a/tests/unit/cases/checkyourself_complex.md
+++ b/tests/unit/cases/checkyourself_complex.md
@@ -3,4 +3,5 @@ Suppose you mix Enumerable into a class Foo that does not provide
Check yourself
The map method in Enumerable will attempt to call each on its receiver, but since the new Foo object doesn't define each, Ruby will raise an Undefined Method error.
+
|||
\ No newline at end of file
diff --git a/tests/unit/cases/html.md b/tests/unit/cases/html.md
index ebf28f35..9dc87c52 100644
--- a/tests/unit/cases/html.md
+++ b/tests/unit/cases/html.md
@@ -108,6 +108,7 @@ True or false: every HTML element must have an ID.
Check yourself
False---the ID is optional, though must be unique if provided.
+
|||
@@ -130,6 +131,7 @@ ch_arch/code/htmlexercise.html
Check yourself
Three possibilities, from most specific to least specific, are: #i span, p.x span, and .x span. Other selectors are possible but redundant or over-constrained; for example, p#i span and p#i.x span are redundant with respect to this HTML snippet since at most one element can have the ID i.
+
|||
@@ -139,6 +141,7 @@ In Self-Check ex:css1, why are span and p span not valid a
Check yourself
Both of those selector also match Tuesdays, which is a span inside a p.
+
|||
@@ -148,4 +151,5 @@ What is the most common way to associate a CSS stylesheet with an HTML or HTML d
Check yourself
Within the HEAD element of the HTML or HTML document, include a LINK element with at least the following three attributes: REL="STYLESHEET", TYPE="text/css", and HREF="uri", where uri is the full or partial URI of the stylesheet. That is, the stylesheet must be accessible as a resource named by a URI.
+
|||
diff --git a/tests/unit/cases/saas.md b/tests/unit/cases/saas.md
index 87cfd725..784b91ce 100644
--- a/tests/unit/cases/saas.md
+++ b/tests/unit/cases/saas.md
@@ -64,6 +64,7 @@ While you can argue the mappings, below is our answer. (Note that we cheated and
6. No field upgrades when improve app: Documents.
+
|||
@@ -73,6 +74,7 @@ True or False: If you are using the Agile development process to develop SaaS ap
Check yourself
True. Programming frameworks for Agile and SaaS include Django and ASP.NET.
+
|||
diff --git a/tests/unit/cases/saas1.md b/tests/unit/cases/saas1.md
index 235914da..7cf742df 100644
--- a/tests/unit/cases/saas1.md
+++ b/tests/unit/cases/saas1.md
@@ -151,6 +151,7 @@ What are a major similarity and a major difference between processes like Spiral
Check yourself
All rely on planning and documentation, but Spiral and RUP use iteration and prototypes to improve them over time versus a single long path to the product.
+
|||
@@ -160,6 +161,7 @@ What are the differences between the phases of these Plan-and-Document processes
Check yourself
Waterfall phases separate planning (requirements and architectural design) from implementation. Testing the product before release is next, followed by a separate operations phase. The Spiral phases are aimed at an iteration: set the goals for an iteration; explore alternatives; develop and verify the prototype for this iteration; and plan the next iteration. RUP phases are tied closer to business objectives: inception makes business case and sets schedule and budget; elaboration works with customers to build an initial prototype; construction builds and test the first version; and transition deploys the product.
+
|||
## SEI Capability Maturity Model (CMM)
diff --git a/tests/unit/cases/saas2.md b/tests/unit/cases/saas2.md
index a6dd6f21..dc6a5d47 100644
--- a/tests/unit/cases/saas2.md
+++ b/tests/unit/cases/saas2.md
@@ -14,6 +14,7 @@ True or False: A big difference between Spiral and Agile development is building
Check yourself
False: Both build working but incomplete prototypes that the customer helps evaluate. The difference is that customers are involved every two weeks in Agile versus up to two years in with Spiral.
+
|||
## Versions of Agile
From 6319ab587e62cacd9f8883a92f719486ac1c778c Mon Sep 17 00:00:00 2001
From: achetporov
Date: Mon, 30 Nov 2020 16:23:26 +0300
Subject: [PATCH 33/39] 12023 broken figure num (#71)
---
converter/latex2markdown.py | 5 ++++-
converter/markdown/checkyourself.py | 1 +
converter/markdown/figure.py | 14 ++++++++++++--
converter/markdown/ignore.py | 1 -
tests/unit/cases/saas1.md | 2 --
tests/unit/test_render_markdown.py | 2 +-
6 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/converter/latex2markdown.py b/converter/latex2markdown.py
index 36b9403f..ffc2e125 100644
--- a/converter/latex2markdown.py
+++ b/converter/latex2markdown.py
@@ -145,7 +145,8 @@ def _latex_to_markdown(self):
if images:
self._pdfs.extend(images)
output, images, figure_counter = Figure(
- output, self._figure_counter_offset, self._chapter_num, self._detect_asset_ext, self._caret_token
+ output, self._figure_counter_offset, self._chapter_num, self._detect_asset_ext,
+ self._caret_token, self._refs
).convert()
if images:
self._pdfs.extend(images)
@@ -178,6 +179,8 @@ def _latex_to_markdown(self):
output = Tags(output).convert()
output = NewLine(output).convert()
+ output = re.sub(r"\n? *\\label{.*?}", r"", output)
+
# convert all matched % back
output = re.sub(self._percent_token, "%", output)
output = re.sub(self._caret_token, "\n", output)
diff --git a/converter/markdown/checkyourself.py b/converter/markdown/checkyourself.py
index d993b5b2..468509ed 100644
--- a/converter/markdown/checkyourself.py
+++ b/converter/markdown/checkyourself.py
@@ -25,6 +25,7 @@ def make_block(self, matchobj):
block_contents = matchobj.group('block_contents')
block_contents = re.sub(r"\s*\n\s*", " ", block_contents).strip()
block_contents = block_contents.replace("\\\\", "
")
+ block_contents = re.sub(r"\n? *\\label{.*?} *", r"", block_contents)
answer_str = answer_re.sub(self.make_answer_block, block_contents)
caret_token = self._caret_token
answer_str = re.sub(r"\\{", r"{", answer_str)
diff --git a/converter/markdown/figure.py b/converter/markdown/figure.py
index 4eb91e4b..f331189e 100644
--- a/converter/markdown/figure.py
+++ b/converter/markdown/figure.py
@@ -5,7 +5,7 @@
class Figure(TextAsParagraph):
- def __init__(self, latex_str, figure_num, chapter_num, detect_asset_ext, caret_token):
+ def __init__(self, latex_str, figure_num, chapter_num, detect_asset_ext, caret_token, refs):
super().__init__(latex_str, caret_token)
self._figure_counter = 0
@@ -13,6 +13,7 @@ def __init__(self, latex_str, figure_num, chapter_num, detect_asset_ext, caret_t
self._chapter_num = chapter_num
self._pdfs = []
self._detect_asset_ext = detect_asset_ext
+ self._refs = refs
self._figure_re = re.compile(r"""\\begin{figure}(.*?)\n
(?P.*?)
@@ -20,6 +21,11 @@ def __init__(self, latex_str, figure_num, chapter_num, detect_asset_ext, caret_t
def _figure_block(self, matchobj):
block_contents = matchobj.group('block_contents')
+ match_label = re.search(r'\\label{(.*?)}', block_contents)
+ if match_label:
+ label = match_label.group(1)
+ block_contents = re.sub(r'\\label{.*?}', '', block_contents)
+
self._figure_counter += 1
images = []
@@ -27,6 +33,11 @@ def _figure_block(self, matchobj):
self._chapter_num, self._figure_counter + self._figure_counter_offset
)
+ if self._refs.get(label, {}):
+ caption = '**Figure {}'.format(
+ self._refs.get(label).get('ref')
+ )
+
caption_line = None
for line in block_contents.strip().split("\n"):
@@ -65,7 +76,6 @@ def _figure_block(self, matchobj):
if markdown_images:
return f'{self._caret_token.join(markdown_images)}{caret_token}{caret_token}**{caption}**'
- block_contents = block_contents.replace('\\label{.*?}', '')
block_contents = re.sub(r"\\caption{(.*?)}", r"", block_contents, flags=re.DOTALL + re.VERBOSE)
return f'{block_contents}{caret_token}**
{caption}
**{caret_token}'
diff --git a/converter/markdown/ignore.py b/converter/markdown/ignore.py
index a88f08ba..435c278b 100644
--- a/converter/markdown/ignore.py
+++ b/converter/markdown/ignore.py
@@ -37,7 +37,6 @@ def make_block(self, group):
def convert(self):
output = self.str
- output = self.remove_chars(output, "\\label{")
output = self.remove_chars(output, "\\vspace{")
output = re.sub(r"\\textit{.*?}", "", output)
output = re.sub(r"\\index\n{(.*?)}", r"\\index{\1}", output, flags=re.DOTALL)
diff --git a/tests/unit/cases/saas1.md b/tests/unit/cases/saas1.md
index 7cf742df..2455a338 100644
--- a/tests/unit/cases/saas1.md
+++ b/tests/unit/cases/saas1.md
@@ -1,8 +1,6 @@
### Software Development Processes: Plan and Document
-
-
> If builders built buildings the way programmers wrote programs, then the first woodpecker that came along would destroy civilization.
>
> __Gerald Weinberg, Weinberg's Second Law__
diff --git a/tests/unit/test_render_markdown.py b/tests/unit/test_render_markdown.py
index dbaa9aa7..a9d9b56f 100644
--- a/tests/unit/test_render_markdown.py
+++ b/tests/unit/test_render_markdown.py
@@ -22,7 +22,7 @@ def load_md(path):
def load_file(path):
dn = os.path.dirname(os.path.realpath(__file__))
fn = os.path.join(dn, path)
- with open(fn, 'r') as file:
+ with open(fn, 'r', encoding='utf-8') as file:
return file.read()
From 949fc4ad904cafe6dd6cf80a36161c4e00028021 Mon Sep 17 00:00:00 2001
From: sergei-bronnikov
Date: Thu, 28 Jan 2021 14:05:48 +0300
Subject: [PATCH 34/39] fix in figure
---
converter/markdown/figure.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/converter/markdown/figure.py b/converter/markdown/figure.py
index f331189e..5a28c2b9 100644
--- a/converter/markdown/figure.py
+++ b/converter/markdown/figure.py
@@ -22,6 +22,7 @@ def __init__(self, latex_str, figure_num, chapter_num, detect_asset_ext, caret_t
def _figure_block(self, matchobj):
block_contents = matchobj.group('block_contents')
match_label = re.search(r'\\label{(.*?)}', block_contents)
+ label = None
if match_label:
label = match_label.group(1)
block_contents = re.sub(r'\\label{.*?}', '', block_contents)
@@ -33,7 +34,7 @@ def _figure_block(self, matchobj):
self._chapter_num, self._figure_counter + self._figure_counter_offset
)
- if self._refs.get(label, {}):
+ if label and self._refs.get(label, {}):
caption = '**Figure {}'.format(
self._refs.get(label).get('ref')
)
From 24452915ac64a98ebb3aad8f8d478611b7d1082e Mon Sep 17 00:00:00 2001
From: Max Kraev
Date: Thu, 28 Jan 2021 14:41:52 +0000
Subject: [PATCH 35/39] fix
---
converter/toc.py | 5 -----
1 file changed, 5 deletions(-)
diff --git a/converter/toc.py b/converter/toc.py
index 6833be6a..26f0173b 100644
--- a/converter/toc.py
+++ b/converter/toc.py
@@ -345,11 +345,6 @@ def process_rst_lines(lines, exercises):
def print_to_yaml(structure, tex, data_format):
directory = tex.parent.parent.resolve() if data_format == 'rst' else tex.parent.resolve()
- directory: {}
- {}: {}
-assets:
-sections:
-""".format(directory, data_format, tex.name)
first_item = True
exercises_flag = False
for ind, item in enumerate(structure):
From 45b074ca00789310c6dbec51c922f22016868808 Mon Sep 17 00:00:00 2001
From: sergei-bronnikov
Date: Fri, 29 Jan 2021 09:22:59 +0300
Subject: [PATCH 36/39] fix merge
---
converter/toc.py | 6 ++++++
tests/unit/toc_cases/toc_simple.yml | 1 -
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/converter/toc.py b/converter/toc.py
index 26f0173b..a9cf3f48 100644
--- a/converter/toc.py
+++ b/converter/toc.py
@@ -345,6 +345,12 @@ def process_rst_lines(lines, exercises):
def print_to_yaml(structure, tex, data_format):
directory = tex.parent.parent.resolve() if data_format == 'rst' else tex.parent.resolve()
+ yaml_structure = """workspace:
+ directory: {}
+ {}: {}
+assets:
+sections:
+""".format(directory, data_format, tex.name)
first_item = True
exercises_flag = False
for ind, item in enumerate(structure):
diff --git a/tests/unit/toc_cases/toc_simple.yml b/tests/unit/toc_cases/toc_simple.yml
index 0e8b5305..6cdd1cd5 100644
--- a/tests/unit/toc_cases/toc_simple.yml
+++ b/tests/unit/toc_cases/toc_simple.yml
@@ -1,4 +1,3 @@
-name: "TODO: book name"
workspace:
directory: toc_cases
tex: toc_simple.tex
From 7ed18ec2d9cbf477d9734249cdca4fcada330bb1 Mon Sep 17 00:00:00 2001
From: sergei-bronnikov
Date: Fri, 29 Jan 2021 09:40:35 +0300
Subject: [PATCH 37/39] fix werker
---
wercker.yml | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/wercker.yml b/wercker.yml
index f8a40aeb..837cc6aa 100644
--- a/wercker.yml
+++ b/wercker.yml
@@ -1,4 +1,7 @@
-box: python:3.7
+box:
+ id: python:3.7
+ username: $DOCKER_USER
+ password: $DOCKER_PASSWORD
no-response-timeout: 10
build:
steps:
From 3fac3cd711f2581f58963718d40caf8045b86619 Mon Sep 17 00:00:00 2001
From: achetporov
Date: Tue, 16 Feb 2021 13:10:32 +0300
Subject: [PATCH 38/39] 12366 fix issues (#76)
---
converter/markdown/ignore.py | 6 +++---
tests/unit/cases/comments.md | 3 +++
tests/unit/cases/html.md | 5 ++++-
3 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/converter/markdown/ignore.py b/converter/markdown/ignore.py
index 435c278b..26e50872 100644
--- a/converter/markdown/ignore.py
+++ b/converter/markdown/ignore.py
@@ -37,17 +37,17 @@ def make_block(self, group):
def convert(self):
output = self.str
+ output = re.sub(r"\\index\n{(.*?)}", r"\\index{\1}", output)
output = self.remove_chars(output, "\\vspace{")
+ output = self.remove_chars(output, "\\index{")
output = re.sub(r"\\textit{.*?}", "", output)
- output = re.sub(r"\\index\n{(.*?)}", r"\\index{\1}", output, flags=re.DOTALL)
- output = re.sub(r"\n? *\\index{.*?\n?.*?}%", "", output)
- output = re.sub(r"(?![ ])\n? *\\index{.*?\n?.*?}", "", output)
output = re.sub(r"\\noindent", "", output)
output = re.sub(r"\\bigconcepts", "", output)
output = re.sub(r"\\prereqs?", "", output)
output = re.sub(r"\\relax", "", output)
output = re.sub(r"\\vfill", "", output)
output = re.sub(r"\\indent", "", output)
+ output = re.sub(r"\\pitfallicon", "", output)
output = re.sub(r"\\fallaciesandpitfalls", "", output)
output = re.sub(r"\\makebox\[.*?\]{}", "
", output)
output = re.sub(r"\\hspace{.*?}", "", output)
diff --git a/tests/unit/cases/comments.md b/tests/unit/cases/comments.md
index dc2d670a..2312afa9 100644
--- a/tests/unit/cases/comments.md
+++ b/tests/unit/cases/comments.md
@@ -4,6 +4,8 @@ The remainder operator looks like a percent sign, but you might find it helpful
+
+
Modular arithmetic turns out to be surprisingly useful. For example, you can check whether one number is divisible by another: if `x % y` is zero, then `x` is divisible by `y`. You can use remainder to “extract” digits from a number: `x % 10` yields the rightmost digit of `x`, and `x % 100` yields the last two digits. And many encryption algorithms use the remainder operator extensively.
@@ -29,6 +31,7 @@ At this point, you have seen enough Java to write useful programs that solve eve
+
```code
import java.util.Scanner;
diff --git a/tests/unit/cases/html.md b/tests/unit/cases/html.md
index 9dc87c52..17766062 100644
--- a/tests/unit/cases/html.md
+++ b/tests/unit/cases/html.md
@@ -8,6 +8,7 @@ If the Web browser is the universal client, ___HTML___, the HyperText Markup Lan
HTML consists of a hierarchy of nested elements, each of which consists of an opening tag such as <p>, a content part (in some cases), and a closing tag such as </p>. Most opening tags can also have attributes, as in $<$a href="http://..."$>$. Some tags that don't have a content part are self-closing, such as <br clear="both"/> for a line break that clears both left and right margins.
+
|||info
@@ -17,7 +18,9 @@ The use of angle brackets for tags comes from ___SGML___ (Standard Generalized M
-There is an unfortunate and confusing mess of terminology surrounding the [lineage of HTML](http://www.w3.org/TR/html5/introduction.html#history-1) HTML 5 includes features of both its predecessors (HTML versions 1 through 4) and XHTML (eXtended HyperText Markup Language), which is a subset of ___XML___, an eXtensible Markup Language that can be used both to represent data and to describe other markup languages. Indeed, XML is a common data representation for exchanging information between two services in a Service-Oriented Architecture, as we'll see in Chapter chap:tdd when we extend RottenPotatoes to retrieve movie information from a separate movie database service. The differences among the variants of XHTML and HTML are difficult to keep straight, and not all browsers support all versions. Unless otherwise noted, from now on when we say HTML we mean HTML 5, and we will try to avoid using features that aren't widely supported.
+There is an unfortunate and confusing mess of terminology surrounding the [lineage of HTML](http://www.w3.org/TR/html5/introduction.html#history-1)
+
+HTML 5 includes features of both its predecessors (HTML versions 1 through 4) and XHTML (eXtended HyperText Markup Language), which is a subset of ___XML___, an eXtensible Markup Language that can be used both to represent data and to describe other markup languages. Indeed, XML is a common data representation for exchanging information between two services in a Service-Oriented Architecture, as we'll see in Chapter chap:tdd when we extend RottenPotatoes to retrieve movie information from a separate movie database service. The differences among the variants of XHTML and HTML are difficult to keep straight, and not all browsers support all versions. Unless otherwise noted, from now on when we say HTML we mean HTML 5, and we will try to avoid using features that aren't widely supported.
Of particular interest are the HTML tag attributes id and class, because they figure heavily into connecting the HTML structure of a page with its visual appearance. The following screencast illustrates the use of Firefox's Web Developer toolbar to quickly identify the ID's and Classes of HTML elements on a page.
From 8c2ecf2f75b159b33723cd8934781a61655010b8 Mon Sep 17 00:00:00 2001
From: Jairo Velasquez
Date: Mon, 8 Jul 2024 16:22:54 +0000
Subject: [PATCH 39/39] Update for competencies
---
converter/latex2markdown.py | 2 ++
converter/markdown/competency.py | 21 +++++++++++++++++++++
2 files changed, 23 insertions(+)
create mode 100644 converter/markdown/competency.py
diff --git a/converter/latex2markdown.py b/converter/latex2markdown.py
index ffc2e125..dce4d151 100644
--- a/converter/latex2markdown.py
+++ b/converter/latex2markdown.py
@@ -26,6 +26,7 @@
from converter.markdown.cleanup import Cleanup
from converter.markdown.exercise import Exercise
from converter.markdown.figure import Figure
+from converter.markdown.competency import Competency
from converter.markdown.refs import Refs
from converter.markdown.sidebar import Sidebar
from converter.markdown.eqnarray import EqnArray
@@ -118,6 +119,7 @@ def _latex_to_markdown(self):
# remove comments
output = RemoveComments(output).convert()
output = Quotation(output, self._caret_token).convert()
+ output = Competency(output, self._caret_token).convert()
output = Paragraph(output).convert_without_tags()
output = Refs(output, self._refs).convert()
output = Links(output).convert()
diff --git a/converter/markdown/competency.py b/converter/markdown/competency.py
new file mode 100644
index 00000000..4c74ff8b
--- /dev/null
+++ b/converter/markdown/competency.py
@@ -0,0 +1,21 @@
+import re
+
+from converter.markdown.block_matcher import match_block
+from converter.markdown.text_as_paragraph import TextAsParagraph
+
+competency_re = re.compile(r"""\\competency(\[(.*?)\])?{(?P.*?)}""",
+ flags=re.DOTALL + re.VERBOSE)
+
+class Competency(TextAsParagraph):
+ def __init__(self, latex_str, caret_token):
+ super().__init__(latex_str, caret_token)
+
+ def make_block(self, matchobj):
+ block_contents = matchobj.group('block_contents')
+ block_contents = re.sub(r"\s*\n\s*", " ", block_contents).strip()
+ block_contents = block_contents.replace("\\\\", "
")
+ caret_token = self._caret_token
+ return f'{caret_token}|||topic{caret_token}## Competency{caret_token}{block_contents}{caret_token}{caret_token}|||{caret_token}'
+
+ def convert(self):
+ return competency_re.sub(self.make_block, self.str)
\ No newline at end of file