├── project
└── assembly.sbt
├── lib
├── pdfclown.jar
└── pdfclown-0.1.2-sources.jar
├── src
├── test
│ ├── resources
│ │ ├── agile_contracts_primer.pdf
│ │ ├── Test1.txt
│ │ ├── ExampleClippings.txt~
│ │ ├── ExampleClippings.txt
│ │ ├── pdfHighlightTest.txt
│ │ └── MyClippings.txt
│ └── scala
│ │ └── com
│ │ └── fabiooliveiracosta
│ │ └── highlight2pdf
│ │ ├── UnitSpec.scala
│ │ ├── FileReaderSpec.scala
│ │ ├── PDFHandlerSpec.scala
│ │ ├── ClippingSpec.scala
│ │ ├── CommonSubstringSpec.scala
│ │ └── ReadClippingSpec.scala
└── main
│ └── scala
│ └── com
│ └── fabiooliveiracosta
│ └── highlight2pdf
│ ├── Clippings.scala
│ ├── FileReader.scala
│ ├── CommonSubstring.scala
│ ├── CLIApp.scala
│ ├── ClippingFactory.scala
│ ├── ClippingsReader.scala
│ ├── PDFHighlightIntervalFilter.scala
│ └── PDFHandler.scala
├── .gitignore
├── README.md
├── LICENSE
└── samples.txt
/project/assembly.sbt:
--------------------------------------------------------------------------------
1 | addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.13.0")
--------------------------------------------------------------------------------
/lib/pdfclown.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drFabio/highlight2pdf/master/lib/pdfclown.jar
--------------------------------------------------------------------------------
/lib/pdfclown-0.1.2-sources.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drFabio/highlight2pdf/master/lib/pdfclown-0.1.2-sources.jar
--------------------------------------------------------------------------------
/src/test/resources/agile_contracts_primer.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drFabio/highlight2pdf/master/src/test/resources/agile_contracts_primer.pdf
--------------------------------------------------------------------------------
/src/test/scala/com/fabiooliveiracosta/highlight2pdf/UnitSpec.scala:
--------------------------------------------------------------------------------
1 | package com.fabiooliveiracosta.highlight2pdf
2 |
3 | import org.scalatest._
4 |
5 | abstract class UnitSpec extends FlatSpec with Matchers with OptionValues with Inside with Inspectors
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 | *.log
3 |
4 | # sbt specific
5 | .cache
6 | .history
7 | .lib/
8 | dist/*
9 | target/
10 | lib_managed/
11 | src_managed/
12 | project/boot/
13 | project/plugins/project/
14 |
15 | # Scala-IDE specific
16 | .scala_dependencies
17 | .worksheet
18 |
--------------------------------------------------------------------------------
/src/main/scala/com/fabiooliveiracosta/highlight2pdf/Clippings.scala:
--------------------------------------------------------------------------------
1 | package com.fabiooliveiracosta.highlight2pdf
2 |
3 | abstract class AbstractClipping(val firstPage:Int,val lastPage:Int,val bookTitle:String)
4 | case class HighlightClipping(fstPage:Int,
5 | lstPage:Int,
6 | title:String,
7 | val content:String)
8 | extends AbstractClipping(fstPage,lstPage,title)
9 |
10 | case class BookmarkClipping(fstPage:Int,
11 | lstPage:Int,
12 | title:String)
13 | extends AbstractClipping(fstPage,lstPage,title)
--------------------------------------------------------------------------------
/src/test/resources/Test1.txt:
--------------------------------------------------------------------------------
1 | Highlight1
2 | - Your Highlight on page 22-22 | Added on Wednesday, 8 April 2015 16:03:38
3 |
4 | Lorem ipsum dolor sit amet
5 | ==========
6 | Highlight2
7 | - Your Highlight on page 24-24 | Added on Sunday, 12 April 2015 14:15:50
8 |
9 | Consectur lorem ipsum sit
10 | ==========
11 | Highlight3
12 | - Your Highlight on page 24-24 | Added on Sunday, 12 April 2015 14:15:50
13 |
14 | Consectur lorem ipsum sit
15 | ==========
16 |
17 | Bookmark1
18 | - Your Bookmark Location 45 | Added on Monday, 4 November 13 17:13:14
19 |
20 |
21 | ==========
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # highlight2pdf
2 | A scala program that get Kingle clipping highlights and highlight them on the PDF
3 | It uses pdfClown for the pdfHighlight
4 | See the tests for further informations
5 | You can use this as a CLI app using the jar on build like so:
6 | java -jar highlight2pdf -h clippings.txt -t "BookTitleOnClippings" pdfFileToHighlight.pdf
7 |
8 | ## Build
9 | You can build using sbt
10 |
11 | ##F urther improvements
12 |
13 | - PDF bookmarking
14 |
15 | - Make a mapping of clipping title to a pdf file on a folder
16 |
17 | ### About the pdf on tests
18 | The pdf on tests can be found here http://www.agilecontracts.org/
19 |
--------------------------------------------------------------------------------
/src/test/scala/com/fabiooliveiracosta/highlight2pdf/FileReaderSpec.scala:
--------------------------------------------------------------------------------
1 | package com.fabiooliveiracosta.highlight2pdf
2 |
3 | import org.scalatest._
4 | import java.io.FileNotFoundException
5 | class FileReaderSpec extends UnitSpec {
6 | "Files that are not found" should "throw an exception" in{
7 | intercept[FileNotFoundException] {
8 | FileReader.getFileLines("nontExistent.txt");
9 | }
10 | }
11 | "Files that are found " should "return the file lines " in {
12 | val path:String=getClass.getResource("/ExampleClippings.txt").getPath()
13 | val lines:Iterable[String]=FileReader.getFileLines(path)
14 | assert(lines.size>0)
15 | }
16 |
17 | }
--------------------------------------------------------------------------------
/src/test/resources/ExampleClippings.txt~:
--------------------------------------------------------------------------------
1 | Lean Architecture
2 | - Your Highlight on page 22-22 | Added on Wednesday, 8 April 2015 16:03:38
3 |
4 | We will deliver code just in time instead of stockpiling software library warehouses ahead of time
5 | ==========
6 | Lean Architecture
7 | - Your Highlight on page 24-24 | Added on Sunday, 12 April 2015 14:15:50
8 |
9 | that 70% of the software they build is never used
10 | ==========
11 | Lean Architecture
12 | - Your Highlight on page 26-26 | Added on Sunday, 12 April 2015 14:19:35
13 |
14 | Lean focuses on what’s important now, whenever ‘‘now’’ is – whether that is hitting the target for next week’s delivery or doing long-term planning
15 | ==========
16 |
--------------------------------------------------------------------------------
/src/test/scala/com/fabiooliveiracosta/highlight2pdf/PDFHandlerSpec.scala:
--------------------------------------------------------------------------------
1 | package com.fabiooliveiracosta.highlight2pdf
2 |
3 | import java.net.URL
4 | import org.scalatest._
5 | import java.io.FileNotFoundException
6 | class PDFHandlerSpec extends UnitSpec {
7 | "Highlight" should "be possible" in{
8 | val clippingPath:String=getClass.getResource("/pdfHighlightTest.txt").getPath()
9 | val highlightList:List[HighlightClipping]=ClippingsReader.readHighlightsFromFile(clippingPath,"agile_contracts_primer")
10 | val url:URL=getClass.getResource("/agile_contracts_primer.pdf")
11 | val path:String=url.getPath()
12 | val ret:Boolean=PDFHandler.highlightOnFile(path,highlightList)
13 | assert(ret)
14 |
15 | }
16 |
17 | }
--------------------------------------------------------------------------------
/src/test/resources/ExampleClippings.txt:
--------------------------------------------------------------------------------
1 | Lean Architecture
2 | - Your Highlight on page 22-22 | Added on Wednesday, 8 April 2015 16:03:38
3 |
4 | We will deliver code just in time instead of stockpiling software library warehouses ahead of time
5 | ==========
6 | Lean Architecture
7 | - Your Highlight on page 24-24 | Added on Sunday, 12 April 2015 14:15:50
8 |
9 | that 70% of the software they build is never used
10 | ==========
11 | Lean Architecture
12 | - Your Highlight on page 26-26 | Added on Sunday, 12 April 2015 14:19:35
13 |
14 | Lean focuses on what’s important now, whenever ‘‘now’’ is – whether that is hitting the target for next week’s delivery or doing long-term planning
15 | ==========
16 | Lean Architecture
17 | - Your Bookmark Location 45 | Added on Monday, 4 November 13 17:13:14
18 |
19 |
20 | ==========
--------------------------------------------------------------------------------
/src/main/scala/com/fabiooliveiracosta/highlight2pdf/FileReader.scala:
--------------------------------------------------------------------------------
1 | package com.fabiooliveiracosta.highlight2pdf
2 |
3 | import java.nio.file.{Paths, Files}
4 | import scala.io.Source
5 |
6 | object FileReader{
7 | protected val defaultCodecs = List(
8 | io.Codec("UTF-8"),
9 | io.Codec("ISO-8859-1")
10 | )
11 | def getFileLines(fileName:String, codecs:Iterable[io.Codec] = defaultCodecs): Iterable[String]={
12 | if(!Files.exists(Paths.get(fileName))){
13 | throw new java.io.FileNotFoundException("File: "+fileName+" not found ");
14 | }
15 | val codec = codecs.head
16 | val fileHandle=Source.fromFile(fileName)(codec)
17 | try{
18 | fileHandle.getLines().toList
19 | }
20 | catch{
21 | case ex: Exception => {
22 | if (codecs.tail.isEmpty) {
23 | throw ex
24 | }
25 | getFileLines(fileName, codecs.tail)
26 | }
27 | }
28 | finally{
29 | fileHandle.close()
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/src/main/scala/com/fabiooliveiracosta/highlight2pdf/CommonSubstring.scala:
--------------------------------------------------------------------------------
1 | package com.fabiooliveiracosta.highlight2pdf
2 | import scala.util.control.Breaks
3 |
4 | object CommonSubstring{
5 | /**
6 | *Finds the segment of a needle on a haystack assuming that needle is started on haystack always
7 | */
8 | def findSegment(needle:String,haystack:String):String={
9 | var start:Int=0
10 | var max:Int=0
11 | val needleLength:Int=needle.length()
12 | val haystackLength:Int=haystack.length()
13 | var j:Int=0
14 | var x:Int=0
15 | for(j<-0 until haystackLength){
16 | x=0
17 | def loopNeedle{
18 | if(x>=needleLength || (j+x)>=haystackLength){
19 | return
20 | }
21 | if(needle.charAt(x)==haystack.charAt(j+x)){
22 | x+=1
23 | }
24 | else{
25 | return
26 | }
27 | loopNeedle
28 | }
29 | loopNeedle
30 |
31 | if(x>max){
32 | max=x
33 | start=j
34 | }
35 | //Already found match
36 | if(max==needleLength){
37 | return haystack.substring(start,(start+max))
38 | }
39 | }
40 |
41 | haystack.substring(start,(start+max))
42 | }
43 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Fabio Oliveira Costa
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/src/test/scala/com/fabiooliveiracosta/highlight2pdf/ClippingSpec.scala:
--------------------------------------------------------------------------------
1 | package com.fabiooliveiracosta.highlight2pdf
2 |
3 | import org.scalatest._
4 | import java.io.FileNotFoundException
5 | class ClippingSpec extends UnitSpec {
6 | "Clipping with highlight " should "be returned as highlighted clippings " in{
7 | val clippingList=List("Some title",
8 | "- Your Highlight on page 24-30 | Added on Sunday, 12 April 2015 14:15:50 ",
9 | "Lorem ipsum dolor sit amet");
10 |
11 | val clipping:Option[AbstractClipping]=ClippingFactory.getClippling(clippingList)
12 | clipping match{
13 | case Some(h:HighlightClipping)=>{
14 | println(h.lastPage)
15 | assert(h.lastPage==30)
16 | assert(h.firstPage==24)
17 | assert(h.bookTitle=="Some title")
18 | assert(h.content=="Lorem ipsum dolor sit amet")
19 | }
20 | case _=>{
21 | fail("Type of clipping should be highlight")
22 | }
23 | }
24 | }
25 | "Clipping with Bookmark " should "be returned as bookmarks clippings " in{
26 | val clippingList=List("Another title",
27 | "- Your Bookmark on Page 67 | Added on Sunday, 12 April 2015 14:15:50 ");
28 |
29 | val clipping:Option[AbstractClipping]=ClippingFactory.getClippling(clippingList)
30 | clipping match{
31 | case Some(b:BookmarkClipping)=>{
32 | println(b.lastPage)
33 | assert(b.lastPage==67)
34 | assert(b.firstPage==67)
35 | assert(b.bookTitle=="Another title")
36 | }
37 | case _=>{
38 | fail("Type of clipping should be bookmark")
39 | }
40 | }
41 | }
42 |
43 | }
--------------------------------------------------------------------------------
/src/test/scala/com/fabiooliveiracosta/highlight2pdf/CommonSubstringSpec.scala:
--------------------------------------------------------------------------------
1 | package com.fabiooliveiracosta.highlight2pdf
2 |
3 | import org.scalatest._
4 | class CommonSubstringSpec extends UnitSpec {
5 | val haystack:String="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse porttitor luctus massa, quis pretium sapien tristique vitae. Cras non magna scelerisque, pretium ex quis, blandit lacus. Aenean lacinia aliquet tempus. Aenean suscipit eget quam in pharetra. Donec id velit sit amet velit pretium pretium. Donec et enim ac velit congue hendrerit. Cras tempus sodales dui quis gravida. Cras pellentesque ut sem eu ullamcorper. Aenean dictum, purus eget pulvinar semper, nulla magna suscipit erat, non vestibulum mi ante eget elit. Aliquam ut leo nisl. Fusce tristique vitae nisi a gravida. Vestibulum semper tristique turpis quis ultricies. Sed sit amet euismod quam. In hac habitasse platea dictumst. Nulla dapibus sagittis orci vitae cursus. Aliquam libero nisi, volutpat sit amet rhoncus eu, dapibus a lorem"
6 | "The longest common substring" should "be found if fully matched" in{
7 | val needle:String="Lorem ipsum dolor sit amet"
8 | val comparison=CommonSubstring.findSegment(needle,haystack)
9 | assert(needle==comparison)
10 | }
11 | "The longest common substring" should "be found if partialy matched" in{
12 | val baseNeedle:String="volutpat sit amet rhoncus eu, dapibus a lorem"
13 | val comparison=CommonSubstring.findSegment(baseNeedle+"Some stuff that should never be found",haystack)
14 | assert(baseNeedle==comparison)
15 | }
16 | }
--------------------------------------------------------------------------------
/src/main/scala/com/fabiooliveiracosta/highlight2pdf/CLIApp.scala:
--------------------------------------------------------------------------------
1 | package com.fabiooliveiracosta.highlight2pdf
2 | object CLIApp {
3 | val usage = """Usage: highlight2pdf -h highlightFile -t bookHighlightTitle pdfFile"""
4 |
5 | type OptionMap = Map[Symbol, String]
6 |
7 | def highlightFromClippingIntoFile(highlightFile:String,bookTitle:String,pdfFile:String):Boolean={
8 | val highlightList:List[HighlightClipping]=ClippingsReader.readHighlightsFromFile(highlightFile,bookTitle)
9 | PDFHandler.highlightOnFile(pdfFile,highlightList)
10 | }
11 | def parseCliArguments(args:Array[String]):OptionMap={
12 | val arglist = args.toList
13 |
14 | def isSwitch(s : String) = (s(0) == '-')
15 | def nextOption(map : OptionMap, list: List[String]) : OptionMap = {
16 | list match {
17 | case Nil => map
18 | case "-h" :: value :: tail =>{
19 | nextOption(map ++ Map('highlightFile -> value), tail)
20 | }
21 | case "-t" :: value :: tail =>{
22 | nextOption(map ++ Map('bookTitle -> value), tail)
23 | }
24 | case value :: opt2 :: tail if isSwitch(opt2) => {
25 | nextOption(map ++ Map('pdfFile -> value), list.tail)
26 | }
27 | case value :: Nil =>{
28 | nextOption(map ++ Map('pdfFile -> value), list.tail)
29 | }
30 | case _=>{
31 | throw new Exception("Invalid usage")
32 | }
33 | }
34 | }
35 | nextOption(Map(),arglist)
36 | }
37 | def main(args: Array[String]){
38 | if (args.length <5){
39 | println(usage)
40 | return
41 | }
42 | val opt:OptionMap=parseCliArguments(args)
43 | val highlightFile:String=opt.get('highlightFile).get
44 | val bookTitle:String=opt.get('bookTitle).get
45 | val pdfFile:String=opt.get('pdfFile).get
46 | println("Trying to highlight the clippings from "+highlightFile+" on the book "+bookTitle+" for the pdf "+pdfFile)
47 | highlightFromClippingIntoFile(highlightFile,bookTitle,pdfFile)
48 | }
49 |
50 | }
--------------------------------------------------------------------------------
/src/main/scala/com/fabiooliveiracosta/highlight2pdf/ClippingFactory.scala:
--------------------------------------------------------------------------------
1 | package com.fabiooliveiracosta.highlight2pdf
2 |
3 | object ClippingFactory{
4 | val titleRegex="""(?i)\s*-\s*Your (Highlight|Bookmark) (on Page|Location) ((\d*)(-(\d*))?) \|[^,]*, (\d*) (\w*) (\d*) (\d*):(\d*):(\d*)""".r
5 | def getHighlight(data:List[String],desiredTitles:String*):Option[HighlightClipping]={
6 | val theClipping=this.getClippling(data,desiredTitles:_*)
7 | theClipping match{
8 | case Some(h:HighlightClipping)=>Some(h)
9 | case _=>None
10 | }
11 | }
12 | def getBookmark(data:List[String],desiredTitles:String*):Option[BookmarkClipping]={
13 | val theClipping=this.getClippling(data,desiredTitles:_*)
14 | theClipping match{
15 | case Some(h:BookmarkClipping)=>Some(h)
16 | case _=>None
17 | }
18 | }
19 | def getClippling(data:List[String],desiredTitles:String*):Option[AbstractClipping]={
20 | val title:String=data.head.trim
21 | if(desiredTitles.length>0 && !(desiredTitles contains title)){
22 | return None
23 | }
24 | val temp=data.tail
25 | val typeData:String=temp.head.trim
26 | val groupMatchs=titleRegex findFirstMatchIn typeData
27 | var firstPage:Int=0
28 | var lastPage:Int=0
29 | var isBookmark:Boolean=false
30 |
31 | groupMatchs match {
32 | case Some(value) =>{
33 | if(value.group(3) contains "-"){
34 | firstPage=value.group(4).toInt
35 | lastPage=value.group(6).toInt
36 | }
37 | else{
38 | firstPage=value.group(3).toInt
39 | lastPage=firstPage
40 | }
41 | if(value.group(1).toLowerCase() contains "bookmark"){
42 | isBookmark=true
43 | }
44 | else{
45 | isBookmark=false
46 | }
47 | }
48 | case None => throw new Exception("Invalid info data")
49 | }
50 | if(isBookmark){
51 | Some(new BookmarkClipping(firstPage,lastPage,title))
52 | }
53 | else{
54 | val content:String=temp.tail.head.trim
55 | Some(new HighlightClipping(firstPage,lastPage,title,content))
56 | }
57 | }
58 | }
--------------------------------------------------------------------------------
/src/main/scala/com/fabiooliveiracosta/highlight2pdf/ClippingsReader.scala:
--------------------------------------------------------------------------------
1 | package com.fabiooliveiracosta.highlight2pdf
2 | import scala.collection.mutable.ListBuffer
3 |
4 | object ClippingsReader{
5 | protected val defaultSeparator="=========="
6 | object ClippingTypes extends Enumeration {
7 | val ALL,BOOKMARK,CLIPPING = Value
8 | }
9 | def readClippingsFromFile(fileName:String,desiredTitles:String*):List[AbstractClipping]={
10 | filterClippings(fileName,ClippingTypes.ALL,desiredTitles:_*)
11 | }
12 | def filterClippings(fileName:String,desiredType:ClippingTypes.Value,desiredTitles:String*):List[AbstractClipping]={
13 | val lines:Iterable[String]=FileReader.getFileLines(fileName);
14 | var line:String=""
15 | var clippingsLinesList=new ListBuffer[String]()
16 | var clippingBuffer=new ListBuffer[AbstractClipping]()
17 | var theClipping:Option[AbstractClipping]=None
18 | var clippingStrList:List[String]=Nil
19 | for(line<-lines){
20 | if(line!=""){
21 | if(line==defaultSeparator){
22 | clippingStrList=clippingsLinesList.toList
23 | desiredType match{
24 | case ClippingTypes.ALL=>{
25 | theClipping=ClippingFactory.getClippling(clippingStrList,desiredTitles:_*)
26 | }
27 | case ClippingTypes.CLIPPING=>{
28 | theClipping=ClippingFactory.getHighlight(clippingStrList,desiredTitles:_*)
29 | }
30 | case ClippingTypes.BOOKMARK=>{
31 | theClipping=ClippingFactory.getBookmark(clippingStrList,desiredTitles:_*)
32 | }
33 | }
34 | theClipping match{
35 | case Some(h)=>clippingBuffer+=h
36 | case None=>
37 | }
38 | clippingsLinesList.clear()
39 | }
40 | else{
41 | clippingsLinesList+=line
42 | }
43 | }
44 | }
45 | clippingBuffer.toList
46 | }
47 | def readHighlightsFromFile(fileName:String,desiredTitles:String*):List[HighlightClipping]={
48 | filterClippings(fileName,ClippingTypes.CLIPPING,desiredTitles:_*).asInstanceOf[List[HighlightClipping]]
49 | }
50 | def readBookmarksFromFile(fileName:String,desiredTitles:String*):List[BookmarkClipping]={
51 | filterClippings(fileName,ClippingTypes.BOOKMARK,desiredTitles:_*).asInstanceOf[List[BookmarkClipping]]
52 | }
53 |
54 | }
--------------------------------------------------------------------------------
/src/test/scala/com/fabiooliveiracosta/highlight2pdf/ReadClippingSpec.scala:
--------------------------------------------------------------------------------
1 | package com.fabiooliveiracosta.highlight2pdf
2 |
3 | import org.scalatest._
4 | import java.io.FileNotFoundException
5 | class ReadClippingSpec extends UnitSpec {
6 | "All Clippings " should "be obtained from a file and returned on the order they were found" in{
7 | val path:String=getClass.getResource("/Test1.txt").getPath()
8 | val clippingList:List[AbstractClipping]=ClippingsReader.readClippingsFromFile(path)
9 | assert(clippingList.size==4)
10 | assert(clippingList(0).bookTitle=="Highlight1")
11 | assert(clippingList(1).bookTitle=="Highlight2")
12 | assert(clippingList(2).bookTitle=="Highlight3")
13 | assert(clippingList(3).bookTitle=="Bookmark1")
14 | }
15 | "Only bookmark clippings" should " be returned when using readHighlightsFromFile" in {
16 | val path:String=getClass.getResource("/Test1.txt").getPath()
17 | val clippingList:List[BookmarkClipping]=ClippingsReader.readBookmarksFromFile(path)
18 | assert(clippingList.size==1)
19 | assert(clippingList(0).bookTitle=="Bookmark1")
20 | assert(clippingList(0).isInstanceOf[BookmarkClipping])
21 | }
22 | "Only Highlight clippings" should " be returned when using readHighlightsFromFile" in {
23 | val path:String=getClass.getResource("/Test1.txt").getPath()
24 | val clippingList:List[AbstractClipping]=ClippingsReader.readHighlightsFromFile(path)
25 | assert(clippingList.size==3)
26 | assert(clippingList(0).bookTitle=="Highlight1")
27 | assert(clippingList(1).bookTitle=="Highlight2")
28 | assert(clippingList(2).bookTitle=="Highlight3")
29 | assert(clippingList(0).isInstanceOf[HighlightClipping])
30 | assert(clippingList(1).isInstanceOf[HighlightClipping])
31 | assert(clippingList(2).isInstanceOf[HighlightClipping])
32 | }
33 | "Only the highlights from the selected title " should " be returned only when using readHighlightsFromFileForBook" in {
34 | val path:String=getClass.getResource("/Test1.txt").getPath()
35 | val clippingList:List[AbstractClipping]=ClippingsReader.readHighlightsFromFile(path,"Highlight1","Highlight2")
36 | assert(clippingList.size==2)
37 | assert(clippingList(0).bookTitle=="Highlight1")
38 | assert(clippingList(1).bookTitle=="Highlight2")
39 | }
40 | }
--------------------------------------------------------------------------------
/src/main/scala/com/fabiooliveiracosta/highlight2pdf/PDFHighlightIntervalFilter.scala:
--------------------------------------------------------------------------------
1 | package com.fabiooliveiracosta.highlight2pdf
2 |
3 | import scala.collection.JavaConversions._
4 |
5 | import java.awt.geom.Rectangle2D
6 | import java.util.ArrayList
7 | import java.util.{Map => JMap, List => JList,Iterator=>JIterator}
8 |
9 | import org.pdfclown.documents.Pages
10 | import org.pdfclown.documents.Page
11 | import org.pdfclown.documents.contents.ITextString
12 | import org.pdfclown.documents.contents.TextChar
13 | import org.pdfclown.documents.interaction.annotations.TextMarkup
14 | import org.pdfclown.documents.interaction.annotations.TextMarkup.MarkupTypeEnum
15 | import org.pdfclown.files.File
16 | import org.pdfclown.tools.TextExtractor
17 | import org.pdfclown.util.math.Interval
18 | import org.pdfclown.util.math.geom.Quad
19 |
20 | class PDFHighlightIntervalFilter(val page:Page,val pageText:String,val desiredHighlight:String) extends TextExtractor.IIntervalFilter{
21 |
22 | protected var _alreadyFound=false
23 | protected var _remainingText:Option[String]=None
24 | def getRemainingText:Option[String]={
25 | _remainingText
26 | }
27 | def hasNext():Boolean={
28 | if(_alreadyFound){
29 | false
30 | }
31 | else{
32 | _alreadyFound=true
33 | true
34 | }
35 | }
36 | def next():Interval[Integer]={
37 | val actualHighlight=CommonSubstring.findSegment(desiredHighlight,pageText)
38 | if(actualHighlight!=desiredHighlight){
39 | _remainingText=Some(desiredHighlight.substring(actualHighlight.length()+1))
40 | }
41 | val startIndex:Int=pageText.indexOf(actualHighlight)
42 | val endIndex:Int=startIndex+actualHighlight.length()
43 | new Interval[Integer](startIndex,endIndex)
44 | }
45 | def process(interval:Interval[Integer],textMatch:ITextString){
46 | val highlightQuads:JList[Quad] = new ArrayList[Quad]()
47 | /*
48 | NOTE: A text pattern match may be split across multiple contiguous lines,
49 | so we have to define a distinct highlight box for each text chunk.
50 | */
51 | var textBox:Rectangle2D = null
52 | val txtMatchList=textMatch.getTextChars().toList
53 | for(textChar:TextChar <- txtMatchList)
54 | {
55 |
56 | var textCharBox:Rectangle2D = textChar.getBox()
57 | if(textBox == null)
58 | {
59 | textBox=textCharBox.clone().asInstanceOf[Rectangle2D]
60 | }
61 | else{
62 | if(textCharBox.getY() > textBox.getMaxY()){
63 | highlightQuads.add(Quad.get(textBox));
64 | textBox=textCharBox.clone().asInstanceOf[Rectangle2D]
65 | }
66 | else
67 | {
68 | textBox.add(textCharBox);}
69 | }
70 | }
71 | highlightQuads.add(Quad.get(textBox));
72 | val markup:TextMarkup=new TextMarkup(page, null, MarkupTypeEnum.Highlight, highlightQuads);
73 | markup.setVisible(true)
74 | markup.setPrintable(true)
75 | }
76 | }
--------------------------------------------------------------------------------
/src/main/scala/com/fabiooliveiracosta/highlight2pdf/PDFHandler.scala:
--------------------------------------------------------------------------------
1 | package com.fabiooliveiracosta.highlight2pdf
2 |
3 | import scala.collection.JavaConversions._
4 |
5 | import java.awt.geom.Rectangle2D
6 | import java.util.ArrayList
7 | import java.util.{Map => JMap, List => JList,Iterator=>JIterator}
8 | import java.util.regex.Matcher
9 | import java.util.regex.Pattern
10 |
11 | import org.pdfclown.documents.Document
12 | import org.pdfclown.documents.Pages
13 | import org.pdfclown.documents.PageLabels
14 | import org.pdfclown.documents.interaction.navigation.page.PageLabel
15 | import org.pdfclown.documents.Page
16 | import org.pdfclown.documents.contents.ITextString
17 | import org.pdfclown.documents.contents.TextChar
18 | import org.pdfclown.documents.interaction.annotations.TextMarkup
19 | import org.pdfclown.documents.interaction.annotations.TextMarkup.MarkupTypeEnum
20 | import org.pdfclown.files.File
21 | import org.pdfclown.tools.TextExtractor
22 | import org.pdfclown.util.math.Interval
23 | import org.pdfclown.util.math.geom.Quad
24 | import org.pdfclown.files.SerializationModeEnum
25 | import org.pdfclown.objects.PdfInteger
26 |
27 | object PDFHandler{
28 | val txtExtractor:TextExtractor= new TextExtractor(true, true)
29 | def highlightOnFile(filePath:String,highlights:List[HighlightClipping]):Boolean={
30 | val file:File= new File(filePath)
31 | val doc:Document=file.getDocument()
32 | val numericStart:Int=getNumericStart(doc)
33 | val pages:Pages=doc.getPages()
34 | for (h <- highlights){
35 | highlightPages(pages,h,numericStart) match{
36 | case false=> return false
37 | case _ =>
38 | }
39 | }
40 | file.save(SerializationModeEnum.Incremental)
41 | file.close()
42 | true
43 | }
44 | /**
45 | *Get the first numerical start of a page
46 | */
47 | def getNumericStart(doc:Document):Int={
48 | val labels:JMap[PdfInteger,PageLabel]=doc.getPageLabels()
49 | labels.foreach(kv=>{
50 | if(kv._2.getNumberStyle()==PageLabel.NumberStyleEnum.ArabicNumber && kv._2.getPrefix()==null){
51 | return kv._1.getIntValue()
52 | }
53 | })
54 | 0
55 | }
56 | def highlightPages(pages:Pages,clipping:HighlightClipping,numericStart:Int):Boolean={
57 | var desiredHighlight:String=clipping.content
58 | var intervalFilter:PDFHighlightIntervalFilter=null
59 | var page:Page=null
60 | var pageText:String=null
61 | var textMap:JMap[Rectangle2D,JList[ITextString]]=null
62 | var i:Int=0
63 | for(i<-((clipping.firstPage+numericStart)-1) until (clipping.lastPage+numericStart)){
64 | page=pages.get(i)
65 | textMap= txtExtractor.extract(page)
66 | pageText=TextExtractor.toString(textMap)
67 | intervalFilter=new PDFHighlightIntervalFilter(page,pageText,desiredHighlight)
68 | txtExtractor.filter(textMap,intervalFilter)
69 |
70 | intervalFilter.getRemainingText match{
71 | case Some(s:String)=>{
72 | desiredHighlight=s
73 | }
74 | case None=>
75 | }
76 | }
77 | true
78 | }
79 | }
--------------------------------------------------------------------------------
/samples.txt:
--------------------------------------------------------------------------------
1 | package org.pdfclown.samples.cli;
2 |
3 | import java.awt.geom.Rectangle2D;
4 | import java.util.ArrayList;
5 | import java.util.List;
6 | import java.util.Map;
7 | import java.util.regex.Matcher;
8 | import java.util.regex.Pattern;
9 |
10 | import org.pdfclown.documents.Page;
11 | import org.pdfclown.documents.contents.ITextString;
12 | import org.pdfclown.documents.contents.TextChar;
13 | import org.pdfclown.documents.interaction.annotations.TextMarkup;
14 | import org.pdfclown.documents.interaction.annotations.TextMarkup.MarkupTypeEnum;
15 | import org.pdfclown.files.File;
16 | import org.pdfclown.tools.TextExtractor;
17 | import org.pdfclown.util.math.Interval;
18 | import org.pdfclown.util.math.geom.Quad;
19 |
20 | /**
21 | This sample demonstrates how to highlight text matching arbitrary patterns.
22 |
Highlighting is defined through text markup annotations.
23 |
24 | @author Stefano Chizzolini (http://www.stefanochizzolini.it)
25 | @since 0.1.1
26 | @version 0.1.2, 09/24/12
27 | */
28 | public class TextHighlightSample
29 | extends Sample
30 | {
31 | @Override
32 | public void run(
33 | )
34 | {
35 | // 1. Opening the PDF file...
36 | File file;
37 | {
38 | String filePath = promptFileChoice("Please select a PDF file");
39 | try
40 | {file = new File(filePath);}
41 | catch(Exception e)
42 | {throw new RuntimeException(filePath + " file access error.",e);}
43 | }
44 |
45 | // Define the text pattern to look for!
46 | String textRegEx = promptChoice("Please enter the pattern to look for: ");
47 | Pattern pattern = Pattern.compile(textRegEx, Pattern.CASE_INSENSITIVE);
48 |
49 | // 2. Iterating through the document pages...
50 | TextExtractor textExtractor = new TextExtractor(true, true);
51 | for(final Page page : file.getDocument().getPages())
52 | {
53 | System.out.println("\nScanning page " + (page.getIndex()+1) + "...\n");
54 |
55 | // 2.1. Extract the page text!
56 | Map> textStrings = textExtractor.extract(page);
57 |
58 | // 2.2. Find the text pattern matches!
59 | final Matcher matcher = pattern.matcher(TextExtractor.toString(textStrings));
60 |
61 | // 2.3. Highlight the text pattern matches!
62 | textExtractor.filter(
63 | textStrings,
64 | new TextExtractor.IIntervalFilter(
65 | )
66 | {
67 | @Override
68 | public boolean hasNext(
69 | )
70 | {return matcher.find();}
71 |
72 | @Override
73 | public Interval next(
74 | )
75 | {return new Interval(matcher.start(), matcher.end());}
76 |
77 | @Override
78 | public void process(
79 | Interval interval,
80 | ITextString match
81 | )
82 | {
83 | // Defining the highlight box of the text pattern match...
84 | List highlightQuads = new ArrayList();
85 | {
86 | /*
87 | NOTE: A text pattern match may be split across multiple contiguous lines,
88 | so we have to define a distinct highlight box for each text chunk.
89 | */
90 | Rectangle2D textBox = null;
91 | for(TextChar textChar : match.getTextChars())
92 | {
93 | Rectangle2D textCharBox = textChar.getBox();
94 | if(textBox == null)
95 | {textBox = (Rectangle2D)textCharBox.clone();}
96 | else
97 | {
98 | if(textCharBox.getY() > textBox.getMaxY())
99 | {
100 | highlightQuads.add(Quad.get(textBox));
101 | textBox = (Rectangle2D)textCharBox.clone();
102 | }
103 | else
104 | {textBox.add(textCharBox);}
105 | }
106 | }
107 | highlightQuads.add(Quad.get(textBox));
108 | }
109 | // Highlight the text pattern match!
110 | new TextMarkup(page, null, MarkupTypeEnum.Highlight, highlightQuads);
111 | }
112 |
113 | @Override
114 | public void remove(
115 | )
116 | {throw new UnsupportedOperationException();}
117 | }
118 | );
119 | }
120 |
121 | // 3. Highlighted file serialization.
122 | serialize(file);
123 | }
124 | }
125 |
126 |
127 |
128 | public void filter(
129 | Map> textStrings,
130 | IIntervalFilter filter
131 | )
132 | {
133 | Iterator> textStringsIterator = textStrings.values().iterator();
134 | if(!textStringsIterator.hasNext())
135 | return;
136 |
137 | Iterator areaTextStringsIterator = textStringsIterator.next().iterator();
138 | if(!areaTextStringsIterator.hasNext())
139 | return;
140 |
141 | List textChars = areaTextStringsIterator.next().getTextChars();
142 | int baseTextCharIndex = 0;
143 | int textCharIndex = 0;
144 | while(filter.hasNext())
145 | {
146 | Interval interval = filter.next();
147 | TextString match = new TextString();
148 | {
149 | int matchStartIndex = interval.getLow();
150 | int matchEndIndex = interval.getHigh();
151 | while(matchStartIndex > baseTextCharIndex + textChars.size())
152 | {
153 | baseTextCharIndex += textChars.size();
154 | if(!areaTextStringsIterator.hasNext())
155 | {areaTextStringsIterator = textStringsIterator.next().iterator();}
156 | textChars = areaTextStringsIterator.next().getTextChars();
157 | }
158 | textCharIndex = matchStartIndex - baseTextCharIndex;
159 |
160 | while(baseTextCharIndex + textCharIndex < matchEndIndex)
161 | {
162 | if(textCharIndex == textChars.size())
163 | {
164 | baseTextCharIndex += textChars.size();
165 | if(!areaTextStringsIterator.hasNext())
166 | {areaTextStringsIterator = textStringsIterator.next().iterator();}
167 | textChars = areaTextStringsIterator.next().getTextChars();
168 | textCharIndex = 0;
169 | }
170 | match.textChars.add(textChars.get(textCharIndex++));
171 | }
172 | }
173 | filter.process(interval, match);
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/src/test/resources/pdfHighlightTest.txt:
--------------------------------------------------------------------------------
1 | agile_contracts_primer
2 | - Your Highlight on page 4-4 | Added on Saturday, 18 January 2014 06:17:44
3 |
4 | key difference is the approach to and understanding of operational process and delivery and how this is captured in or intersects with contracts
5 | ==========
6 | agile_contracts_primer
7 | - Your Highlight on page 4-4 | Added on Saturday, 18 January 2014 06:19:00
8 |
9 | Contracts reflect people’s hopes and, especially, fears. Successful projects are not ultimately born from contracts, but from relationships based on collaboration, transparency, and trust.‘Successful’ contracts contain mechanisms that support the building of collaboration, transparency, and trust. As trust builds between a customer and supplier, the commercial and contract model should ‘relax’ to support increasing “customer collaboration over contract negotiation. ”
10 | ==========
11 | agile_contracts_primer
12 | - Your Highlight on page 6-6 | Added on Saturday, 18 January 2014 06:23:40
13 |
14 | First, it is common that they view it as similar to a construction project—relatively predictable—rather than the highly uncertain and variable research and development that it usually is.
15 | ==========
16 | agile_contracts_primer
17 | - Your Highlight on page 7-7 | Added on Saturday, 18 January 2014 06:28:37
18 |
19 | These assumptions are invalidated in agile development.
20 | ==========
21 | agile_contracts_primer
22 | - Your Highlight on page 7-7 | Added on Saturday, 18 January 2014 06:29:25
23 |
24 | The first and perhaps most common misunderstanding is to misinterpret the agile values in terms of a false dichotomy; that is, “customer collaboration is good and contract negotiation is bad” rather than, to quote the Agile Manifesto, …while there is value in the items on the right, we value the items on the left more
25 | ==========
26 | agile_contracts_primer
27 | - Your Highlight on page 8-8 | Added on Saturday, 18 January 2014 06:31:15
28 |
29 | The very thing the contract is ultimately about, the expectation of a deliverable (for example, software that will accelerate bills to be processed), is not in the top ten issues
30 | ==========
31 | agile_contracts_primer
32 | - Your Highlight on page 9-9 | Added on Saturday, 18 January 2014 06:32:59
33 |
34 | win-win” approach is really what is mutually optimal
35 | ==========
36 | agile_contracts_primer
37 | - Your Highlight on page 9-9 | Added on Monday, 20 January 2014 08:10:38
38 |
39 | without understanding the larger impact of their choices and actions or ignoring higher-level goals of the system.
40 | ==========
41 | agile_contracts_primer
42 | - Your Highlight on page 9-9 | Added on Monday, 20 January 2014 08:11:10
43 |
44 | On this last point: Measurement and incentives not only inject dysfunction and locally optimizing behavior into project delivery, they do likewise in contract writing. If professionals in a legal department are rewarded on the basis of legal outcomes, there may be fewer legal issues—but not greater project success
45 | ==========
46 | agile_contracts_primer
47 | - Your Highlight on page 9-9 | Added on Monday, 20 January 2014 08:17:41
48 |
49 | also of the legal professionals’ ability to foster a framework for collaboration and success
50 | ==========
51 | agile_contracts_primer
52 | - Your Highlight on page 10-10 | Added on Monday, 20 January 2014 08:18:48
53 |
54 | how important are they in the larger picture of ensuring the success of the underlying focus of the contract—the project? There is an amusing story [Parkinson57] told by the British civil servant, C. Northcote Parkinson, illustrating his Law of Triviality: Time spent on any item of an agenda is inversely proportional to the cost of the item. He shares the story of a government steering committee with two items on the agenda: 1) the choice of technology for a nuclear power plant, and 2) the choice of coffee for the meetings. The government mandarins, overwhelmed by the technical complexities and science, quickly pass the technology recommendation of the advising engineer, but everybody has an opinion on the coffee—and wants to discuss it at length. A similar dynamic plays out amongst lawyers writing project contracts: There is an inverse relationship between time spent on the terms that are being negotiated and what is being dealt with on a day-to-day level during execution of the project. But there is good news with respect to negotiating issues: An agile and iterative approach can—by design—decrease risk.Therefore, pressure on negotiating “big issue” terms (such as liability) is alleviated because agile methods imply early and frequent incremental delivery of done slices of the system. The early feedback and delivery of a working system every two weeks (for example) fundamentally changes the dynamics behind negotiating some terms, whose excruciating negotiation in traditional ‘waterfall’ projects is driven by the assumption (and fear) of a long delay before delivery. One can understand how extreme pressure comes to bear on articulating terms, when viewed in the light of a big “all or nothing” delivery model. Because of the small, iterative nature of deliverables in an agile approach and the ability to stop the project at any two-week boundary (since each incrementally small slice of the system is done and potentially deployable or ‘shippable’), there should be less pressure on concepts such as liability multiples and indemnity. In The Fifth Discipline, Peter Senge states that systems thinking and a learning organization are ultimately aimed at building “…organizations where people continually expand their capacity to create results they truly desire, where new and expansive patterns of thinking are nurtured, where collec-10
55 | ==========
56 | agile_contracts_primer
57 | - Your Highlight on page 10-10 | Added on Monday, 20 January 2014 23:25:17
58 |
59 | An agile and iterative approach can—by design—decrease risk
60 | ==========
61 | agile_contracts_primer
62 | - Your Highlight on page 11-11 | Added on Monday, 20 January 2014 23:27:11
63 |
64 | …Lawyers study the impact of potentially deployable two-week increments on assumptions and contracts
65 | ==========
66 | agile_contracts_primer
67 | - Your Highlight on page 11-11 | Added on Monday, 20 January 2014 23:28:29
68 |
69 | This means that a supplier cannot fully be comfortable with the deliverable until the end of the project, and may not therefore be able to recognize total order value until the final deliverable.
70 | ==========
71 | agile_contracts_primer
72 | - Your Highlight on page 11-11 | Added on Monday, 20 January 2014 23:29:14
73 |
74 | aims to build not partial components of a project iteratively, but rather to build a deployable working model of value to the customer that can be accepted and used at each two-week iteration
75 | ==========
76 | agile_contracts_primer
77 | - Your Highlight on page 11-11 | Added on Monday, 20 January 2014 23:29:48
78 |
79 | agile model of delivering a useful deployable system after each short iteration
80 | ==========
81 | agile_contracts_primer
82 | - Your Highlight on page 12-12 | Added on Monday, 20 January 2014 23:31:23
83 |
84 | The customer has something of value that she has paid for and accepted
85 | ==========
86 | agile_contracts_primer
87 | - Your Highlight on page 13-13 | Added on Monday, 20 January 2014 23:33:57
88 |
89 | An agile approach contemplates that requirements will be articulated in an iterative and evolutionary manner so that time and money is not wasted in developing software for requirements that are not ultimately needed
90 | ==========
91 | agile_contracts_primer
92 | - Your Highlight on page 13-13 | Added on Monday, 20 January 2014 23:35:10
93 |
94 | money may be better spent for requirements that were not recognized at the beginning
95 | ==========
96 | agile_contracts_primer
97 | - Your Highlight on page 13-13 | Added on Monday, 20 January 2014 23:35:34
98 |
99 | Requirements identified and developed in a sequential-development project may never be used, because they were ill-conceived or lacked effective engagement with real users.
100 | ==========
101 | agile_contracts_primer
102 | - Your Highlight on page 13-13 | Added on Monday, 20 January 2014 23:36:00
103 |
104 | that “conforms to the contract,” requirements still need to be added to meet the true needs. From a contractual perspective, this means that a contract based on a sequential
105 | ==========
106 | agile_contracts_primer
107 | - Your Highlight on page 13-13 | Added on Monday, 20 January 2014 23:36:24
108 |
109 | a contractual perspective, this means that a contract based on a sequential approach will actually increase
110 | ==========
111 | agile_contracts_primer
112 | - Your Highlight on page 13-13 | Added on Monday, 20 January 2014 23:36:34
113 |
114 | From a contractual perspective, this means that a contract based on a sequential approach will actually increase the risk that the client pays more and gets less than she expects
115 | ==========
116 | agile_contracts_primer
117 | - Your Highlight on page 13-13 | Added on Monday, 20 January 2014 23:37:35
118 |
119 | The attendant contract will not protect against this scenario but will actually promote it by incorrectly assuming that it is quite possible to define and deliver a large set of requirements without ongoing feedback and evolution of understanding.
120 | ==========
121 | agile_contracts_primer
122 | - Your Highlight on page 13-13 | Added on Monday, 20 January 2014 23:39:20
123 |
124 | Hence, once a lawyer knows about agile principles, she will be neglectful if she does not protect her client’s interests by continuing to allow (by continuing to write traditional contracts) that client to pay for what she doesn’t need and then allowing that client to pay extra to realize what she truly needed
125 | ==========
126 | agile_contracts_primer
127 | - Your Highlight on page 14-14 | Added on Tuesday, 21 January 2014 01:03:41
128 |
129 | Heighten lawyer sensitivity to software project complexity by analogies to legal work
130 | ==========
131 | agile_contracts_primer
132 | - Your Highlight on page 14-14 | Added on Tuesday, 21 January 2014 01:04:20
133 |
134 | want a fully complete project contract for my new project: A new enterprise-wide financial management system that will probably involve around 200 development people in six countries involving four outsourcing service providers never used before, and that takes between two and four years to complete. To the exact hour, how long will it take you to negotiate and write the contract with the four providers? To the exact word count, how many words will be in the contract? What will be the exact cost?”
135 | ==========
136 | agile_contracts_primer
137 | - Your Highlight on page 15-15 | Added on Tuesday, 21 January 2014 01:05:41
138 |
139 | there is ample evidence incentives lead to increased gaming, a reduction in transparency and quality, and other dysfunctions. Research was summarized in the Organization chapter of our book Scaling Lean & Agile Development.
140 | ==========
141 | agile_contracts_primer
142 | - Your Highlight on page 16-16 | Added on Tuesday, 21 January 2014 01:12:00
143 |
144 | Contract lawyers need to understand the Definition of Done because it changes how agile contacts are framed, and how projects are done. In short, the Scrum Definition of Done defines the “doneness” of the product increment each iteration in terms of activities and artifacts
145 | ==========
146 | agile_contracts_primer
147 | - Your Highlight on page 16-16 | Added on Tuesday, 21 January 2014 01:12:34
148 |
149 | coded, integrated, functional/performance/usability tested, documented
150 | ==========
151 | agile_contracts_primer
152 | - Your Highlight on page 19-19 | Added on Tuesday, 21 January 2014 01:17:16
153 |
154 | However, the content of these topics in the contract—and legal professional’s mindset behind it—contains elements that support collaboration, learning, and evolution.
155 | ==========
156 | agile_contracts_primer
157 | - Your Highlight on page 19-19 | Added on Tuesday, 21 January 2014 01:17:53
158 |
159 | At the end of each two-week (or up to four-week) timeboxed iteration, deliver a deployable system with useful features. – it may have insufficient functionality to be of interest to deploy, but each cycle it is closer to interesting deployment
160 | ==========
161 | agile_contracts_primer
162 | - Your Highlight on page 20-20 | Added on Tuesday, 21 January 2014 01:18:24
163 |
164 | doneness and deployability—each iteration delivery is done, programmed, tested, and so on, and is in theory deployable - duration—smaller, usually two weeks - timeboxing—fixed time but variable scope
165 | ==========
166 | agile_contracts_primer
167 | - Your Highlight on page 20-20 | Added on Tuesday, 21 January 2014 01:26:10
168 |
169 | Agile contracts do not define an exact and unchanging project scope
170 | ==========
171 | agile_contracts_primer
172 | - Your Highlight on page 20-20 | Added on Tuesday, 21 January 2014 01:26:56
173 |
174 | target-cost contracts, in which the overall project scope and details are identified at the start as best as possible
175 | ==========
176 | agile_contracts_primer
177 | - Your Highlight on page 20-20 | Added on Tuesday, 21 January 2014 01:27:20
178 |
179 | progressive contracts, in which no (necessary) scope is defined beyond one iteration
180 | ==========
181 | agile_contracts_primer
182 | - Your Highlight on page 21-21 | Added on Monday, 9 March 2015 20:44:58
183 |
184 | The issue of change is largely inherently addressed within the overall philosophy of an agile approach because of a re-prioritizable backlog and adaptive iterative planning
185 | ==========
186 | agile_contracts_primer
187 | - Your Highlight on page 21-21 | Added on Monday, 9 March 2015 20:46:50
188 |
189 | change in relationships between parties
190 | ==========
191 | agile_contracts_primer
192 | - Your Highlight on page 21-21 | Added on Monday, 9 March 2015 20:47:22
193 |
194 | change in project scope – This area requires the most care in contracting, to prevent subverting the point of agile development: to make change easy and frequent in the collaboration between customer and vendor. Avoid mandating change-management boards, change requests, or special change processes. – But, as with project scope, there are variations in change-management flexibility, ranging from high flexibility without penalty when using flexible-scope progressive contracts, to medium flexibility with shared gain/pain when using target-cost models.
195 | ==========
196 | agile_contracts_primer
197 | - Your Highlight on page 21-21 | Added on Monday, 9 March 2015 20:47:50
198 |
199 | early termination should be viewed as a positive, desirable event in an agile project
200 | ==========
201 | agile_contracts_primer
202 | - Your Highlight on page 22-22 | Added on Monday, 9 March 2015 20:48:38
203 |
204 | both parties will have clear and up-to-date views on the state of the deliverable. These are crucial points for legal professionals to grasp
205 | ==========
206 | agile_contracts_primer
207 | - Your Highlight on page 22-22 | Added on Monday, 9 March 2015 20:49:45
208 |
209 | Is it done?”—“What to do if not done?”—“We have now decided to change our minds and reject the iteration delivery from three iterations ago. Do you mind
210 | ==========
211 | agile_contracts_primer
212 | - Your Highlight on page 22-22 | Added on Monday, 9 March 2015 20:50:08
213 |
214 | Clarity (in so far as practically feasible) regarding doneness, acceptance, and correction both in the minds of the parties and the contract language should be a leading concern for legal professionals
215 | ==========
216 | agile_contracts_primer
217 | - Your Highlight on page 22-22 | Added on Monday, 9 March 2015 20:50:24
218 |
219 | negotiating a contractual framework for acceptance that encourages collaboration
220 | ==========
221 | agile_contracts_primer
222 | - Your Highlight on page 22-22 | Added on Monday, 9 March 2015 20:51:14
223 |
224 | only the framework for acceptance must be contractually clear
225 | ==========
226 | agile_contracts_primer
227 | - Your Highlight on page 22-22 | Added on Monday, 9 March 2015 20:51:53
228 |
229 | Legal professionals concerned with a successful project should ask, “Are the right people—the hands-on users—involved in acceptance, and at each iteration are they collaborating with the supplier?” 22
230 | ==========
231 | agile_contracts_primer
232 | - Your Highlight on page 23-23 | Added on Monday, 9 March 2015 20:52:24
233 |
234 | Sample clauses
235 | ==========
236 | agile_contracts_primer
237 | - Your Highlight on page 24-24 | Added on Monday, 9 March 2015 21:02:09
238 |
239 | an agile approach, the same problematic bills could be sent. But it is also possible that those bills would be sent early to a much smaller subset of customers, using an early release of the system with just-sufficient functionality to field-test this critical feature
240 | ==========
241 | agile_contracts_primer
242 | - Your Highlight on page 24 | Added on Monday, 9 March 2015 21:02:55
243 |
244 | Warranty
245 | ==========
246 | agile_contracts_primer
247 | - Your Highlight on page 24-24 | Added on Monday, 9 March 2015 21:03:38
248 |
249 | leads to an increase in waste activities rather than a focus on working software, and there is a presumption—possibly untrue—of knowing what artifacts are valuable. - There is a focus on negotiating and conforming to “quality plans” rather than cooperating to create useful software24
250 | ==========
251 | agile_contracts_primer
252 | - Your Highlight on page 25-25 | Added on Monday, 9 March 2015 21:04:46
253 |
254 | reinforces (the illusory) command-control predictive-planning mindset rather than learning and responding to change. - It reinforces the (untrue) belief that a fully defined system can be predictably ordered and delivered as though it were a meal in a restaurant rather than creative discovery work.
255 | ==========
256 | agile_contracts_primer
257 | - Your Highlight on page 25-25 | Added on Tuesday, 10 March 2015 10:14:33
258 |
259 | On occasion, technical documentation to support maintenance is valuable
260 | ==========
261 | agile_contracts_primer
262 | - Your Highlight on page 25-25 | Added on Tuesday, 10 March 2015 10:15:36
263 |
264 | could be wasteful to require it as an early deliverable.
265 | ==========
266 | agile_contracts_primer
267 | - Your Highlight on page 25-25 | Added on Tuesday, 10 March 2015 10:16:21
268 |
269 | after the system is finished.
270 | ==========
271 | agile_contracts_primer
272 | - Your Highlight on page 25-25 | Added on Tuesday, 10 March 2015 10:16:52
273 |
274 | Timing of Payment
275 | ==========
276 | agile_contracts_primer
277 | - Your Highlight on page 26-26 | Added on Tuesday, 10 March 2015 10:19:51
278 |
279 | Fixed price per iteration (per unit of time
280 | ==========
281 | agile_contracts_primer
282 | - Your Highlight on page 26-26 | Added on Tuesday, 10 March 2015 10:21:09
283 |
284 | key issue (or cost) for customers is that the supplier adds a contingency fee to the rate because of the risk associated with variability in research and development work.
285 | ==========
286 | agile_contracts_primer
287 | - Your Highlight on page 27-27 | Added on Tuesday, 10 March 2015 10:23:51
288 |
289 | pay-per-use contracts with their customers
290 | ==========
291 | agile_contracts_primer
292 | - Your Highlight on page 29-29 | Added on Tuesday, 10 March 2015 10:25:51
293 |
294 | Avoid…Fixed-price, fixed-scope (FPFS) contracts
295 | ==========
296 | agile_contracts_primer
297 | - Your Highlight on page 29-29 | Added on Tuesday, 10 March 2015 10:29:10
298 |
299 | suppliers can easily lose money. And in an effort to deliver something within the constraints of price and scope, suppliers will often degrade the quality of their work
300 | ==========
301 | agile_contracts_primer
302 | - Your Highlight on page 30-30 | Added on Tuesday, 10 March 2015 10:30:42
303 |
304 | supplier generates further revenue—in India, outsourcers call this ‘rent’—through a series of follow-on change requests, each for an additional cost beyond the original fixed price
305 | ==========
306 | agile_contracts_primer
307 | - Your Highlight on page 31-31 | Added on Tuesday, 10 March 2015 10:34:41
308 |
309 | Do not allow any changes in requirements or scope, or only allow new requirements to displace existing requirements if they are of equal effort
310 | ==========
311 | agile_contracts_primer
312 | - Your Highlight on page 31-31 | Added on Tuesday, 10 March 2015 10:35:05
313 |
314 | Increase the margin of the contract price, to reflect the significant risk inherent in FPFS software development—a domain that is fraught with discovery, variability, and nasty surprises. - Employ experienced domain experts with towering technical excellence
315 | ==========
316 | agile_contracts_primer
317 | - Your Highlight on page 31-31 | Added on Tuesday, 10 March 2015 10:36:26
318 |
319 | displace existing requirements with new ones of equal effort
320 | ==========
321 | agile_contracts_primer
322 | - Your Highlight on page 31-31 | Added on Tuesday, 10 March 2015 10:36:50
323 |
324 | Customer may request additional releases at any time, priced with T&M.
325 | ==========
326 | agile_contracts_primer
327 | - Your Highlight on page 32-32 | Added on Tuesday, 10 March 2015 10:37:21
328 |
329 | Customer may terminate early if satisfied early, for a payment to supplier of 20% of remaining unbilled value
330 | ==========
331 | agile_contracts_primer
332 | - Your Highlight on page 32-32 | Added on Tuesday, 10 March 2015 10:37:44
333 |
334 | There is evidence that sequential life cycle development is correlated with higher cost, slower delivery, lower productivity, more defects, or higher failure rates, compared with iterative, incremental, or agile methods
335 | ==========
336 | agile_contracts_primer
337 | - Your Highlight on page 33-33 | Added on Tuesday, 10 March 2015 10:39:13
338 |
339 | Try…Variable-price variable-scope progressive contracts
340 | ==========
341 | agile_contracts_primer
342 | - Your Highlight on page 33-33 | Added on Tuesday, 10 March 2015 10:43:51
343 |
344 | Contract Evolution on a Large Agile Project
345 | ==========
346 | agile_contracts_primer
347 | - Your Highlight on page 34-34 | Added on Tuesday, 10 March 2015 10:48:28
348 |
349 | the goals for iteration N are clarified during iteration N-2
350 | ==========
351 | agile_contracts_primer
352 | - Your Highlight on page 34-34 | Added on Tuesday, 10 March 2015 10:48:55
353 |
354 | price variable-scope progressive contract is common; there is an overall project price cap
355 | ==========
356 | agile_contracts_primer
357 | - Your Highlight on page 34-34 | Added on Tuesday, 10 March 2015 10:49:16
358 |
359 | This backlog is included as an appendix to the contract.However, it is agreed that nothing in the original backlog is binding
360 | ==========
361 | agile_contracts_primer
362 | - Your Highlight on page 35-35 | Added on Tuesday, 10 March 2015 10:49:59
363 |
364 | frequent pattern (not a recommendation) is 1. 2.early contracts that are variations of fixed price and fixed scope later, a shift to progressive contracts with simple T&M or capped T&M per iteration
365 | ==========
366 | agile_contracts_primer
367 | - Your Highlight on page 35-35 | Added on Tuesday, 10 March 2015 10:54:43
368 |
369 | …Increase flexibility in project and contract variables
370 | ==========
371 | agile_contracts_primer
372 | - Your Highlight on page 35-35 | Added on Tuesday, 10 March 2015 11:12:29
373 |
374 | If trust is low, customers can bound their risk (and fear) by using a series of short-duration, flexible contracts. For example, one year-long, fixed-price, fixed-date, variable-scope contract may be viewed with trepidation. But a series of two-month, fixed-price, fixed-date, variable-scope contracts—with the ability to terminate at the end any cycle—is more palatable
375 | ==========
376 | Plano de Negócios_Como Elaborar_Sebrae_2013
377 | - Your Highlight on page 19-19 | Added on Friday, 13 March 2015 16:28:25
378 |
379 | sumário contendo seus pontos mais importantes
380 | ==========
381 | Plano de Negócios_Como Elaborar_Sebrae_2013
382 | - Your Highlight on page 19-19 | Added on Friday, 13 March 2015 16:28:43
383 |
384 | Missão da empresa
385 | ==========
386 | agile_contracts_primer
387 | - Your Highlight on page 36-36 | Added on Monday, 16 March 2015 13:54:35
388 |
389 | They are used in Toyota with their suppliers, reflecting the pillar of respect for people in lean thinking
390 | ==========
391 | agile_contracts_primer
392 | - Your Highlight on page 36-36 | Added on Monday, 16 March 2015 13:55:06
393 |
394 | target-cost contracts must realistically account for overall effort and cost as best as possible.20. That usually means placing requirement-related risks (‘what’) in the hands of the customer, and placing implementation and technical-related risks (‘how’) in the hands of the supplier36
395 | ==========
396 | agile_contracts_primer
397 | - Your Highlight on page 37-37 | Added on Monday, 16 March 2015 13:57:17
398 |
399 | As will be seen, Adjustment may be positive or negative
400 | ==========
401 | agile_contracts_primer
402 | - Your Highlight on page 39-39 | Added on Monday, 16 March 2015 14:02:28
403 |
404 | One Valtech multi-phase variable-model example reflects the common Scrum pattern
405 | ==========
--------------------------------------------------------------------------------
/src/test/resources/MyClippings.txt:
--------------------------------------------------------------------------------
1 | CONDICIONAL - 1ª revisao.docx
2 | - Your Bookmark on Page 9 | Added on Saturday, 21 September 13 00:20:29
3 |
4 |
5 | ==========
6 | CONDICIONAL - 1ª revisao.docx
7 | - Your Note on Page 12 | Added on Saturday, 21 September 13 00:25:32
8 |
9 | untroducao muito boa.seduzivel enquanto falq de sefucao
10 | ==========
11 | CONDICIONAL - 1ª revisao.docx
12 | - Your Highlight on Page 12-12 | Added on Saturday, 21 September 13 00:25:32
13 |
14 | que são seduzíveis. Conheci tantas pessoas que ficavam me encarando sem dizer nada e eu tinha certeza que, no fundo, elas deviam interiorizar o questionamento sobre o tipo de cara que eu deveria ser, mas elas nunca me perguntaram diretamente e imagino que era por medo de que eu acabasse sendo sincero. “Você é bonito, mas devo confiar em você?” – Não! Naquela época eu diria que não rapidamente para facilitar o desapego. Não me recordo de pelo menos uma vez na vida ter sido questionado. Simplesmente não queriam saber. Deixavam pra descobrir tentando a sorte... Sou o Lucas. Já ia quase me esquecendo. Fico empolgado quando começo a me descrever e me desconstruir a ponto até de achar dispensáveis as apresentações formais. Penso que é interessante começar assim com ar prepotente e cheio de mim, pois, talvez ninguém fosse ler minha história procurando também se perguntar “Devo confiar nele?”caso eu começasse com papo furado vendendo uma imagem hipócrita para agradar. Neste caso, me revelo te 11
15 | ==========
16 | Magento PHP Developer's Guide
17 | - Your Bookmark on Page 67 | Added on Saturday, 28 September 13 14:09:35
18 |
19 |
20 | ==========
21 | Magento PHP Developer's Guide
22 | - Your Bookmark on Page 67 | Added on Saturday, 28 September 13 14:09:49
23 |
24 |
25 | ==========
26 | Magento PHP Developer's Guide
27 | - Your Bookmark on Page 67 | Added on Saturday, 28 September 13 14:09:51
28 |
29 |
30 | ==========
31 | Magento PHP Developer's Guide
32 | - Your Bookmark on Page 65 | Added on Saturday, 28 September 13 14:10:03
33 |
34 |
35 | ==========
36 | Magento PHP Developer's Guide
37 | - Your Bookmark on Page 3 | Added on Saturday, 28 September 13 14:10:26
38 |
39 |
40 | ==========
41 | Magento PHP Developer's Guide
42 | - Your Bookmark on Page 3 | Added on Saturday, 28 September 13 14:10:29
43 |
44 |
45 | ==========
46 | Magento PHP Developer's Guide
47 | - Your Bookmark on Page 32 | Added on Saturday, 28 September 13 16:52:56
48 |
49 |
50 | ==========
51 | Magento Beginner’s Guide Second Edition (Ravensbergen, Robbert;Schoneville, Sander)
52 | - Your Bookmark Location 2722 | Added on Saturday, 28 September 13 16:54:25
53 |
54 |
55 | ==========
56 | Magento PHP Developer's Guide
57 | - Your Bookmark on Page 4 | Added on Saturday, 28 September 13 18:12:11
58 |
59 |
60 | ==========
61 | Magento PHP Developer's Guide
62 | - Your Bookmark on Page 111 | Added on Monday, 30 September 13 08:35:34
63 |
64 |
65 | ==========
66 | Mastering the SPL Library (Joshua Thijssen)
67 | - Your Highlight Location 362-362 | Added on Monday, 30 September 13 19:03:43
68 |
69 | DJBX33A
70 | ==========
71 | Mastering the SPL Library (Joshua Thijssen)
72 | - Your Highlight Location 362-362 | Added on Monday, 30 September 13 19:04:17
73 |
74 | The algorithm used is called DJBX33A which returns a bucket number (a number between
75 | ==========
76 | Mastering the SPL Library (Joshua Thijssen)
77 | - Your Highlight Location 362-362 | Added on Monday, 30 September 13 19:04:31
78 |
79 | The algorithm used is called DJBX33A
80 | ==========
81 | Mastering the SPL Library (Joshua Thijssen)
82 | - Your Highlight Location 451-452 | Added on Monday, 30 September 13 19:08:10
83 |
84 | makes linked lists very memory efficient data structures with very fast insert/delete capabilities.
85 | ==========
86 | Mastering the SPL Library (Joshua Thijssen)
87 | - Your Highlight Location 460-462 | Added on Monday, 30 September 13 19:09:17
88 |
89 | SplDoublyLinkedLists is a perfect way to save memory while still being able to use (most) array functionality. Its main purpose is to iterate over elements in a sequential way, either forwards or backwards. Do not use this data structure when you are planning to do mostly random reads.
90 | ==========
91 | Mastering the SPL Library (Joshua Thijssen)
92 | - Your Highlight Location 572-572 | Added on Monday, 30 September 13 19:13:23
93 |
94 | Dealing with SplHeap Corruptions
95 | ==========
96 | Mastering the SPL Library (Joshua Thijssen)
97 | - Your Highlight Location 786-786 | Added on Monday, 30 September 13 19:42:57
98 |
99 | This can be done by the spl_object_hash() function.
100 | ==========
101 | Mastering the SPL Library (Joshua Thijssen)
102 | - Your Highlight Location 788-789 | Added on Monday, 30 September 13 19:43:33
103 |
104 | The SplObjectStorage allows you to directly add an object as key without hashing it manually.
105 | ==========
106 | Mastering the SPL Library (Joshua Thijssen)
107 | - Your Highlight Location 790-791 | Added on Monday, 30 September 13 19:44:28
108 |
109 | splObjectStorage also can be used for “sets”.
110 | ==========
111 | Mastering the SPL Library (Joshua Thijssen)
112 | - Your Highlight Location 806-807 | Added on Monday, 30 September 13 19:45:17
113 |
114 | Use this class when you need to maintain a (large) set of objects.
115 | ==========
116 | Mastering the SPL Library (Joshua Thijssen)
117 | - Your Highlight Location 1104-1105 | Added on Monday, 30 September 13 23:42:06
118 |
119 | But the CachingIterator is much more than a simple “lookahead” iterator. It’s second feature is that it is possible to let the iterator “cache” all the values it returns. This
120 | ==========
121 | Mastering the SPL Library (Joshua Thijssen)
122 | - Your Highlight Location 1193-1194 | Added on Monday, 30 September 13 23:50:28
123 |
124 | you need to clone() the objects if you are going to reuse them outside your iterator foreach() loop:
125 | ==========
126 | Mastering the SPL Library (Joshua Thijssen)
127 | - Your Highlight Location 1209-1209 | Added on Monday, 30 September 13 23:58:28
128 |
129 | FilesystemIterator
130 | ==========
131 | Mastering the SPL Library (Joshua Thijssen)
132 | - Your Highlight Location 1333-1334 | Added on Tuesday, 1 October 13 08:53:42
133 |
134 | The IteratorIterator can create an iterator out from anything that has implemented traversable.
135 | ==========
136 | Mastering the SPL Library (Joshua Thijssen)
137 | - Your Highlight Location 1354-1354 | Added on Tuesday, 1 October 13 08:57:08
138 |
139 | MultipleIterator
140 | ==========
141 | Mastering the SPL Library (Joshua Thijssen)
142 | - Your Highlight Location 1397-1398 | Added on Tuesday, 1 October 13 08:58:56
143 |
144 | This iterator is useful for filtering out elements that CAN be recursed.
145 | ==========
146 | Mastering the SPL Library (Joshua Thijssen)
147 | - Your Highlight Location 1474-1476 | Added on Tuesday, 1 October 13 09:05:09
148 |
149 | The purpose of the RecursiveIteratorIterator is to turn any RecursiveIterator into a “plain” iterator so you can traverse it linearly even though the data is recursive
150 | ==========
151 | Mastering the SPL Library (Joshua Thijssen)
152 | - Your Highlight Location 1508-1508 | Added on Tuesday, 1 October 13 09:06:14
153 |
154 | Iteration Hooks
155 | ==========
156 | Mastering the SPL Library (Joshua Thijssen)
157 | - Your Highlight Location 1527-1527 | Added on Tuesday, 1 October 13 09:07:48
158 |
159 | RecursiveTreeIterator
160 | ==========
161 | Mastering the SPL Library (Joshua Thijssen)
162 | - Your Highlight Location 1527-1527 | Added on Tuesday, 1 October 13 09:07:57
163 |
164 | really easy way to create tree-like ASCII structures.
165 | ==========
166 | Mastering the SPL Library (Joshua Thijssen)
167 | - Your Highlight Location 1693-1693 | Added on Tuesday, 1 October 13 09:13:32
168 |
169 | This is only possible by interfaces defined by PHP itself, since they are written in C
170 | ==========
171 | Mastering the SPL Library (Joshua Thijssen)
172 | - Your Highlight Location 1693-1694 | Added on Tuesday, 1 October 13 09:13:45
173 |
174 | It is not possible for you to create this kind of functionality, unless you implement them as PHP extensions or directly in the PHP core.
175 | ==========
176 | Mastering the SPL Library (Joshua Thijssen)
177 | - Your Highlight Location 1722-1724 | Added on Tuesday, 1 October 13 09:15:26
178 |
179 | Do not try to check if an object is traversable by checking for Iterator or IteratorAggregate directly, but use the Traversable interface instead.
180 | ==========
181 | Mastering the SPL Library (Joshua Thijssen)
182 | - Your Highlight Location 1841-1842 | Added on Tuesday, 1 October 13 09:19:36
183 |
184 | will not call __destruct() prior to the actual serialization. If you need this functionality, you need to add it yourself.
185 | ==========
186 | Mastering the SPL Library (Joshua Thijssen)
187 | - Your Highlight Location 1974-1974 | Added on Tuesday, 1 October 13 09:29:53
188 |
189 | SplObserver and SplSubject
190 | ==========
191 | Mastering the SPL Library (Joshua Thijssen)
192 | - Your Highlight Location 2049-2049 | Added on Tuesday, 1 October 13 09:33:32
193 |
194 | “failure-first” principle.
195 | ==========
196 | Mastering the SPL Library (Joshua Thijssen)
197 | - Your Highlight Location 2141-2142 | Added on Tuesday, 1 October 13 09:37:49
198 |
199 | Domain exceptions should reflect the working of your domain instead of the inner workings.
200 | ==========
201 | Mastering the SPL Library (Joshua Thijssen)
202 | - Your Highlight Location 2143-2143 | Added on Tuesday, 1 October 13 09:38:02
203 |
204 | should be extended to reflect a more detailed exception.
205 | ==========
206 | Mastering the SPL Library (Joshua Thijssen)
207 | - Your Highlight Location 2190-2191 | Added on Tuesday, 1 October 13 11:19:05
208 |
209 | Always look for a better suited (logic)exception, since you should throw that particular exception instead of this one.
210 | ==========
211 | Mastering the SPL Library (Joshua Thijssen)
212 | - Your Highlight Location 2386-2387 | Added on Tuesday, 1 October 13 19:29:59
213 |
214 | This would imply that you would register the autoloaders that will load the most classes as early as possible in the queue (you can prepend the autoloaders if needed).
215 | ==========
216 | Mastering the SPL Library (Joshua Thijssen)
217 | - Your Highlight Location 2427-2428 | Added on Tuesday, 1 October 13 19:31:54
218 |
219 | following the PSR-0 can be considered as best practice to ensure maximal interoperability between your code and others, now and in the future.
220 | ==========
221 | expert_php_5_tools
222 | - Your Highlight on Page 333-333 | Added on Tuesday, 1 October 13 19:44:26
223 |
224 | I usually redirect users temporarily to a generic HTML page that informs them that the server is undergoing maintenance and that they should retry their request in a couple of minutes.
225 | ==========
226 | expert_php_5_tools
227 | - Your Highlight on Page 333-333 | Added on Tuesday, 1 October 13 19:45:24
228 |
229 | On systems that support symbolic links (or aliases or shortcuts), it is good practice to have a symlink that points to the directory containing the application files. When it is time to upgrade, you merely have to point the symlink at a different directory and the new files become visible instantly[ 333 ]
230 | ==========
231 | expert_php_5_tools
232 | - Your Highlight on Page 334-334 | Added on Tuesday, 1 October 13 20:12:02
233 |
234 | DbDeploy
235 | ==========
236 | Speed Reading: Easily 5X Your Reading Speed And Comprehension Immediately (Dunar, Michael)
237 | - Your Highlight Location 136-139 | Added on Wednesday, 2 October 13 08:52:31
238 |
239 | Refrain from thinking of another thing while reading – having something else in your awareness aside from what you are reading will result in reading at a slower pace as well as a slower processing of information. If you think that you have to do something, attend to it immediately. It will be more counter-productive if what you’re doing is not aligned with what you’re thinking.
240 | ==========
241 | Speed Reading: Easily 5X Your Reading Speed And Comprehension Immediately (Dunar, Michael)
242 | - Your Highlight Location 140-143 | Added on Wednesday, 2 October 13 08:53:02
243 |
244 | Do not take a mini-break – if you’ve decided to allot one hour for your reading, make sure that you read for the duration of that time. Do not take short breaks. Even a 30-second break can destroy your focus; and according to some researches, it can take at least 15 minutes to get your focus back on that particular activity.
245 | ==========
246 | Speed Reading: Easily 5X Your Reading Speed And Comprehension Immediately (Dunar, Michael)
247 | - Your Highlight Location 369-369 | Added on Wednesday, 2 October 13 09:10:21
248 |
249 | the exercise ten times for each eye.
250 | ==========
251 | Speed Reading: Easily 5X Your Reading Speed And Comprehension Immediately (Dunar, Michael)
252 | - Your Highlight Location 424-425 | Added on Wednesday, 2 October 13 09:13:48
253 |
254 | For readers, these two portions in a paragraph are essential to inform them of its content.
255 | ==========
256 | Machine of Death: A collection of stories about people who know how they will die (North, Ryan)
257 | - Your Highlight on Page 247 | Location 3201-3211 | Added on Thursday, 3 October 13 08:59:20
258 |
259 | hand. Karen smokes a cigarette and looks at nothing. There passes several moments when no one speaks, which I can only describe as uncomfortable. The Spandex guy suddenly remembers the friends he left at the other end of the bar, and returns to them in a single bound or so. Aimee, I notice, has scratched out “NEVER” on her tag and written in “BOREDOM.” I am glad to have a drink because it gives me something to do with my hands. Later, I am taking a deep breath, preparing to say something, anything, when the band starts up again—incredibly loud. Which is how I know Jill’s phone was probably on vibrate. She leans forward on the barstool, holding the phone to one ear and plugging the other with a finger. A deep crease begins to form between her eyebrows. Suddenly, still bent forward in that same position, she bolts. “Don’t—!” I hear her yelling into the phone as she darts headlong through the crowd. I look to the other girls. “What an asshole,” Liza says, turning to Aimee. “Brian’s tag should read, ‘Crushed Under Own Ego.’” “‘Being a Total Dickweed,’” Aimee replies. Karen exhales a cloud of grey smoke. “‘Cock Suckery.’” I have been trying to follow this exchange arcing back and forth over my head like a lethal volleyball. “Really?” I say
260 | ==========
261 | Machine of Death: A collection of stories about people who know how they will die (North, Ryan)
262 | - Your Highlight on Page 249 | Location 3238-3238 | Added on Thursday, 3 October 13 09:02:27
263 |
264 | private and reverent about these things. They don’t wear tags.
265 | ==========
266 | Machine of Death: A collection of stories about people who know how they will die (North, Ryan)
267 | - Your Bookmark on Page 325 | Location 4248 | Added on Sunday, 6 October 13 14:24:56
268 |
269 |
270 | ==========
271 | Machine of Death: A collection of stories about people who know how they will die (North, Ryan)
272 | - Your Bookmark on Page 333 | Location 4336 | Added on Sunday, 6 October 13 15:00:30
273 |
274 |
275 | ==========
276 | Machine of Death: A collection of stories about people who know how they will die (North, Ryan)
277 | - Your Highlight on Page 367 | Location 4776-4777 | Added on Sunday, 6 October 13 19:10:46
278 |
279 | Masks are for daylight—once dusk hits, it’s the moon’s turf, and she likes us naked, naked, naked, just the way she made us.
280 | ==========
281 | Orange Is the New Black: My Time in a Women's Prison (Kerman, Piper)
282 | - Your Bookmark Location 69 | Added on Friday, 18 October 13 17:17:59
283 |
284 |
285 | ==========
286 | Orange Is the New Black: My Time in a Women's Prison (Kerman, Piper)
287 | - Your Highlight Location 855-855 | Added on Friday, 18 October 13 17:22:22
288 |
289 | sale
290 | ==========
291 | Orange Is the New Black: My Time in a Women's Prison (Kerman, Piper)
292 | - Your Highlight Location 874-874 | Added on Friday, 18 October 13 17:25:56
293 |
294 | room at
295 | ==========
296 | Orange Is the New Black: My Time in a Women's Prison (Kerman, Piper)
297 | - Your Highlight Location 874-874 | Added on Friday, 18 October 13 17:30:28
298 |
299 | room at my
300 | ==========
301 | expert_php_5_tools
302 | - Your Bookmark on Page x | Added on Thursday, 24 October 13 08:53:10
303 |
304 |
305 | ==========
306 | expert_php_5_tools
307 | - Your Bookmark on Page x | Added on Thursday, 24 October 13 08:53:33
308 |
309 |
310 | ==========
311 | expert_php_5_tools
312 | - Your Bookmark on Page 4 | Added on Thursday, 24 October 13 08:54:56
313 |
314 |
315 | ==========
316 | expert_php_5_tools
317 | - Your Bookmark on Page 4 | Added on Thursday, 24 October 13 08:56:27
318 |
319 |
320 | ==========
321 | O Hobbit (J. R. R. Tolkien)
322 | - Your Bookmark Location 357 | Added on Monday, 4 November 13 17:13:14
323 |
324 |
325 | ==========
326 | The Healthy Programmer
327 | - Your Bookmark on Page 133 | Added on Tuesday, 5 November 13 17:38:08
328 |
329 |
330 | ==========
331 | The Healthy Programmer
332 | - Your Highlight on Page 24-24 | Added on Tuesday, 5 November 13 18:00:16
333 |
334 | What did I do yesterday to improve my health? • What will I do today to improve my health? • Is there anything blocking me from staying healthy?
335 | ==========
336 | O Hobbit (J. R. R. Tolkien)
337 | - Your Bookmark Location 1046 | Added on Monday, 18 November 13 19:22:06
338 |
339 |
340 | ==========
341 | programming_scala
342 | - Your Highlight on Page 77-77 | Added on Monday, 9 December 13 14:52:01
343 |
344 | structural type of
345 | ==========
346 | programming_scala
347 | - Your Bookmark on Page 112 | Added on Friday, 27 December 13 14:49:34
348 |
349 |
350 | ==========
351 | the_wordpress_anthology
352 | - Your Bookmark on Page xvii | Added on Tuesday, 4 February 14 11:05:45
353 |
354 |
355 | ==========
356 | the_wordpress_anthology
357 | - Your Highlight on Page 243-243 | Added on Tuesday, 4 February 14 11:16:00
358 |
359 | load_theme_textdomain() for themes, or load_plugin_textdomain() for
360 | ==========
361 | the_wordpress_anthology
362 | - Your Highlight on Page 250-250 | Added on Tuesday, 4 February 14 11:27:34
363 |
364 | With theme localizations, you’ll want to name your . MO file in the format of locale.mo. For example, in translating your theme to German, your theme translation file in the languages directory within your theme should be named de_DE.mo. On the other hand, if you’re localizing a plugin, WordPress will seek the translation
365 | ==========
366 | the_wordpress_anthology
367 | - Your Highlight on Page 250-250 | Added on Tuesday, 4 February 14 11:27:43
368 |
369 | With theme localizations, you’ll want to name your . MO file in the format of locale.mo. For example, in translating your theme to German, your theme translation file in the languages directory within your theme should be named de_DE.mo. On the other hand, if you’re localizing a plugin, WordPress will seek the translation file in your specified languages directory within your plugin in the format of pluginname-locale.mo. In this
370 | ==========
371 | the_wordpress_anthology
372 | - Your Highlight on Page 257-257 | Added on Tuesday, 4 February 14 11:31:24
373 |
374 | This is the tricky part—and essential for creating a . POT file with Poedit. Before you do anything else here, save the file a second time. The reason this is necessary is that when Poedit initially creates the . PO file, it saves the file first and then imports the translatable strings. If you fail to save the file a second time and close it, you'll end up with a blank . PO file that has no translatable strings, thus defeating the purpose. Once you save your . PO file a second time as in Figure 11.11 (with your translatable strings added), close the file and quit Poedit. Don't worry—we’ll be right back
375 | ==========
376 | the_wordpress_anthology
377 | - Your Highlight on Page 53-53 | Added on Tuesday, 4 February 14 11:58:37
378 |
379 | Role Scoper
380 | ==========
381 | the_wordpress_anthology
382 | - Your Bookmark on Page 83 | Added on Tuesday, 4 February 14 12:53:51
383 |
384 |
385 | ==========
386 | the_wordpress_anthology
387 | - Your Bookmark on Page 82 | Added on Tuesday, 4 February 14 12:53:58
388 |
389 |
390 | ==========
391 | the_wordpress_anthology
392 | - Your Highlight on Page 82-82 | Added on Tuesday, 4 February 14 12:54:22
393 |
394 | The Basics of register_post_type()
395 | ==========
396 | node_up_and_running
397 | - Your Highlight on Page 31-31 | Added on Tuesday, 4 February 14 14:37:24
398 |
399 | Because they get passed an array, they will repeat for each item in the array
400 | ==========
401 | node_up_and_running
402 | - Your Highlight on Page 31-31 | Added on Tuesday, 4 February 14 14:37:43
403 |
404 | The template called chirp accesses its data in a variable of the same name. In this case, the data is simple strings, but if we passed in an array of objects, we could do chirp .property or chirp['property'] to access the properties of the objects
405 | ==========
406 | node_up_and_running
407 | - Your Highlight on Page 34-34 | Added on Tuesday, 4 February 14 14:49:17
408 |
409 | it’s “single-threaded” so that only one thing happens at once.
410 | ==========
411 | node_up_and_running
412 | - Your Highlight on Page 37-37 | Added on Tuesday, 4 February 14 14:54:10
413 |
414 | event-driven architectures don’t add anything. If all (or most) of the work your server does is computation
415 | ==========
416 | node_up_and_running
417 | - Your Highlight on Page 40-40 | Added on Tuesday, 4 February 14 15:00:21
418 |
419 | Once setup has been completed, make all actions event-driven. • If Node.js is required to process something that will take a long time, consider delegating it to web workers
420 | ==========
421 | node_up_and_running
422 | - Your Highlight on Page 46-46 | Added on Tuesday, 4 February 14 15:12:03
423 |
424 | An error during the GET cannot be caught by a try/catch block
425 | ==========
426 | node_up_and_running
427 | - Your Highlight on Page 47-47 | Added on Tuesday, 4 February 14 15:13:24
428 |
429 | the error event catches all kinds of exceptions
430 | ==========
431 | node_up_and_running
432 | - Your Highlight on Page 47-47 | Added on Tuesday, 4 February 14 15:14:57
433 |
434 | Node provides a module called cluster that allows you to delegate work to child processes. This means that Node creates a copy of its current program in another process
435 | ==========
436 | node_up_and_running
437 | - Your Highlight on Page 48-48 | Added on Tuesday, 4 February 14 15:17:34
438 |
439 | cluster provides a cross-platform way to invoke several processes that share a socket
440 | ==========
441 | node_up_and_running
442 | - Your Highlight on Page 56-56 | Added on Wednesday, 5 February 14 09:31:46
443 |
444 | EventEmitter has a handful of methods, the main two being on and emit
445 | ==========
446 | node_up_and_running
447 | - Your Highlight on Page 56-56 | Added on Wednesday, 5 February 14 09:32:43
448 |
449 | utils module so we can use the inherits method. inherits provides a way for the EventEmitter class to add its methods to the Server class we created
450 | ==========
451 | node_up_and_running
452 | - Your Highlight on Page 59-59 | Added on Wednesday, 5 February 14 09:36:40
453 |
454 | Consequently, the this variable must be passed in as a parameter and assigned to a variable if we wish to make use of it in event callback functions.
455 | ==========
456 | node_up_and_running
457 | - Your Highlight on Page 65-65 | Added on Wednesday, 5 February 14 09:46:05
458 |
459 | The URL module provides tools for easily parsing and dealing with URL strings
460 | ==========
461 | node_up_and_running
462 | - Your Highlight on Page 68-68 | Added on Wednesday, 5 February 14 09:57:04
463 |
464 | Another important part of querystring is encode
465 | ==========
466 | node_up_and_running
467 | - Your Highlight on Page 71-71 | Added on Wednesday, 5 February 14 10:31:11
468 |
469 | Buffer provides direct memory access
470 | ==========
471 | node_up_and_running
472 | - Your Highlight on Page 74-74 | Added on Wednesday, 5 February 14 10:46:42
473 |
474 | So when you are building really highly scalable apps, it’s often worth using Buffers to hold strings
475 | ==========
476 | node_up_and_running
477 | - Your Highlight on Page 79-79 | Added on Wednesday, 5 February 14 10:55:11
478 |
479 | Node uses the OpenSSL library as the basis of its cryptography. This
480 | ==========
481 | node_up_and_running
482 | - Your Highlight on Page 79-79 | Added on Wednesday, 5 February 14 10:55:26
483 |
484 | you have to compile Node with OpenSSL support in order to use the methods in this section
485 | ==========
486 | node_up_and_running
487 | - Your Highlight on Page 81-81 | Added on Wednesday, 5 February 14 11:02:15
488 |
489 | When we call hash.digest() again, we get an error. This is because once hash.digest() is called, the Hash object is finalized and cannot be reused. We need to create a new instance of Hash and use that instead. This time we get the hex output that is often more useful. The options for hash.digest() output are binary (default), hex, and base64
490 | ==========
491 | node_up_and_running
492 | - Your Highlight on Page 81-81 | Added on Wednesday, 5 February 14 11:03:18
493 |
494 | The HMAC API in Node is virtually identical to the Hash API. The only difference is that the creation of an hmac object requires a key as well as a hash algorithm
495 | ==========
496 | node_up_and_running
497 | - Your Highlight on Page 81-81 | Added on Wednesday, 5 February 14 11:03:45
498 |
499 | The key required to create an Hmac object is a PEM-encoded key, passed as a string
500 | ==========
501 | node_up_and_running
502 | - Your Highlight on Page 87-87 | Added on Wednesday, 5 February 14 11:06:31
503 |
504 | event loop will not run after the exit event, so only code without callbacks will be executed.
505 | ==========
506 | node_up_and_running
507 | - Your Highlight on Page 87-87 | Added on Wednesday, 5 February 14 11:07:03
508 |
509 | The uncaughtException event provides an extremely brute-force way of catching these exceptions. It’s really a last line of defense, but it’s extremely useful for that purpose.
510 | ==========
511 | node_up_and_running
512 | - Your Highlight on Page 91-91 | Added on Wednesday, 5 February 14 15:51:04
513 |
514 | Before attempting to read from stdin, call its resume() method
515 | ==========
516 | node_up_and_running
517 | - Your Highlight on Page 92-92 | Added on Wednesday, 5 February 14 16:46:30
518 |
519 | generally inadvisable to write a lot to stderr in a production system, because it may block real work
520 | ==========
521 | node_up_and_running
522 | - Your Highlight on Page 92-92 | Added on Wednesday, 5 February 14 16:46:49
523 |
524 | process.stderr is always a UTF-8 stream
525 | ==========
526 | node_up_and_running
527 | - Your Highlight on Page 92-92 | Added on Wednesday, 5 February 14 16:47:11
528 |
529 | argv is an array containing the command-line arguments, starting with the node command itself (
530 | ==========
531 | node_up_and_running
532 | - Your Highlight on Page 93-93 | Added on Wednesday, 5 February 14 16:48:33
533 |
534 | process.nextTick() creates a callback to be executed on the next “tick,” or iteration of the event
535 | ==========
536 | node_up_and_running
537 | - Your Highlight on Page 95-95 | Added on Wednesday, 5 February 14 16:52:11
538 |
539 | child processes have some common properties. They each contain properties for stdin, stdout
540 | ==========
541 | node_up_and_running
542 | - Your Highlight on Page 95-95 | Added on Wednesday, 5 February 14 16:52:37
543 |
544 | When you call exec(), you can pass a shell command for the new process to run. Note that the entire command is a string
545 | ==========
546 | node_up_and_running
547 | - Your Highlight on Page 97-97 | Added on Wednesday, 5 February 14 16:59:10
548 |
549 | This means that spawn() is most often used in server contexts to create subcomponents of a server and is the most common way people make Node work with multiple cores on a single machine.
550 | ==========
551 | node_up_and_running
552 | - Your Highlight on Page 99-99 | Added on Wednesday, 5 February 14 17:05:19
553 |
554 | we can ask child processes to share an existing file descriptor with the parent process
555 | ==========
556 | node_up_and_running
557 | - Your Highlight on Page 100-100 | Added on Wednesday, 5 February 14 17:18:02
558 |
559 | We could start a bunch of Node processes with different ports and load-balance them with Nginx or Apache Traffic Server. However, that’s inelegant and requires us to use more software
560 | ==========
561 | node_up_and_running
562 | - Your Highlight on Page 101-101 | Added on Wednesday, 5 February 14 17:18:55
563 |
564 | This is where passing custom FDs comes into its own. In the same way that we can pass the stdin, stdout, and stderr of a master process, we can create other sockets and pass those in to child processes. However, because we are passing file descriptors instead of messages, the kernel will deal with the routing. This means that although the master Node process is still required, it isn’t bearing the load for all the traffic.
565 | ==========
566 | node_up_and_running
567 | - Your Highlight on Page 102-102 | Added on Wednesday, 5 February 14 17:23:43
568 |
569 | So the deepEqual() and notDeep Equal() methods provide a way of deeply comparing object values. Without going into too many of the gory details
570 | ==========
571 | node_up_and_running
572 | - Your Highlight on Page 102-102 | Added on Wednesday, 5 February 14 17:24:33
573 |
574 | The important point here is that deepEqual() and notDeepEqual() are extremely helpful and thorough, but also potentially expensive
575 | ==========
576 | node_up_and_running
577 | - Your Highlight on Page 105-105 | Added on Thursday, 6 February 14 09:21:26
578 |
579 | You can also compile vm.Script objects (Example 5-43). These save a piece of code that you can then run repeatedly. At runtime, you can choose the context to be applied. This is helpful when you are repeatedly running the same code against multiple contexts.
580 | ==========
581 | node_up_and_running
582 | - Your Highlight on Page 106-106 | Added on Thursday, 6 February 14 09:23:28
583 |
584 | you need to pass in the objects to which you refer (such as the console object); otherwise, even basic global functions are not available.
585 | ==========
586 | node_up_and_running
587 | - Your Highlight on Page 115-115 | Added on Thursday, 6 February 14 09:28:04
588 |
589 | Redis is used when performance and scaling are important
590 | ==========
591 | node_up_and_running
592 | - Your Highlight on Page 115-115 | Added on Thursday, 6 February 14 09:28:27
593 |
594 | choose to use it as a cache for data retrieved from a relational database such as MySQL
595 | ==========
596 | node_up_and_running
597 | - Your Highlight on Page 115-115 | Added on Thursday, 6 February 14 09:28:50
598 |
599 | Node drivers to communicate with it
600 | ==========
601 | node_up_and_running
602 | - Your Highlight on Page 121-121 | Added on Thursday, 6 February 14 09:30:52
603 |
604 | Redis supports the publish-subscribe (or pub-sub) messaging pattern
605 | ==========
606 | node_up_and_running
607 | - Your Highlight on Page 122-122 | Added on Thursday, 6 February 14 09:33:15
608 |
609 | When the unsubscribe command detects no more active subscriptions, both clients end their connection to Redis, and the program execution stops
610 | ==========
611 | node_up_and_running
612 | - Your Highlight on Page 122-122 | Added on Thursday, 6 February 14 09:33:44
613 |
614 | Redis supports password authentication
615 | ==========
616 | node_up_and_running
617 | - Your Highlight on Page 122-122 | Added on Thursday, 6 February 14 09:34:20
618 |
619 | Notice the lack of usernames and multiple passwords. Redis does not include user management functionality
620 | ==========
621 | node_up_and_running
622 | - Your Highlight on Page 122-122 | Added on Thursday, 6 February 14 09:34:35
623 |
624 | Instead, system administrators are expected to secure their servers using other means, such as portblocking Redis from the outside world so that only internal, trusted users may access it
625 | ==========
626 | node_up_and_running
627 | - Your Highlight on Page 122-122 | Added on Thursday, 6 February 14 09:35:10
628 |
629 | Some “dangerous” commands can be renamed or removed entirely
630 | ==========
631 | node_up_and_running
632 | - Your Highlight on Page 123-123 | Added on Thursday, 6 February 14 09:35:22
633 |
634 | BSON object storage
635 | ==========
636 | node_up_and_running
637 | - Your Highlight on Page 123-123 | Added on Thursday, 6 February 14 09:35:29
638 |
639 | BSON object storage (a binary adaption of JSON
640 | ==========
641 | node_up_and_running
642 | - Your Highlight on Page 123-123 | Added on Thursday, 6 February 14 09:35:44
643 |
644 | ideal in high-write situations
645 | ==========
646 | node_up_and_running
647 | - Your Highlight on Page 123-123 | Added on Thursday, 6 February 14 10:08:03
648 |
649 | inserting data into Mongo is nonblocking, making it ideal for logging operations and telemetry data
650 | ==========
651 | node_up_and_running
652 | - Your Highlight on Page 123-123 | Added on Thursday, 6 February 14 10:08:17
653 |
654 | Mongo supports JavaScript functions inside queries, making it very powerful in read situations, including MapReduce queries. Using MongoDB’s document-
655 | ==========
656 | node_up_and_running
657 | - Your Highlight on Page 123-123 | Added on Thursday, 6 February 14 10:08:58
658 |
659 | supports JavaScript functions inside queries, making it very powerful in read situations, including MapReduce queries. Using MongoDB’s document
660 | ==========
661 | node_up_and_running
662 | - Your Highlight on Page 123-123 | Added on Thursday, 6 February 14 10:09:32
663 |
664 | The native MongoDB driver is a good choice when you need precise control over your MongoDB connection
665 | ==========
666 | node_up_and_running
667 | - Your Highlight on Page 127-127 | Added on Thursday, 6 February 14 10:13:30
668 |
669 | you work with Mongoose, you don’t need to maintain a connection to MongoDB, because all of your schema definitions and queries are buffered until you connect. This is a big deal, and an important way Mongoose serves Node’s methodology. By issuing all of the “live” commands at once against Mongo, you limit the amount of time and the number of callbacks to work with your data and greatly increase the number of operations your application is able to perform.
670 | ==========
671 | node_up_and_running
672 | - Your Highlight on Page 131-131 | Added on Thursday, 6 February 14 10:14:44
673 |
674 | Sequelize is an object relational mapper (ORM
675 | ==========
676 | node_up_and_running
677 | - Your Highlight on Page 137-137 | Added on Thursday, 6 February 14 10:17:22
678 |
679 | Connection pooling
680 | ==========
681 | node_up_and_running
682 | - Your Highlight on Page 137-137 | Added on Thursday, 6 February 14 10:17:28
683 |
684 | The solution is to maintain database connections inside a cache pool after they are no longer needed, so they can be used immediately by the next incoming request.
685 | ==========
686 | node_up_and_running
687 | - Your Highlight on Page 137-137 | Added on Thursday, 6 February 14 10:17:42
688 |
689 | Node developers should use the generic-pool module in front of their data layer to serve new database connections
690 | ==========
691 | node_up_and_running
692 | - Your Highlight on Page 139-139 | Added on Thursday, 6 February 14 10:18:40
693 |
694 | The beauty of Node’s pool is that any persistent resource can be represented. Databases are a natural fit, but you can just as easily write commands to maintain connections to an outside session cache, or even to hardware interfaces.
695 | ==========
696 | node_up_and_running
697 | - Your Highlight on Page 139-139 | Added on Thursday, 6 February 14 10:21:27
698 |
699 | This is known as a publish-subscribe pattern.
700 | ==========
701 | node_up_and_running
702 | - Your Highlight on Page 139-139 | Added on Thursday, 6 February 14 10:21:44
703 |
704 | This is known as a request-reply pattern.
705 | ==========
706 | node_up_and_running
707 | - Your Highlight on Page 140-140 | Added on Thursday, 6 February 14 10:22:06
708 |
709 | RabbitMQ is a message broker that supports the advanced message queueing protocol (AMQP). It is useful in situations where data needs to be communicated between different servers, or between different processes on the same server
710 | ==========
711 | node_up_and_running
712 | - Your Highlight on Page 140-140 | Added on Thursday, 6 February 14 10:22:30
713 |
714 | Once RabbitMQ has been installed and is running, use npm to retrieve Node’s AMQP drivers:
715 | ==========
716 | node_up_and_running
717 | - Your Highlight on Page 140-140 | Added on Thursday, 6 February 14 10:23:03
718 |
719 | For example, a publisher written in PHP can send a message to a consumer written in JavaScript.
720 | ==========
721 | node_up_and_running
722 | - Your Highlight on Page 142-142 | Added on Thursday, 6 February 14 10:24:43
723 |
724 | Using RabbitMQ, is it possible to split tasks among multiple workers and ensure that tasks are completed even if the first worker that handles them dies mid-process
725 | ==========
726 | node_up_and_running
727 | - Your Highlight on Page 143-143 | Added on Thursday, 6 February 14 10:25:56
728 |
729 | Although there is no “sleep” function in Node, you can fake it with a blocking loop, as done here.
730 | ==========
731 | node_up_and_running
732 | - Your Highlight on Page 144-144 | Added on Thursday, 6 February 14 10:27:09
733 |
734 | common “gotcha” occurs when developers forget to use the q.shift() command. If you forget it, your program will continue to function as normal, but as soon as your client disconnects, the server will place all of the messages the client processed back onto the queue. Another side effect is that the memory usage by RabbitMQ will gradually rise. This is because, although the messages are removed from active duty on the queue, they are kept in memory until they are acknowledged and deleted by the client. 144 | Chapter 6:
735 | ==========
736 | node_up_and_running
737 | - Your Highlight on Page 152-152 | Added on Thursday, 6 February 14 10:29:36
738 |
739 | Some of the more popular engines are Haml, Jade, Embedded Javascript (EJ), CoffeeKup (a CoffeeScript-based engine), and jQuery templates
740 | ==========
741 | node_up_and_running
742 | - Your Highlight on Page 159-159 | Added on Thursday, 6 February 14 10:35:59
743 |
744 | Socket.IO allows you to send messages back and forth with browser clients that connect with your Node server, using an efficient, low-level socket mechanism
745 | ==========
746 | node_up_and_running
747 | - Your Highlight on Page 161-161 | Added on Thursday, 6 February 14 10:37:21
748 |
749 | how namespaces avoid this problem by effectively dividing Socket.IO’s listeners into channels.
750 | ==========
751 | node_up_and_running
752 | - Your Highlight on Page 169-169 | Added on Thursday, 6 February 14 10:39:33
753 |
754 | The Node module system is based on the commonJS module specification.
755 | ==========
756 | node_up_and_running
757 | - Your Highlight on Page 170-170 | Added on Thursday, 6 February 14 10:41:31
758 |
759 | you can instruct npm to clean the cache using the following command
760 | ==========
761 | node_up_and_running
762 | - Your Highlight on Page 170-170 | Added on Thursday, 6 February 14 10:42:18
763 |
764 | Creating a package doesn’t require much more work than creating a package.json file with some basic definitions about your module—its name and version number being the most critical components
765 | ==========
766 | node_up_and_running
767 | - Your Highlight on Page 171-171 | Added on Thursday, 6 February 14 10:43:13
768 |
769 | This raises an interesting point about npm: because anyone can publish a package without any prefiltering or oversight, the quality of the libraries you install using npm is uncertain. So “buyer beware
770 | ==========
771 | node_up_and_running
772 | - Your Highlight on Page 172-172 | Added on Thursday, 6 February 14 10:44:01
773 |
774 | Using npm init is the fastest way to generate a barebones version of this file.
775 | ==========
776 | node_up_and_running
777 | - Your Highlight on Page 172-172 | Added on Thursday, 6 February 14 10:44:28
778 |
779 | If you have linked Express in more than one project, all of those projects will be synchronized to the most recent version, freeing you from having to update every one of them whenever Express is updated
780 | ==========
781 | node_up_and_running
782 | - Your Highlight on Page 172-172 | Added on Thursday, 6 February 14 10:44:48
783 |
784 | Whereas modules are the JavaScript extensions for Node, add-ons are the C/C++ extensions
785 | ==========
786 | node_up_and_running
787 | - Your Highlight on Page 172-172 | Added on Thursday, 6 February 14 10:45:03
788 |
789 | Add-ons are dynamically linked shared objects.
790 | ==========
791 | node_up_and_running
792 | - Your Highlight on Page 172-172 | Added on Thursday, 6 February 14 10:45:20
793 |
794 | Node uses the waf build system written in Python
795 | ==========
796 | node_up_and_running
797 | - Your Highlight on Page 172-172 | Added on Thursday, 6 February 14 10:45:47
798 |
799 | The first thing this code needs to do is include the v8 header file because Node is built on top of V8
800 | ==========
801 | node_up_and_running
802 | - Your Highlight on Page 172-172 | Added on Thursday, 6 February 14 10:46:08
803 |
804 | We’ll hang everything we expose from the add-on off a function with the signature extern 'C' void init (Handle