<!--{{{-->
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml' />
<!--}}}-->
Background: #fff
Foreground: #000
PrimaryPale: #8cf
PrimaryLight: #18f
PrimaryMid: #04b
PrimaryDark: #014
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
/*{{{*/
body {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}

a {color:[[ColorPalette::PrimaryMid]];}
a:hover {background-color:[[ColorPalette::PrimaryMid]]; color:[[ColorPalette::Background]];}
a img {border:0;}

h1,h2,h3,h4,h5,h6 {color:[[ColorPalette::SecondaryDark]]; background:transparent;}
h1 {border-bottom:2px solid [[ColorPalette::TertiaryLight]];}
h2,h3 {border-bottom:1px solid [[ColorPalette::TertiaryLight]];}

.button {color:[[ColorPalette::PrimaryDark]]; border:1px solid [[ColorPalette::Background]];}
.button:hover {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::SecondaryLight]]; border-color:[[ColorPalette::SecondaryMid]];}
.button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::SecondaryDark]];}

.header {background:[[ColorPalette::PrimaryMid]];}
.headerShadow {color:[[ColorPalette::Foreground]];}
.headerShadow a {font-weight:normal; color:[[ColorPalette::Foreground]];}
.headerForeground {color:[[ColorPalette::Background]];}
.headerForeground a {font-weight:normal; color:[[ColorPalette::PrimaryPale]];}

.tabSelected{color:[[ColorPalette::PrimaryDark]];
	background:[[ColorPalette::TertiaryPale]];
	border-left:1px solid [[ColorPalette::TertiaryLight]];
	border-top:1px solid [[ColorPalette::TertiaryLight]];
	border-right:1px solid [[ColorPalette::TertiaryLight]];
}
.tabUnselected {color:[[ColorPalette::Background]]; background:[[ColorPalette::TertiaryMid]];}
.tabContents {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::TertiaryPale]]; border:1px solid [[ColorPalette::TertiaryLight]];}
.tabContents .button {border:0;}

#sidebar {}
#sidebarOptions input {border:1px solid [[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel {background:[[ColorPalette::PrimaryPale]];}
#sidebarOptions .sliderPanel a {border:none;color:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:hover {color:[[ColorPalette::Background]]; background:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:active {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::Background]];}

.wizard {background:[[ColorPalette::PrimaryPale]]; border:1px solid [[ColorPalette::PrimaryMid]];}
.wizard h1 {color:[[ColorPalette::PrimaryDark]]; border:none;}
.wizard h2 {color:[[ColorPalette::Foreground]]; border:none;}
.wizardStep {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];
	border:1px solid [[ColorPalette::PrimaryMid]];}
.wizardStep.wizardStepDone {background:[[ColorPalette::TertiaryLight]];}
.wizardFooter {background:[[ColorPalette::PrimaryPale]];}
.wizardFooter .status {background:[[ColorPalette::PrimaryDark]]; color:[[ColorPalette::Background]];}
.wizard .button {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryLight]]; border: 1px solid;
	border-color:[[ColorPalette::SecondaryPale]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryPale]];}
.wizard .button:hover {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Background]];}
.wizard .button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::Foreground]]; border: 1px solid;
	border-color:[[ColorPalette::PrimaryDark]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryDark]];}

.wizard .notChanged {background:transparent;}
.wizard .changedLocally {background:#80ff80;}
.wizard .changedServer {background:#8080ff;}
.wizard .changedBoth {background:#ff8080;}
.wizard .notFound {background:#ffff80;}
.wizard .putToServer {background:#ff80ff;}
.wizard .gotFromServer {background:#80ffff;}

#messageArea {border:1px solid [[ColorPalette::SecondaryMid]]; background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]];}
#messageArea .button {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::SecondaryPale]]; border:none;}

.popupTiddler {background:[[ColorPalette::TertiaryPale]]; border:2px solid [[ColorPalette::TertiaryMid]];}

.popup {background:[[ColorPalette::TertiaryPale]]; color:[[ColorPalette::TertiaryDark]]; border-left:1px solid [[ColorPalette::TertiaryMid]]; border-top:1px solid [[ColorPalette::TertiaryMid]]; border-right:2px solid [[ColorPalette::TertiaryDark]]; border-bottom:2px solid [[ColorPalette::TertiaryDark]];}
.popup hr {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::PrimaryDark]]; border-bottom:1px;}
.popup li.disabled {color:[[ColorPalette::TertiaryMid]];}
.popup li a, .popup li a:visited {color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:active {background:[[ColorPalette::SecondaryPale]]; color:[[ColorPalette::Foreground]]; border: none;}
.popupHighlight {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
.listBreak div {border-bottom:1px solid [[ColorPalette::TertiaryDark]];}

.tiddler .defaultCommand {font-weight:bold;}

.shadow .title {color:[[ColorPalette::TertiaryDark]];}

.title {color:[[ColorPalette::SecondaryDark]];}
.subtitle {color:[[ColorPalette::TertiaryDark]];}

.toolbar {color:[[ColorPalette::PrimaryMid]];}
.toolbar a {color:[[ColorPalette::TertiaryLight]];}
.selected .toolbar a {color:[[ColorPalette::TertiaryMid]];}
.selected .toolbar a:hover {color:[[ColorPalette::Foreground]];}

.tagging, .tagged {border:1px solid [[ColorPalette::TertiaryPale]]; background-color:[[ColorPalette::TertiaryPale]];}
.selected .tagging, .selected .tagged {background-color:[[ColorPalette::TertiaryLight]]; border:1px solid [[ColorPalette::TertiaryMid]];}
.tagging .listTitle, .tagged .listTitle {color:[[ColorPalette::PrimaryDark]];}
.tagging .button, .tagged .button {border:none;}

.footer {color:[[ColorPalette::TertiaryLight]];}
.selected .footer {color:[[ColorPalette::TertiaryMid]];}

.sparkline {background:[[ColorPalette::PrimaryPale]]; border:0;}
.sparktick {background:[[ColorPalette::PrimaryDark]];}

.error, .errorButton {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Error]];}
.warning {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryPale]];}
.lowlight {background:[[ColorPalette::TertiaryLight]];}

.zoomer {background:none; color:[[ColorPalette::TertiaryMid]]; border:3px solid [[ColorPalette::TertiaryMid]];}

.imageLink, #displayArea .imageLink {background:transparent;}

.annotation {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border:2px solid [[ColorPalette::SecondaryMid]];}

.viewer .listTitle {list-style-type:none; margin-left:-2em;}
.viewer .button {border:1px solid [[ColorPalette::SecondaryMid]];}
.viewer blockquote {border-left:3px solid [[ColorPalette::TertiaryDark]];}

.viewer table, table.twtable {border:2px solid [[ColorPalette::TertiaryDark]];}
.viewer th, .viewer thead td, .twtable th, .twtable thead td {background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::Background]];}
.viewer td, .viewer tr, .twtable td, .twtable tr {border:1px solid [[ColorPalette::TertiaryDark]];}

.viewer pre {border:1px solid [[ColorPalette::SecondaryLight]]; background:[[ColorPalette::SecondaryPale]];}
.viewer code {color:[[ColorPalette::SecondaryDark]];}
.viewer hr {border:0; border-top:dashed 1px [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::TertiaryDark]];}

.highlight, .marked {background:[[ColorPalette::SecondaryLight]];}

.editor input {border:1px solid [[ColorPalette::PrimaryMid]];}
.editor textarea {border:1px solid [[ColorPalette::PrimaryMid]]; width:100%;}
.editorFooter {color:[[ColorPalette::TertiaryMid]];}
.readOnly {background:[[ColorPalette::TertiaryPale]];}

#backstageArea {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::TertiaryMid]];}
#backstageArea a {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstageArea a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; }
#backstageArea a.backstageSelTab {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
#backstageButton a {background:none; color:[[ColorPalette::Background]]; border:none;}
#backstageButton a:hover {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstagePanel {background:[[ColorPalette::Background]]; border-color: [[ColorPalette::Background]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]];}
.backstagePanelFooter .button {border:none; color:[[ColorPalette::Background]];}
.backstagePanelFooter .button:hover {color:[[ColorPalette::Foreground]];}
#backstageCloak {background:[[ColorPalette::Foreground]]; opacity:0.6; filter:'alpha(opacity=60)';}
/*}}}*/
/*{{{*/
* html .tiddler {height:1%;}

body {font-size:.75em; font-family:arial,helvetica; margin:0; padding:0;}

h1,h2,h3,h4,h5,h6 {font-weight:bold; text-decoration:none;}
h1,h2,h3 {padding-bottom:1px; margin-top:1.2em;margin-bottom:0.3em;}
h4,h5,h6 {margin-top:1em;}
h1 {font-size:1.35em;}
h2 {font-size:1.25em;}
h3 {font-size:1.1em;}
h4 {font-size:1em;}
h5 {font-size:.9em;}

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

ol {list-style-type:decimal;}
ol ol {list-style-type:lower-alpha;}
ol ol ol {list-style-type:lower-roman;}
ol ol ol ol {list-style-type:decimal;}
ol ol ol ol ol {list-style-type:lower-alpha;}
ol ol ol ol ol ol {list-style-type:lower-roman;}
ol ol ol ol ol ol ol {list-style-type:decimal;}

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

.indent {margin-left:3em;}
.outdent {margin-left:3em; text-indent:-3em;}
code.escaped {white-space:nowrap;}

.tiddlyLinkExisting {font-weight:bold;}
.tiddlyLinkNonExisting {font-style:italic;}

/* the 'a' is required for IE, otherwise it renders the whole tiddler in bold */
a.tiddlyLinkNonExisting.shadow {font-weight:bold;}

#mainMenu .tiddlyLinkExisting,
	#mainMenu .tiddlyLinkNonExisting,
	#sidebarTabs .tiddlyLinkNonExisting {font-weight:normal; font-style:normal;}
#sidebarTabs .tiddlyLinkExisting {font-weight:bold; font-style:normal;}

.header {position:relative;}
.header a:hover {background:transparent;}
.headerShadow {position:relative; padding:4.5em 0 1em 1em; left:-1px; top:-1px;}
.headerForeground {position:absolute; padding:4.5em 0 1em 1em; left:0px; top:0px;}

.siteTitle {font-size:3em;}
.siteSubtitle {font-size:1.2em;}

#mainMenu {position:absolute; left:0; width:10em; text-align:right; line-height:1.6em; padding:1.5em 0.5em 0.5em 0.5em; font-size:1.1em;}

#sidebar {position:absolute; right:3px; width:16em; font-size:.9em;}
#sidebarOptions {padding-top:0.3em;}
#sidebarOptions a {margin:0 0.2em; padding:0.2em 0.3em; display:block;}
#sidebarOptions input {margin:0.4em 0.5em;}
#sidebarOptions .sliderPanel {margin-left:1em; padding:0.5em; font-size:.85em;}
#sidebarOptions .sliderPanel a {font-weight:bold; display:inline; padding:0;}
#sidebarOptions .sliderPanel input {margin:0 0 0.3em 0;}
#sidebarTabs .tabContents {width:15em; overflow:hidden;}

.wizard {padding:0.1em 1em 0 2em;}
.wizard h1 {font-size:2em; font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em;}
.wizard h2 {font-size:1.2em; font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em;}
.wizardStep {padding:1em 1em 1em 1em;}
.wizard .button {margin:0.5em 0 0; font-size:1.2em;}
.wizardFooter {padding:0.8em 0.4em 0.8em 0;}
.wizardFooter .status {padding:0 0.4em; margin-left:1em;}
.wizard .button {padding:0.1em 0.2em;}

#messageArea {position:fixed; top:2em; right:0; margin:0.5em; padding:0.5em; z-index:2000; _position:absolute;}
.messageToolbar {display:block; text-align:right; padding:0.2em;}
#messageArea a {text-decoration:underline;}

.tiddlerPopupButton {padding:0.2em;}
.popupTiddler {position: absolute; z-index:300; padding:1em; margin:0;}

.popup {position:absolute; z-index:300; font-size:.9em; padding:0; list-style:none; margin:0;}
.popup .popupMessage {padding:0.4em;}
.popup hr {display:block; height:1px; width:auto; padding:0; margin:0.2em 0;}
.popup li.disabled {padding:0.4em;}
.popup li a {display:block; padding:0.4em; font-weight:normal; cursor:pointer;}
.listBreak {font-size:1px; line-height:1px;}
.listBreak div {margin:2px 0;}

.tabset {padding:1em 0 0 0.5em;}
.tab {margin:0 0 0 0.25em; padding:2px;}
.tabContents {padding:0.5em;}
.tabContents ul, .tabContents ol {margin:0; padding:0;}
.txtMainTab .tabContents li {list-style:none;}
.tabContents li.listLink { margin-left:.75em;}

#contentWrapper {display:block;}
#splashScreen {display:none;}

#displayArea {margin:1em 17em 0 14em;}

.toolbar {text-align:right; font-size:.9em;}

.tiddler {padding:1em 1em 0;}

.missing .viewer,.missing .title {font-style:italic;}

.title {font-size:1.6em; font-weight:bold;}

.missing .subtitle {display:none;}
.subtitle {font-size:1.1em;}

.tiddler .button {padding:0.2em 0.4em;}

.tagging {margin:0.5em 0.5em 0.5em 0; float:left; display:none;}
.isTag .tagging {display:block;}
.tagged {margin:0.5em; float:right;}
.tagging, .tagged {font-size:0.9em; padding:0.25em;}
.tagging ul, .tagged ul {list-style:none; margin:0.25em; padding:0;}
.tagClear {clear:both;}

.footer {font-size:.9em;}
.footer li {display:inline;}

.annotation {padding:0.5em; margin:0.5em;}

* html .viewer pre {width:99%; padding:0 0 1em 0;}
.viewer {line-height:1.4em; padding-top:0.5em;}
.viewer .button {margin:0 0.25em; padding:0 0.25em;}
.viewer blockquote {line-height:1.5em; padding-left:0.8em;margin-left:2.5em;}
.viewer ul, .viewer ol {margin-left:0.5em; padding-left:1.5em;}

.viewer table, table.twtable {border-collapse:collapse; margin:0.8em 1.0em;}
.viewer th, .viewer td, .viewer tr,.viewer caption,.twtable th, .twtable td, .twtable tr,.twtable caption {padding:3px;}
table.listView {font-size:0.85em; margin:0.8em 1.0em;}
table.listView th, table.listView td, table.listView tr {padding:0px 3px 0px 3px;}

.viewer pre {padding:0.5em; margin-left:0.5em; font-size:1.2em; line-height:1.4em; overflow:auto;}
.viewer code {font-size:1.2em; line-height:1.4em;}

.editor {font-size:1.1em;}
.editor input, .editor textarea {display:block; width:100%; font:inherit;}
.editorFooter {padding:0.25em 0; font-size:.9em;}
.editorFooter .button {padding-top:0px; padding-bottom:0px;}

.fieldsetFix {border:0; padding:0; margin:1px 0px;}

.sparkline {line-height:1em;}
.sparktick {outline:0;}

.zoomer {font-size:1.1em; position:absolute; overflow:hidden;}
.zoomer div {padding:1em;}

* html #backstage {width:99%;}
* html #backstageArea {width:99%;}
#backstageArea {display:none; position:relative; overflow: hidden; z-index:150; padding:0.3em 0.5em;}
#backstageToolbar {position:relative;}
#backstageArea a {font-weight:bold; margin-left:0.5em; padding:0.3em 0.5em;}
#backstageButton {display:none; position:absolute; z-index:175; top:0; right:0;}
#backstageButton a {padding:0.1em 0.4em; margin:0.1em;}
#backstage {position:relative; width:100%; z-index:50;}
#backstagePanel {display:none; z-index:100; position:absolute; width:90%; margin-left:3em; padding:1em;}
.backstagePanelFooter {padding-top:0.2em; float:right;}
.backstagePanelFooter a {padding:0.2em 0.4em;}
#backstageCloak {display:none; z-index:20; position:absolute; width:100%; height:100px;}

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which need larger font sizes.
***/
/*{{{*/
body {font-size:0.8em;}
#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}
.subtitle {font-size:0.8em;}
.viewer table.listView {font-size:0.95em;}
/*}}}*/
/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea {display: none !important;}
#displayArea {margin: 1em 1em 0em;}
noscript {display:none;} /* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
}
/*}}}*/
<!--{{{-->
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser excludeLists'></span></div>
<!--}}}-->
To get started with this blank [[TiddlyWiki]], you'll need to modify the following tiddlers:
* [[SiteTitle]] & [[SiteSubtitle]]: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* [[MainMenu]]: The menu (usually on the left)
* [[DefaultTiddlers]]: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>
These [[InterfaceOptions]] for customising [[TiddlyWiki]] are saved in your browser

Your username for signing your edits. Write it as a [[WikiWord]] (eg [[JoeBloggs]])

<<option txtUserName>>
<<option chkSaveBackups>> [[SaveBackups]]
<<option chkAutoSave>> [[AutoSave]]
<<option chkRegExpSearch>> [[RegExpSearch]]
<<option chkCaseSensitiveSearch>> [[CaseSensitiveSearch]]
<<option chkAnimate>> [[EnableAnimations]]

----
Also see [[AdvancedOptions]]
<<importTiddlers>>
[[Presentations 2013]]
Syllabus
#Start Eview and Import the Data
#Select the data
#Click on proc, then select Hodrik-Prescott filter, choose the value for lambda
#Example: [[HP Filter of S&P Annual Data|http://ihome.ust.hk/~dxie/Econ5250/s and p.png]]
How did Paul Krugman get it so Wrong?

John H. Cochrane[1]

Many friends and colleagues have asked me what I think of Paul Krugman’s New York Times Magazine article, “How did Economists get it so wrong?”

Most of all, it’s sad. Imagine this weren’t economics for a moment. Imagine this were a respected scientist turned popular writer, who says, most basically, that everything everyone has done in his field since the mid 1960s is a complete waste of time. Everything that fills its academic journals, is taught in its ~PhD programs, presented at its conferences, summarized in its graduate textbooks, and rewarded with the accolades a profession can bestow, including multiple Nobel prizes, is totally wrong. Instead, he calls for a return to the eternal verities of a rather convoluted book written in the 1930s, as taught to our author in his undergraduate introductory courses. If a scientist, he might be a global-warming skeptic, an ~AIDS-HIV disbeliever, a stalwart that maybe continents don’t move after all, or that smoking isn’t that bad for you really.

It gets worse. Krugman hints at dark conspiracies, claiming “dissenters are marginalized.” Most of the article is just a calumnious personal attack on an ever-growing enemies list, which now includes “new Keyenesians” such as Olivier Blanchard and Greg Mankiw. Rather than source professional writing, he plays gotcha with out-of-context second-hand quotes from media interviews. He makes stuff up, boldly putting words in people’s mouths that run contrary to their written opinions. Even this isn’t enough: he adds cartoons to try to make his “enemies” look silly, and puts them in false and embarrassing situations. He accuses us literally of adopting ideas for pay, selling out for “sabbaticals at the Hoover institution” and fat “Wall street paychecks.” It sounds a bit paranoid.

It’s annoying to the victims, but we’re big boys and girls. It’s a disservice to New York Times readers. They depend on Krugman to read real academic literature and digest it, and they get this schlock instead. And it’s ineffective. Any astute reader knows that personal attacks and innuendo mean the author has run out of ideas.

And that’s the biggest and saddest news of this piece: Paul Krugman has no interesting ideas whatsoever about what caused our current financial and economic problems, what policies might have prevented it, or what might help us in the future, and he has no contact with people who do. “Irrationality” and “spend like a drunken sailor” are pretty superficial compared to all the fascinating things economists are writing about it these days.

What do I think? How sad.

That’s what I think, but I don’t expect you the reader to be convinced by my opinion or my reference to professional consensus. Maybe he is right. Occasionally sciences, especially social sciences, do take a wrong turn for a decade or two. I thought Keynesian economics was such a wrong turn. So let’s take a quick look at the ideas.

Krugman’s attack has two goals. First, he thinks financial markets are “inefficient,” fundamentally due to “irrational” investors, and thus prey to excessive volatility which needs government control. Second, he likes the huge “fiscal stimulus” provided by multi-trillion dollar deficits.

Efficiency.

It’s fun to say we didn’t see the crisis coming, but the central empirical prediction of the efficient markets hypothesis is precisely that nobody can tell where markets are going – neither benevolent government bureaucrats, nor crafty hedge-fund managers, nor ivory-tower academics. This is probably the best-tested proposition in all the social sciences. Krugman knows this, so all he can do is huff and puff about his dislike for a theory whose central prediction is that nobody can be a reliable soothsayer.

Krugman writes as if the volatility of stock prices alone disproves market efficiency, and efficient marketers just ignored it all these years. This is a canard that Paul knows better than to pass on, no matter how rhetorically convenient. (I can overlook his mixing up the CAPM and ~Black-Scholes model, but not this.) There is nothing about “efficiency” that promises “stability.” “Stable” growth would in fact be a major violation of efficiency. Efficient markets did not need to wait for “the memory of 1929 … gradually receding,” nor did we fail to read the newspapers in 1987. Data from the great depression has been included in practically all the tests. In fact, the great “equity premium puzzle” is that if efficient, stock markets don’t seem risky enough to deter more people from investing! Gene Fama’s ~PhD thesis was on “fat tails” in stock returns.

It is true and very well documented that asset prices move more than reasonable expectations of future cashflows. This might be because people are prey to bursts of irrational optimism and pessimism. It might also be because people’s willingness to take on risk varies over time, and is sharply lower in bad economic times. As Gene Fama pointed out in 1972, these are observationally equivalent explanations at the superficial level of staring at prices and writing magazine articles and opeds. Unless you are willing to elaborate your theory to the point that it can quantitatively describe how much and when risk premiums, or waves of “optimism” and “pessimism,” can vary, you know nothing. No theory is particularly good at that right now. Crying “bubble” is no good unless you have an operational procedure for identifying bubbles, distinguishing them from rationally low risk premiums, and not crying wolf too many years in a row.

But this difficulty is really no surprise. It’s also the central prediction of free-market economics, as crystallized by Hayek, that no academic, bureaucrat or regulator will ever be able to fully explain market price movements. Nobody knows what “fundamental” or “hold to maturity value” is. If anyone could tell what the price of tomatoes should be, let alone the price of Microsoft stock, communism would have worked.

More deeply, the economist’s job is not to “explain” market fluctuations after the fact, to give a pleasant story on the evening news about why markets went up or down. Markets up? “A wave of positive sentiment.” Markets went down? “Irrational pessimism.” (And “the risk premium must have increased” is just as empty.) Our ancestors could do that. Really, is that an improvement on “Zeus had a fight with Apollo?” Good serious behavioral economists know this, and they are circumspect in their explanatory claims so far.

But this argument takes us away from the main point. The case for free markets never was that markets are perfect. The case for free markets is that government control of markets, especially asset markets, has always been much worse. Free markets are the worst system ever devised – except for all of the others.

Krugman at bottom is arguing that the government should massively intervene in financial markets, and take charge of the allocation of capital. He can’t quite come out and say this, but he does say “Keynes considered it a very bad idea to let such markets…dictate important business decisions,” and “finance economists believed that we should put the capital development of the nation in the hands of what Keynes had called a `casino.’” Well, if markets can’t be trusted to allocate capital, we don’t have to connect too many dots to imagine who Paul has in mind.

To reach this conclusion, you need theory, evidence, experience, or any realistic hope that the alternative will be better. Remember, the SEC couldn’t even find Bernie Madoff when he was handed to them on a silver platter. Think of the great job Fannie, Freddie, and Congress did in the mortgage market. Is this system going to regulate Citigroup, guide financial markets to the right price, replace the stock market, and tell our society which new products are worth investment? As David Wessel’s excellent In Fed We Trust makes perfectly clear, government regulators failed just as abysmally as private investors and economists to see the storm coming. And not from any lack of smarts.

In fact, the behavioral view gives us a new and stronger argument against regulation and control. Regulators are just as human and irrational as market participants. If bankers are, in Krugman’s words, “idiots,” then so must be the typical treasury secretary, fed chairman, and regulatory staff. They act alone or in committees, where behavioral biases are much better documented than in market settings. They are still easily captured by industries, and face horrendously distorted incentives.

Careful behavioralists know this, and do not quickly run from “the market got it wrong” to “the government can put it all right.” Even my most behavioral colleagues Richard Thaler and Cass Sunstein in their book “Nudge” go only so far as a light libertarian paternalism, suggesting good default options on our 401(k) accounts. (And even here they’re not very clear on how the Federal Nudging Agency is going to steer clear of industry capture.) They don’t even think of jumping from irrational markets, which they believe in deeply, to Federal control of stock and house prices and allocation of capital.

Stimulus

Most of all, Krugman likes fiscal stimulus. In this quest, he accuses us and the rest of the economics profession of “mistaking beauty for truth.” He’s not that clear on what the “beauty” is that we all fell in love with, and why one should shun it. And for good reason. The first siren of beauty is simple logical consistency. Paul’s Keynesian economics requires that people make plans to consume more, invest more, and pay more taxes with the same income. The second siren is even vaguely plausible assumptions about how people behave. Keynesian economics requires that the government is able to systematically fool people again and again. It presumes that people don’t think about the future in making decisions today. Logical consistency and vaguely plausible foundations are indeed “beautiful” but to me they are also basic preconditions for “truth.”

In economics, stimulus spending ran aground on Robert Barro’s Ricardian equivalence theorem. This theorem says that debt-financed spending can’t have any effect because people, seeing the higher future taxes that must pay off the debt, will simply save more. They will buy the new government debt and leave all spending decisions unaltered. Is this theorem true? It’s a logical connection from a set of “if” to a set of “therefore.” Not even Paul can object to the connection.

Therefore, we have to examine the “ifs.” And those ifs are, as usual, obviously not true. For example, the theorem presumes lump-sum taxes, not proportional income taxes. Alas, when you take this into account we are all made poorer by deficit spending, so the multiplier is most likely negative. The theorem (like most Keynesian economics) ignores the composition of output; but surely spending money on roads rather than cars can affect the overall level.

Economists have spent a generation tossing and turning the Ricardian equivalence theorem, and assessing the likely effects of fiscal stimulus in its light, generalizing the “ifs” and figuring out the likely “therefores.” This is exactly the right way to do things. The impact of Ricardian equivalence is not that this simple abstract benchmark is literally true. The impact is that in its wake, if you want to understand the effects of government spending, you have to specify why it is false. Doing so does not lead you anywhere near old-fashioned Keynesian economics. It leads you to consider distorting taxes, estate taxes, how much people care about their children, how many people would like to borrow more to finance today’s consumption and so on. And when you find “market failures” that might justify a multiplier, that analysis quickly suggests direct fixes for the market failures, not their exploitation along the lines Keynes suggested. Most “New Keynesian” analysis that add frictions don’t produce big multipliers.

This is how real thinking about stimulus actually proceeds. Nobody ever “asserted that an increase in government spending cannot, under any circumstances, increase employment.” This is unsupportable by any serious review of professional writings, and Krugman knows it. (My own are perfectly clear on lots of possibilities for an answer that is not zero.) But thinking through this sort of thing and explaining it is so much harder than just tarring your enemies with out-of-context quotes, ethical innuendo, or silly cartoons.

In fact, I propose that Krugman himself doesn’t really believe the Keynesian logic for that stimulus. I doubt he would follow that logic to its inevitable conclusions. Stimulus must have some other attraction to him.

If you believe the Keynesian argument for stimulus, you should think Bernie Madoff is a hero. Seriously. He took money from people who were saving it, and gave it to people who most assuredly were going to spend it. Each dollar so transferred, in Krugman’s world, generates an additional dollar and a half of national income. The analogy is even closer. Madoff didn’t just take money from his savers, he really borrowed it from them, giving them phony accounts with promises of great profits to come. This looks a lot like government debt.

If you believe the Keynesian argument for stimulus, you don’t care how the money is spent. All this puffery about “infrastructure,” monitoring, wise investment, jobs “created” and so on is pointless. Keynes thought the government should pay people to dig ditches and fill them up.

If believe in Keynesian stimulus, you don’t even care if the government spending money is stolen. Actually, that would be better. Thieves have notoriously high propensities to consume.

The crash.

Krugman’s article is supposedly about how the crash and recession changed our thinking, and what economics has to say about it. The most amazing piece of news in the whole article is that Paul Krugman has absolutely no idea about what caused the crash, what policies might have prevented it, and what policies we should adopt going forward. Furthermore, he seems completely unaware of the large body of work by economists who actually do know something about the banking and financial system, and have been thinking about it productively for a generation.

Here’s all he has to say: “Irrationality” caused markets to go up and then down. “Spending” then declined, for unclear reasons, possibly “irrational” as well. The sum total of his policy recommendations is for the Federal Government to spend like a drunken sailor after the fact.

Paul, there was a financial crisis, a classic near-run on banks. The centerpiece of our crash was not the relatively free stock or real estate markets, it was the highly regulated commercial banks. A generation of economists has thought really hard about these kinds of events. Look up Diamond, Rajan, Gorton, Kashyap, Stein, and so on. They’ve thought about why there is so much short term debt, why banks run, how deposit insurance and credit guarantees help, but how they give incentives for excessive risk taking.

If we want to think about events and policies, this seems like more than a minor detail. The hard and central policy debate over the last year was how to manage this financial crisis. Now it is how to set up the incentives of banks and other financial institutions so this mess doesn’t happen again. There’s lots of good and subtle economics here that New York Times readers might like to know about. What does Krugman have to say? Zero.

Krugman doesn’t even have anything to say about the Fed. Ben Bernanke did a lot more last year than set the funds rate to zero and then go off on vacation and wait for fiscal policy to do its magic. Leaving aside the string of bailouts, the Fed started term lending to securities dealers. Then, rather than buy treasuries in exchange for reserves, it essentially sold treasuries in exchange for private debt. Though the funds rate was near zero, the Fed noticed huge commercial paper and securitized debt spreads, and intervened in those markets. There is no “the” interest rate anymore, the Fed is managing them all. Recently the Fed has started buying massive quantities of mortgage-backed securities and long-term treasury debt.

Monetary policy now has little to do with “money” vs. “bonds” with all the latter lumped together. Monetary policy has become financial policy. Does any of this work? What are the dangers? Can the Fed stay independent in this new role? These are the questions of our time. What does Krugman have to say? Nothing.

Or perhaps Krugman’s point is that a cabal of obvious crackpots bedazzled all of macroeconomics with the beauty of their mathematics, to the point of inducing policy paralysis. Alas, that won’t stick. The sad fact is that few in Washington pay the slightest attention to neo-classical or intertemporal ideas. Paul’s simple Keynesianism has dominated policy analysis for decades and continues to do so. From the CEA to the Fed to the OMB and CBO, everyone just adds up consumer, investment and government “demand” to forecast output and uses simple Phillips curves to think about inflation. If a failure of ideas caused bad policy, it’s Keynes’ ideas that failed.

The future of economics.

How should economics change? Krugman argues for three incompatible changes.

First, Krugman argues for a future of economics that “recognizes flaws and frictions,” and incorporates alternative assumptions about behavior, especially towards risk-taking. To which I say, “Hello, Paul, where have you been for the last 30 years?” Macroeconomists have not spent 30 years admiring the eternal verities of Kydland and Prescott’s 1982 paper. Pretty much all we have been doing for 30 years is introducing flaws, frictions and new behaviors, especially new models of attitudes to risk, and comparing the resulting models, quantitatively, to data. The long literature on financial crises and banking which Krugman does not mention has been doing exactly this bidding for the same time.

Second, Krugman argues that “a more or less Keynesian view is the only plausible game in town,” and “Keynesian economics remains the best framework we have for making sense of recessions and depressions.” One thing is pretty clear by now, that when economics incorporates flaws and frictions, the result will not be to rehabilitate an 80-year-old book. As Paul bemoans, the “new Keynesians” who did just what he asks, putting Keynes inspired price-stickiness into logically coherent models, ended up with something that looked a lot more like monetarism. (Actually, though this is the consensus, my own work finds that new-Keynesian economics ended up with something much different and more radical than monetarism.) A science that moves forward almost never ends up back where it started. Einstein revises Newton, but does not send you back to Aristotle. At best you can play the fun game of hunting for inspirational quotes, but that doesn’t mean much.

Third, and most surprising, is Krugman’s Luddite attack on mathematics; “economists as a group, mistook beauty, clad in impressive-looking mathematics, for truth.” Models are “gussied up with fancy equations.” I’m old enough to remember when Krugman was young, working out the interactions of game theory and increasing returns in international trade, and the old guard tut-tutted “nice recreational mathematics, but not real-world at all.” How quickly time passes.

Again, what is the alternative? Does Krugman really think we can make progress on his – and my – agenda for economic and financial research — understanding frictions, imperfect markets, complex human behavior, institutional rigidities – by reverting to a literary style of exposition, and abandoning the attempt to compare theories quantitatively against data? Against the worldwide tide of quantification in all fields of human endeavor (read “Moneyball”) is there any real hope that this will work in economics?

No, the problem is that we don’t have enough math. Math in economics serves to keep the logic straight, to make sure that the “then” really does follow the “if,” which it so frequently does not if you just write prose. The challenge is how hard it is to write down explicit artificial economies with these ingredients, actually solve them, in order to see what makes them tick. Frictions are just bloody hard with the mathematical tools we have now.

The insults.

The level of personal attack in this article, and fudging of the facts to achieve it, is simply amazing.

As one little example (ok, I’m a bit sensitive), take my quotation about carpenters in Nevada. I didn’t write this. It’s a quote, taken out of context, from a bloomberg.com article written by a rather dense reporter who I spent about 10 hours with patiently trying to explain some basics. (It’s the last time I’ll do that!) I was trying to explain how sectoral shifts contribute to unemployment. Krugman follows it by a lie — I never asserted that “it take mass unemployment across the whole nation to get carpenters to move out of Nevada.” You can’t even dredge up a quote for that monstrosity.

What’s the point? I don’t think Paul disagrees that sectoral shifts result in some unemployment, so the quote actually makes sense as economics. The only point is to make me, personally, seem heartless — a pure, personal, calumnious attack, having nothing to do with economics.

Bob Lucas has written extensively on Keynesian and monetarist economics, sensibly and even-handedly. Krugman chooses to quote a joke, made back in 1980 at a lunch talk to some business school alumni. Really, this is on the level of the picture of Barack Obama with Bill Ayres that Sean Hannity likes to show on Fox News.

It goes on. Krugman asserts that I and others “believe” “that an increase in government spending cannot, under any circumstances, increase employment,” or that we “argued that price fluctuations and shocks to demand actually had nothing to do with the business cycle.” These are just gross distortions, unsupported by any documentation, let alone professional writing. And Krugman knows better. All economic models are simplified to exhibit one point; we all understand the real world is more complicated; and his job is supposed to be to explain that to lay readers. It would be no different than if we were to look up Paul’s early work which assumed away transport costs and claim “Paul Krugman believes ocean shipping is free, how stupid” in the Wall Street Journal.

Of course the idea that any of us do what we do because we’re paid off by fancy Wall Street salaries or cushy sabbaticals at Hoover is just ridiculous. (If Krugman knew anything about hedge funds he’d know that believing in efficient markets disqualifies you for employment. Nobody wants a guy who thinks you can’t make any money trading!) And given Krugman’s speaking fees and how much the looney right likes him, it’s a surprising first stone for him to cast.

Apparently, salacious prose, ethical innuendo, calumny, and selective quotation from media aren’t enough: Krugman added cartoons to try to make opponents look silly. The Lucas-Blanchard-Bernanke conspiratorial cocktail party celebrating the end of recessions is a fiction. So is their despondent gloom on reading “recession” in the paper. Nobody at a conference looks like Dr. Pangloss with wild hair and a suit from the 1800s. (OK, Randy Wright has the hair, but not the suit.) Keynes did not reappear at the NBER to be booed as an “outsider.” Why are you allowed to make things up in pictures that wouldn’t pass even the Times’ weak fact-checking in words?

Well, perhaps we got off easy. This all was mild compared to Krugman’s vicious obituary of Milton Friedman in the New York Review of Books. But most of all, Paul isn’t doing his job. He’s supposed to read, explain, and criticize things economists write, and preferably real professional writing, not interviews, opeds and blog posts. At a minimum, this leads to the unavoidable conclusion that Krugman simply isn’t reading real economics anymore. Well, the equations are hard. But most of all, who cares about Paul’s character assassination attempts of us boring and politically unimportant academics?

How did Krugman get it so wrong?

So what is Krugman up to? Why become a denier, a skeptic, an apologist for 70 year old ideas, replete with well-known logical fallacies, a pariah? Why publish an essentially personal attack on an ever-growing enemies list that now includes practically every professional economist? Why publish an incoherent vision for the future of economics?

The only explanation that makes sense to me is that Krugman isn’t trying to be an economist, he is trying to be a partisan, political opinion writer. This is not an insult. I read George Will, Charles Krauthnammer and Frank Rich with equal pleasure even when I disagree with them. Krugman wants to be Rush Limbaugh of the Left. I still want to be Milton Friedman, but each is a worthy calling.

Alas, to Krugman, as to far too many ex-economists in partisan debates, economics is not a quest for understanding. It is a set of debating points to argue for policies that one has adopted for partisan political purposes. “Stimulus” is just marketing with which to sell voters on a package of government spending priorities that you want for political reasons. It’s not a proposition to be explained, understood, taken seriously to its logical limits, or reflective of market failures that should be addressed directly. To my mind, Krugman left the world of economics when, in the California electricity crisis, he argued that supply curves slope down; that a price cap, desired by his political constituency, would increase electricity supplies. That position served the political goal no matter how tortured the economics. This is more of the same.

Why argue for a nonsensical future for economics? Well, again, if you don’t regard economics as a science, a discipline that ought to result in quantitative matches to data, a discipline that requires crystal-clear logical connections between the “if” and the “then,” if the point of economics is merely to provide marketing and propaganda for politically-motivated policy, then it all does make sense. It makes sense to appeal to some future economics – not yet worked out, even verbally –disdain quantification and comparison to data, and to appeal to the authority of ancient books as interpreted you, their lone remaining apostle.

Most of all, this is the only reason I can come up with to understand why Krugman wants to write personal attacks on those who disagree with him. I like it when people disagree with me, and take time to read my work and criticize it. At worst I learn how to position it better. At best, I discover I was wrong and learn something. I send a polite thank you note.

Krugman wants people to swallow his arguments whole from his authority, without demanding logic, or evidence. Those who disagree with him, alas, are pretty smart and have pretty good arguments if you bother to read them. So, he tries to discredit them with personal attacks.

This is the political sphere, not the intellectual one. Don’t argue with them, swift-boat them. Find some embarrassing quote from an old interview. Well, good luck, Paul. Let’s just not pretend this has anything to do with economics, or actual truth about how the world works or could be made a better place.

[1] University of Chicago Booth School of Business. Many colleagues and friends helped, but I don’t want to name them for obvious reasons. Please don’t bother emailing me to tell me what a jerk I am. 
/***
|''Name:''|LoadRemoteFileThroughProxy (previous LoadRemoteFileHijack)|
|''Description:''|When the TiddlyWiki file is located on the web (view over http) the content of [[SiteProxy]] tiddler is added in front of the file url. If [[SiteProxy]] does not exist "/proxy/" is added. |
|''Version:''|1.1.0|
|''Date:''|mar 17, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#LoadRemoteFileHijack|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0|
***/
//{{{
version.extensions.LoadRemoteFileThroughProxy = {
 major: 1, minor: 1, revision: 0, 
 date: new Date("mar 17, 2007"), 
 source: "http://tiddlywiki.bidix.info/#LoadRemoteFileThroughProxy"};

if (!window.bidix) window.bidix = {}; // bidix namespace
if (!bidix.core) bidix.core = {};

bidix.core.loadRemoteFile = loadRemoteFile;
loadRemoteFile = function(url,callback,params)
{
 if ((document.location.toString().substr(0,4) == "http") && (url.substr(0,4) == "http")){ 
 url = store.getTiddlerText("SiteProxy", "/proxy/") + url;
 }
 return bidix.core.loadRemoteFile(url,callback,params);
}
//}}}
[[Syllabus]]
[[Danyang Xie|http://danyang.xie.tiddlyspot.com/]]
"Is Growth Exogenous? Taking Mankiw, Romer, and Weil Seriously"
#Conclusion: long-run growth is significantly correlated with behavioral variables such as the saving rate, and that this correlation is not easily explained by models in which growth is treated as the exogenous variables. Future empirical studies should focus on models that exhibit endogenous growth.
#Explicitly model the productivity change Zdot as a function of other variables, see equation (2.3), which can be written as (2.11), noting that Z grows at a constant rate on the balanced growth path rules out scale effects in the determination of Z. Xie: it seems problematic to have Z0, K0, H0, L0 in  (2.11).
#Two testable equations: (2.17) and (2.18)
#Replication of MRW: For the augmented Solow Model, the implied alpha is low in some cases. Table III.
#Equation (3.2): If the growth rate g is constant across countries, then we could test by adding saving rates, the schooling rates, and population growth rates into the estimation equation and see if their coefficient is zero.Table Vrejected this hypothesis.
#Two reasons for the rejection: 1. Growth may not be exogenous; 2. countries may be on a transition, rather than on a BGP. In fact, Results of Western Hemisphere sample in Table V suggests that reason 2 is a possibility.
#Other notable results: Table VI indicates that Ramsey model does not fit well with the data, neither does~Uzawa-Lucas. AK model does better (Table VIII)
/***
|''Name:''|PasswordOptionPlugin|
|''Description:''|Extends TiddlyWiki options with non encrypted password option.|
|''Version:''|1.0.2|
|''Date:''|Apr 19, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#PasswordOptionPlugin|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0 (Beta 5)|
***/
//{{{
version.extensions.PasswordOptionPlugin = {
	major: 1, minor: 0, revision: 2, 
	date: new Date("Apr 19, 2007"),
	source: 'http://tiddlywiki.bidix.info/#PasswordOptionPlugin',
	author: 'BidiX (BidiX (at) bidix (dot) info',
	license: '[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D]]',
	coreVersion: '2.2.0 (Beta 5)'
};

config.macros.option.passwordCheckboxLabel = "Save this password on this computer";
config.macros.option.passwordInputType = "password"; // password | text
setStylesheet(".pasOptionInput {width: 11em;}\n","passwordInputTypeStyle");

merge(config.macros.option.types, {
	'pas': {
		elementType: "input",
		valueField: "value",
		eventName: "onkeyup",
		className: "pasOptionInput",
		typeValue: config.macros.option.passwordInputType,
		create: function(place,type,opt,className,desc) {
			// password field
			config.macros.option.genericCreate(place,'pas',opt,className,desc);
			// checkbox linked with this password "save this password on this computer"
			config.macros.option.genericCreate(place,'chk','chk'+opt,className,desc);			
			// text savePasswordCheckboxLabel
			place.appendChild(document.createTextNode(config.macros.option.passwordCheckboxLabel));
		},
		onChange: config.macros.option.genericOnChange
	}
});

merge(config.optionHandlers['chk'], {
	get: function(name) {
		// is there an option linked with this chk ?
		var opt = name.substr(3);
		if (config.options[opt]) 
			saveOptionCookie(opt);
		return config.options[name] ? "true" : "false";
	}
});

merge(config.optionHandlers, {
	'pas': {
 		get: function(name) {
			if (config.options["chk"+name]) {
				return encodeCookie(config.options[name].toString());
			} else {
				return "";
			}
		},
		set: function(name,value) {config.options[name] = decodeCookie(value);}
	}
});

// need to reload options to load passwordOptions
loadOptionsCookie();

/*
if (!config.options['pasPassword'])
	config.options['pasPassword'] = '';

merge(config.optionsDesc,{
		pasPassword: "Test password"
	});
*/
//}}}
Orders to be determined by random draw later. Students are required to send a pdf version of the paper of their choice to all classmates + TA + me 

*November 17, 8:30 am
**Henry He: Ricardo Reis, "Inattentive Consumers", JME 2006.
**Song Tianle: Robert Hall, "By how much does GDP rise if the Government buys more output?" 2009.
**Song Difan: Barro, "Rare Disasters, Asset Prices, and Welfare Costs," AER, 2009.
**Cai Shu: Hsieh C. T. and P. Klenow, "Misallocation and Manufacturing Productivity in China and India," Quarterly Journal of Economics, 2009.
*November 24, 9:00 am
**Xu Sheng: Arrow and Dasgupta, "Conspicuous Consumption, Inconspicuous Leisure," Economic Journal, Forthcoming.
**Jennifer Song: Blundell et al. "Consumption Inequality and Partial Insurance" AER 2008.
**Wang Qian: Frank Smets and Rafael Wouters, "Shocks and Frictions in US Business Cycle: A Bayesian DSGE Approach", American Economic Review, 2007.
**Shen Di: Galí Jordi, López-Salido J. David and Vallés Javier "Understanding the effects of government spending on consumption " Journal of the European Economic Association 2007
*December 1, 9:00 am
**Ren Qitian: Arellano, "Default risk and income fluctuations in Emerging economies" American Economic Review 2008.
**Ma Qing, "When Can Changes in Expectations Cause Business Cycle Fluctuations in Neo-Classical Settings?", Journal of Economic Theory, 2007.
**Kong Lingbing: Acemoglu Daron and Veronica Guerrieri, “Capital Deepening and Non-Balanced Economic Growth," Journal of Political Economy, 2008.
**Dong Xiaoxiao: Christiano, Eichenbaum, and Rebelo, "WHEN IS THE GOVERNMENT SPENDING MULTIPLIER LARGE", NBER, 2009. 
*December 3, 10:00 am
**Wong Chun Kwan,"Ngai Rachel and Christopher Pissarides, “Structural Change in a Multi-Sector Model of Growth,” American Economic Review, 2007.
**Zhong Xiangmin: Jose-Victor Rios-Rull and Raul Santaeulalia-Llopis, "Redistributive shocks and productivity shocks", JME, 2010.
!November 22, 2012
*Wang Bo: [[Hsieh and Klenow, "Misallocation and Manufacturing TFP in China and India," QJE 2009|http://faculty.chicagobooth.edu/chang-tai.hsieh/research/MMTFP.pdf]]
*Xu Jiawei: [[Barro, "Rare Disasters, Asset Prices, and Welfare Costs," AER 2009|http://piketty.pse.ens.fr/fichiers/enseig/ecoineg/articl/Barro2009.pdf]]
*Jiang Yilin: [[Klein, Krusell and Rios-Rull, "Time-Consistent Public Policy,"ReStud 2008|http://restud.oxfordjournals.org/content/75/3/789.full.pdf+html]]
!November 29, 2012
*Hu Kun: [[P Beaudry, F Portier, "When can changes in expectations cause business cycle fluctuations in neo-classical settings" JET 2007 |http://www.sciencedirect.com/science/article/pii/S0022053106001517]]
*Song Chenlu: [[Fatih Guvenen, "A Parsimonious Macroeconomics Model for Asset Pricing," Econometrica 2009.|http://onlinelibrary.wiley.com/doi/10.3982/ECTA6658/pdf]]
*Chen Sihao: [[Jaimovich and Rebelo: "Can News about the Future Drive the Business Cycle?" AER 2009|http://www.aeaweb.org/articles.php?doi=10.1257/aer.99.4.1097]]
*Li Weikai: [[Gabaix, "Variable Rare Disasters: an Exactly Solved Framework for Ten Puzzles in Macro-Finance,"QJE 2012|http://pages.stern.nyu.edu/~xgabaix/papers/tenPuzzles.pdf]]
!December 6, 2012
*Zhang Ran: [[Song, Storesletten, and Zilibotti: "Growing like China" AER 2011|http://pubs.aeaweb.org/doi/pdfplus/10.1257/aer.101.1.196]]
*Song Tianle: [[Florin O. Bilbiie, Fabio Ghironi, and Marc J. Melitz, "Endogenous Entry, Product Variety, and Business Cycles," Journal of Political Economy, Vol. 120, No. 2 (April 2012), pp. 304-345.|http://www.jstor.org/discover/10.1086/665825?uid=3738176&uid=2134&uid=2&uid=70&uid=4&sid=21101278787743]]
*Zeng Xueyang: [[Blundell, Richard, Luigi Pistaferri, and Ian Preston. 2008. "Consumption Inequality and Partial Insurance." American Economic Review, 98(5): 1887-1921|http://www.jstor.org/stable/10.2307/29730156]]
*Jiang Bo: [[Acemoglu Daron, Philippe Aghion, Leonardo Bursztyn, and David Hemous, "The Environment and Directed Technical Change", AER 2012.|http://pubs.aeaweb.org/doi/pdfplus/10.1257/aer.102.1.131]]
!December 8, 2012, Room 4503
*Liu Ke: [[Jaimovich and Floetotto, "Firm dynamics, markup variations, and the business cycle". Journal of Monetary Economics, 2008.|http://ac.els-cdn.com/S0304393208001207/1-s2.0-S0304393208001207-main.pdf?_tid=a0043956-3481-11e2-ba91-00000aab0f27&acdnat=1353574391_b1225e0fc3c897e9d4844b7748809078]]
*Justin Leung:  [[Doepke and Zilibotti "Occupational Choice and the Spirit of Capitalism," QJE 2008 |http://qje.oxfordjournals.org/content/123/2/747.full.pdf+html]]
*Zou Teng: [[Hansen, Heaton, and Li, "Consumption Strikes Back? Measuring Long‐Run Risk," JPE 2008|http://www.jstor.org/stable/pdfplus/10.1086/588200.pdf?acceptTC=true]]
!Nov 12
*ZOU Xianqiang: [[Song, Storesletten, and Zilibotti: "Growing like China" AER 2011|http://pubs.aeaweb.org/doi/pdfplus/10.1257/aer.101.1.196]]
*Yong Kil AHN: [[Wachter, Jessica, Can Time-Varying Risk of Rare Disasters Explain Aggregate Stock Market Volatility?|https://docs.google.com/file/d/1V-x08j1f_KkrR4AXFcKN55e0AiRAZAnHt5EiCjO6sGjplXGIu32NX6WZM98o/edit?usp=sharing]]
*Kelvin YUEN: [[Jaimovich, Nir, and Sergio Rebelo. 2009. "Can News about the Future Drive the Business Cycle?" American Economic Review, 99(4): 1097-1118.|http://pubs.aeaweb.org/doi/pdfplus/10.1257/aer.99.4.1097]]
*SU Xijian: [[Mark Gertler and Peter Karadi, "A Model of Unconventional Monetary Policy," JME 2010|http://ac.els-cdn.com/S0304393210001261/1-s2.0-S0304393210001261-main.pdf?_tid=60de50f8-4110-11e3-9712-00000aab0f6c&acdnat=1383102615_08437f0dee49b8f3726f77788b6783d9]]
!Nov 16
*ZHANG Zilei:  [[Hsieh and Klenow, "Misallocation and Manufacturing TFP in China and India," QJE 2009|http://faculty.chicagobooth.edu/chang-tai.hsieh/research/MMTFP.pdf]]
*ZHOU Ti: [[Xavier Gabaix, "Variable Rare Disasters: An Exactly Solved Framework for Ten Puzzles in Macro-Finance," QJE 2009|http://qje.oxfordjournals.org/content/127/2/645.full.pdf+html]]
*John CHENG: [[Eric Hanushek & Ludger Woessmann, 2012. "Do better schools lead to more growth? Cognitive skills, economic outcomes, and causation," Journal of Economic Growth, Springer, vol. 17(4), pages 267-321, December.|http://hanushek.stanford.edu/sites/default/files/publications/Hanushek%2BWoessmann%202012%20JEconGrowth%2017%284%29.pdf]]
*XU Sichuang: [[Jermann and Quadrini, "Macroeconomic Effects of Financial Shocks, NBER Working Paper 2009|http://www.nber.org/papers/w15338]]
!Nov 23
*ZHOU Fei: [[Brunnermeier and Sannikov, "A Macroeconomic Model with a Financial Sector", AER 2013|http://www.princeton.edu/~sannikov/macro_finance.pdf]]
*JIN Shuang: [[Bianchi, Javier. 2011. "Overborrowing and Systemic Externalities in theBusiness Cycle." American Economic Review, 101(7): 3400-3426|http://econ.as.nyu.edu/docs/IO/18565/Bianchi_20110113.pdf]]
*WONG Yufu: [[Daron Acemoglu, Philippe Aghion, Leonardo Bursztyn, and David Hemous "The Environment and Directed Technical Change" NBER 2009 |http://dspace.mit.edu/openaccess-disseminate/1721.1/61749]]
*LIANG Yuanning: [[Carol Corrado, Charles Hulten, Daniel Sichel, "Intangible Capital and US Economic Growth," Review of Income and Wealth. 2009|http://onlinelibrary.wiley.com/doi/10.1111/j.1475-4991.2009.00343.x/pdf]]
*WANG Shi: [[François Gourio."Disasters Risk and Business Cycles" NBER Working Paper 2009|http://www.nber.org/papers/w15399]]
!Nov 26
*WANG Shiqi: [[Margaret S. McMillan and Dani Rodrik, "Globalization, structural change and productivity growth" NBER, 2011|http://www.ifpri.org/sites/default/files/publications/ifpridp01160.pdf]]
*ZHANG Qiang: [[Justiniano, Alejandro, Giorgio E. Primiceri, and Andrea Tambalotti. "Investment shocks and business cycles." Journal of Monetary Economics 57.2 (2010): 132-145.|http://ac.els-cdn.com/S0304393210000048/1-s2.0-S0304393210000048-main.pdf?_tid=70106874-4235-11e3-aebd-00000aab0f26&acdnat=1383228483_036a4ef748f52abc6910ef7a48ae8e8e]]
*CHAN Man Hing: [[Philippe Aghion, Richard Blundell, Rachel Griffith, Peter Howitt, and Susanne Prant, "The Effects of Entry on Incumbent Innovation and Productivity," Review of Economics and Statistics 2009 91:1, 20-32 |http://www.econstor.eu/bitstream/10419/51205/1/563419822.pdf]]
*XU Chenjie: [[Fatih Guvenen, A Parsimonious Macroeconomic Model for Asset Pricing. Econometrica (Vol. 77, No. 6, November 2009, pp. 1711-1750)|http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.195.605&rep=rep1&type=pdf]]
*ZHAO Liping: [[Gertler and Kiyotaki: “ Financial Intermediation and Credit Policy in Business Cycle Analysis” Handbook of Monetary Economics, 2010.|http://www.gaia.e.u-tokyo.ac.jp/utipe/news/macro0622.pdf]]
Due date to be announced.

[[Problem Set I: (Due September 24)|http://ihome.ust.hk/~dxie/Econ5250/5250set1.pdf]]
[[Problem Set 2: (Due October 8)|http://ihome.ust.hk/~dxie/Econ5250/5250set2.pdf]]
[[Problem Set 3: (Due October 15)|http://ihome.ust.hk/~dxie/Econ5250/5250set3.pdf]].                Dataset can be found [[here|http://ihome.ust.hk/~dxie/OnlineMacro/mrwdata.xls]]
[[Problem Set 4: (Due October 22)|http://ihome.ust.hk/~dxie/Econ5250/5250set4.pdf]]
[[Problem Set 5: (Due November 16)|http://ihome.ust.hk/~dxie/Econ5250/5250set5.pdf]].               Dataset can be found [[here|http://ihome.ust.hk/~dxie/Econ5250/HK.xlsx]]
[[Caballero and Farhi, "The Safety Trap" |http://scholar.harvard.edu/files/farhi/files/safetytrap_021414_ef.pdf]]
Danyang Xie, HKUST
Econ 5250. Macroeconomic Theory I
''Econ 5250: Macroeconomic Theory I
Course Website: http://econ5250.tiddlyspot.com/
Fall 2013
Instructor: Danyang Xie
Office Hours: Friday 2:00 pm to 3:30 pm or by appointment''
	
!Course Outline and Reading List
		
This course covers deterministic and stochastic models of economic growth. These dynamic models are used to conduct business cycle analysis and to discuss government fiscal and monetary policies. Background in dynamic optimization is helpful but not required.

@@All the blue items are the required readings. You need to print them out by yourself.@@
	
There is no required textbook. The following books are recommended for general reference:
	
#Olivier Blanchard and Stanley Fischer, Lectures on Macroeconomics, MIT Press, 1989.
#Thomas Sargent, Dynamic Macroeconomic Theory, Harvard University Press, 1987.
#Barro and ~Sala-i-Martin, Economic Growth,~McGraw-Hill, Inc. 2nd Edition, 2003.
#Roger E. A. Farmer, The Macroeconomics of ~Self-Fulfilling Prophecies, MIT Press,1993.
#David Romer, Advanced Macroeconomics, Second Edition, ~McGraw-Hill, 2001.

The following articles are for general discussions:
#Blanchard Olivier, "What Do We Know about Macroeconomics that Fisher and Wicksell did not?" Quarterly Journal of Economics, 2000.
#Woodford Michael,"Revolution and Evolution in ~Twentieth-Century Macroeconomics," 1999.
#Mankiw Gregory,"The Macroeconomist as Scientist and Engineer," NBER, 2006.
#Chari V.V. and P. Kehoe,"Modern Macroeconomics in Practice: How Theory is Shaping Policy," Journal of Economic Perspectives, 2006.
#[[Krugman Paul,"How Did Economists Get it So Wrong," September 2009|http://www.nytimes.com/2009/09/06/magazine/06Economic-t.html?pagewanted=print]]
#[[John Cochrane, "How Did Paul Krugman Get it So Wrong." 2009]] 

!Evaluation Criterion
	
The evaluation is based on a final exam (50%), a set of homework (10%),  paper presentation (25 percent) and participation in class discussion (15%). The exam will be open-book. @@Selection Criteria for a paper to be used for presentation (1. 2009 or more recent; 2. related to the topics covered; 3. a Google citation above 100.) @@

!Topics and Readings 

''An Introduction and Math Preparation''
*[[Major Development in Macroeconomics|http://ihome.ust.hk/~dxie/Econ5250/majordevelopment.pdf]]
*[[Chapter 17|http://ihome.ust.hk/~dxie/Econ5250/ch17.pdf]]
*[[Heuristic Derivation of Hamiltonian Approach|http://ihome.ust.hk/~dxie/Econ5250/hamiltoniansimplified.pdf]]

''A. 	Growth Theory (4 weeks)''

A.1 Classics

Solow Robert, “A Contribution to the Theory of Economic Growth,” Quarterly Journal of Economics, Vol. 70, 1956: 65-94.
Ramsey Frank, “A Mathematical Theory of Saving,” Economic Journal, Vol. 38, December 1928: 543-559.

A.2 Endogenous Growth: ~One-Sector Model

*[[Chapter 18|http://ihome.ust.hk/~dxie/Econ5250/ch18.pdf]]
*[[Backward Shooting: Mathcad Program|http://ihome.ust.hk/~dxie/Econ5250/backwardshooting.pdf]]
*[[Chapter 19|http://ihome.ust.hk/~dxie/Econ5250/ch19.pdf]]
*[[Chapter 20|http://ihome.ust.hk/~dxie/Econ5250/ch20.pdf]]
[[Romer, Paul “Increasing Returns and Long Run Growth,” Journal of Political Economy, Vol. 94, 1986:1002-1037.|http://ihome.ust.hk/~dxie/OnlineMacro/romerjpe1986.pdf]]
[[Xie, Danyang “Increasing Returns and Increasing Rates of Growth,” Journal of Political Economy, April, 1991: 429-435.|http://ihome.ust.hk/~dxie/OnlineMacro/xiejpe.pdf]]

A.3 Endogenous Growth: ~Two-Sector Model

[[Lucas, Robert, E. Jr. “On the Mechanics of Economic Development,” Journal of Monetary Economics, Vol. 22, 1988:3-42.|http://ihome.ust.hk/~dxie/OnlineMacro/lucasjme1988.pdf]]
[[Xie Danyang “Divergence in Economic Performance: Transitional Dynamics with Multiple Equilibria,” Journal of Economic Theory, Vol. 63, June, 1994: 97-112.|http://ihome.ust.hk/~dxie/OnlineMacro/xiejet1994.pdf]]
[[Romer, Paul “Endogenous Technological Change,” Journal of Political Economy, Vol. 98, 1990: ~S71-S102.|http://ihome.ust.hk/~dxie/OnlineMacro/romerjpe1990.pdf]]
*[[Notes on Romer 1990|http://ihome.ust.hk/~dxie/Econ5250/Note Endogenous Technological Change.pdf]]
Grossman Gene and Elhanan Helpman, “Endogenous Product Cycles,” Economic Journal, Vol. 101, September, 1991: 1214-1229.
Grossman Gene and Elhanan Helpman “Quality Ladders in the Theory of Growth,” Review of Economic Studies, Vol. 58, January, 1991: 43-61.
Bond Eric, Ping Wang and C, K. Yip, “A General ~Two-Sector Model of Endogenous Growth with Physical and Human Capital: Balanced Growth and Transitional Dynamics,” Journal of Economic Theory, vol. 68, 1996, 149—173.

A4. Fiscal Policies in Endogenous Growth Models

Rebelo, Sergio, “~Long-Run Policy Analysis and ~Long-Run Growth,” Journal of Political Economy, Vol. 99, No. 3, 1991: 500-521.
Barro, Robert, J. “Government Spending in a Simple Model of Endogenous Growth,” Journal of Political Economy, Vol. 98, No. 5, 1990: ~S103-S125.
[[Devarajan, Shantayanan, Danyang Xie and Heng-fu Zou, “Does Public Capital Formation Promote Economic Growth,”|http://ihome.ust.hk/~dxie/OnlineMacro/xiejme1998.pdf]] Journal of Monetary Economics, April, 1998.

A.5. Structural Change and Economic Growth 

[[Kongsamut Piyabha, Sergio Rebelo and D. Xie, “Beyond Balanced Growth,”|http://ihome.ust.hk/~dxie/OnlineMacro/xieres2001.pdf]] Review of Economic Studies, Vol. 68, November, 2001: 869-882. 
Ngai Rachel and Christopher Pissarides, “Structural Change in a ~Multi-Sector Model of Growth,” American Economic Review, 2007.
Acemoglu Daron and Veronica Guerrieri, “Capital Deepening and ~Non-Balanced Economic Growth," Journal of Political Economy, 2008.
*[[Acemoglu's presentation of KRX and his paper on Non-Balanced Growth|http://econ-www.mit.edu/files/1953]]

''B.	Empirics of Growth (1 week)''

B.1 Growth Regression and Convergence Debate

[[Presentation: Determinants of Growth|http://ihome.ust.hk/~dxie/Econ5250/Part 5 Determinants of Growth.pptx]]
[[N. Gregory Mankiw, David Romer, and David Weil, “A Contribution to the Emprics of Economic Growth,” Quarterly Journal of Economics, 107 (1992), 407-438.|http://ihome.ust.hk/~dxie/Econ5250/MRW QJE 1992.pdf]]
*[[Note on MRW|http://ihome.ust.hk/~dxie/Econ5250/Note on mrw.pdf]], [[The derivation of item 20 in the Note on MRW|http://ihome.ust.hk/~dxie/Econ5250/notemrw-item20.pdf]]
Bernard, A. B. and Jones, C. I. , “Technology and Convergence,” Economic Journal, 106, 1996, 1037-1044.	
Jones, Charles I. “Convergence Revisited,” Journal of Economic Growth, Vol. 2, July, 1997: 131-153.	
Jones, Charles I. “On the Evolution of the World Income Distribution,” Journal of Economic Perspectives, Summer, 11, 1997: 19-36.	
Quah, D. T. “Twin Peaks: Growth and Convergence in Models of Distribution Dynamics”. Economic Journal, 106, 1996: 1045-1055.
Hsieh C. T. and P. Klenow, "Misallocation and Manufacturing Productivity in China and India," Quarterly Journal of Economics, 2009.
Lucas, R. E. Jr. "Trade and the Diffusion of the Industrial Revolution," ~AEJ-Macro 2009.
[[Bernanke and Gurkaynak, "Is Growth Exogenous? Taking Mankiw, Romer, Weil Seriously,", NBER Macroeconomics Annual 2001|http://ihome.ust.hk/~dxie/Econ5250/bernanke on mrw.pdf]]
[[Note on Bernanke and Gurkaynak]]

	
B.2. Growth Accounting

Alwyn Young, “A Tale of Two Cities:Factor Accumulation and Technical Change in Hong Kong and Singapore,” NBER Macroeconomics Annual 1992, 13-54.

B.3. Finance and Growth

Rafael La Porta, Florencio ~Lopez-de-Silanes, Andrei Shleifer, and Robert Vishny, “Investor Protection and Corporate Valuation,” Journal of Finance, 2002.
King Robert G. and Ross Levine, “Finance and Growth: Schumpeter Might be Right,” Quarterly Journal of Economics, Vol. 108, 1993: 717-737.
Levine Ross, Norman Loayza, and Thorsten Beck, “Financial Intermediation and Growth: Causality and Causes,” Journal of Monetary Economics, Vol. 46, 2000: 31-77.

B4. Law and Development
   
Daron Acemoglu,, Simon Johnson, and James A. Robinson, “The Colonial Origins of Comparative Development: An Empirical Investigation,” American Economic Review, December 2001: 1369-1401.
	
''C.	Real Business Cycle Models (2 weeks)''
	
C.1. Classics

Long, John, Jr. and Charles Plosser, “Real Business Cycles,” Journal of Political Economy, Vol. 91, 1983: 39-69.
Kydland Finn and Edward Prescott, “Time to Build and Aggregate Fluctuations,” Econometrica, Vol. 50, November, 1982: 1345-1370.
[[Introduction to RBC|http://ihome.ust.hk/~dxie/Econ5250/Introduction to RBC.pdf]] and [[An example of the use of HP Filter|http://ihome.ust.hk/~dxie/Econ5250/SP500 HP Filter.pdf]]
[[Wang Pengfei's Example|http://ihome.ust.hk/~dxie/Econ5250/Wang Pengfei rbc example.pdf]]

C.2. Refinements
	
~McCallum, Bennett, “Real Business Cycle Models,” Modern Business Cycle Theory, (Robert J. Barro, ed.), 1988.
Prescott Edward “Theory Ahead of ~Business-Cycle Measurement,” ~Carnegie-Rochester Conference Series on Public Policy, Vol. 25, Autumn, 1985: 11-44	
Hansen, Gary, “Indivisible Labor and the Business cycle,” Journal of Monetary Economy, Vol. 16, November, 1985: 309-327.	
King R. G. and C. Plosser, 1984, “Money, Credit, and Prices in a Real Business Cycle,” American Economic Review, Vol. 74, June, 1984: 363-380.	
King R. G. and M. W. Watson, “Money, Prices, Interest Rates and the Business Cycle,” Review of Economics and Statistics, Vol 78, February, 1996: 35-53.	
[[Robert G. King and Sergio T. Rebelo, 2000. “Resuscitating Real Business Cycles,” RCER Working Papers 467, University of Rochester - Center for Economic Research (RCER).|http://ihome.ust.hk/~dxie/Econ5250/kingrebelo.pdf]]
[[Note on King and Rebelo|http://ihome.ust.hk/~dxie/Econ5250/Note on Resusciting_RBC.pdf]]

C 3 ~Self-Fulfilling Prophecies

Cass David and Karl Shell, “Do Sunspots Matter?” Journal of Political Economy, Vol. 91, 1983: 193-227.
Asariadis, Costas, “~Self-Fulfilling Prophecies,” Journal of Economic Theory, Vol. 25, 1981: 380-396.
Benhabib Jess and Roger Farmer, “Indeterminacy and Increasing Returns,” Journal of Economic Theory, Vol. 63, June, 1994: 19-41.	
[[Farmer Roger, and ~Jang-Ting Guo, “Real Business Cycles and the Animal Spirits Hypothesis,” Journal of Economic Theory, Vol. 63, June 1994: 42-72.|http://ihome.ust.hk/~dxie/Econ5250/farmer_guo.pdf]]
[[Note on Farmer and Guo|http://ihome.ust.hk/~dxie/Econ5250/Note on farmerguo.pdf]]	
Day Richard, “Irregular Growth Cycles,” American Economic Review, Vol. 72, 1982: 406-414.	
Benhabib Jess and Richard Day, “A Characterization of Erratic dynamics in the Overlapping Generations Model,” Journal of Economic Dynamics and Control, Vol. 4, 1982: 37-55.	
Benhabib Jess and K Nishimura, “Competitive Equilibrium Cycles,” Journal of Economic Theory, Vol. 35, 1985: 284-306.
	
''D.	Consumption Behavior (1 week)''

Hall Robert E. “Stochastic Implications of the Life ~Cycle-Permanent Income Hypothesis: Theory and Evidence,” Journal of Political Economy, December 1978: 971-988.	
[[Note on Consumption Behavior|http://ihome.ust.hk/~dxie/Econ5250/Note on consumption.pdf]]
[[Flavin Marjorie “The Adjustment of Consumption to Changing Expectations about Future Income,” Journal of Political Economy, Vol. 89 October 1981: 974-1009.|http://ihome.ust.hk/~dxie/OnlineMacro/flavin.pdf]]	
[[Campbell and Deaton “Why Is Consumption Too Smooth?” Review of Economic Studies, Vol. 56, 1989: 357-374.|http://ihome.ust.hk/~dxie/Econ5250/campbell and deaton.pdf]]	
Christiano Lawrence, Eichenbaum Martin and David Marshall “The Permanent Income Hypothesis Revisited,” Econometrica, Vol. 59, No. 2 (March, 1991): 397-423.
	
''E.	Asset Pricing (1 week)''
	
[[Note on Asset Pricing|http://ihome.ust.hk/~dxie/Econ5250/Note Asset Pricing.pdf]]
Lucas Robert E., Jr. “Asset Prices in an Exchange Economy,” Econometrica, Vol. 46, 1978: 1429-1445.	
Hansen Lars Peter “Calculating Asset Prices in Three Example Economies,” in Advances in Econometrics, Fifth World Congress, edited, Truman F. Bewley, Cambridge University Press, 1987: 207-243.	
Hansen Lars Peter and Scott F. Richard “The Role of Conditioning Information in Deducing Testable Restrictions Implied by Dynamic Asset Pricing Models,” Econometrica, Vol. 55 May, 1987: 587-613.	
Mehra Rajnish and Edward Prescott “The Equity Premium: a Puzzle,” Journal of Monetary Economics, January, 1985: 145-61.	
Constantinides George “Habit Formation: A Resolution of the Equity Premium Puzzle,” Journal of Political Economy, 1990.	
Abel Andrew, “Asset Prices under Habit Formation and Catching up with the Joneses,” American Economic Review, May, 1990: 38-42.
[[Note on Equity Premium Puzzle|http://ihome.ust.hk/~dxie/Econ5250/Note Equity Premium Puzzle taken by Greenwood.pdf]]
[[Note on Habit Formation|http://ihome.ust.hk/~dxie/Econ5250/Note Habit Formation.pdf]]
Savov Alexi, "Asset Pricing with Garbage," Journal of Finance, 2011.

	
''F.	Time Inconsistency of Government Policies (3 weeks)''
	
F.1. Classics
	
[[Kydland Finn and Edward Prescott, “The Inconsistency of Optimal Plans,” Journal of Political Economy, Vol. 85, 1977: 473–492.|http://ihome.ust.hk/~dxie/Econ5250/rulesdiscretion.pdf]]	
[[Note on Time Consistency|http://ihome.ust.hk/~dxie/Econ5250/Note Time Consistency.pdf]]
[[Fischer Stanley, “Dynamic Inconsistency, Cooperation, and the Benevolent Dissembling Government,” Journal of Economic Dynamics and Control, Vol. 2, 1980: 93–107.|http://ihome.ust.hk/~dxie/Econ5250/Fischer JEDC 1980.pdf]]
[[Blanchard interview Fischer|http://ihome.ust.hk/~dxie/Econ5250/blanchardinterviewfischer.pdf]], 2004.
Barro Robert and David Gordon, “Rules, Discretion and Reputation in a Model of Monetary Policy,” Journal of Monetary Economics,  Vol. 12, 1983: 101–121.	
[[Note on Barro and Gordon|http://ihome.ust.hk/~dxie/Econ5250/Note Barro and Gordon.pdf]]
Rogoff, Kenneth, “The Optimal Degree of Commitment to an Intermediate Monetary Target,” Quarterly Journal of Economics, Vol. 85, 1985: 1169–1189.	
Lucas Robert Jr. and Nancy Stokey, “Optimal Fiscal and Monetary Policy in an Economy Without Capital,” Journal of Monetary Economics, Vol. 12, 1983: 55–93.	
[[Note on Lucas and Stokey 1983|http://ihome.ust.hk/~dxie/Econ5250/Note Lucas and Stokey.pdf]]
Persson Torsten and Lars Svensson, “Why a Stubborn Conservative Would Run a Deficit: Policy with ~Time-Inconsistent Preferences,” Quarterly Journal of Economics,, Vol 104, 1989: 325–345.

F.2 Discrete Time Models

Abreu D, D. Pearce, and E. Stachetti, “Toward a Theory of Discounted Repeated Games with Imperfect Monitoring,” Econometrica, Vol. 58, 1990: 1041-1063.
Chang Roberto, “Credible Monetary Policy in an Infinite Horizon Model: Recursive Approaches,” Journal of Economic Theory, Vol. 81, 1998: 431–461. 
Chari V.V. and Kehoe Patrick,” Optimal Fiscal and Monetary Policy,” Handbook of Macroeconomics, 1999.  
~Schmitt-Grohe Stephanie and Martin Uribe,"Optimal Fiscal and Monetary Policy under Sticky Prices,” Journal of Economic Theory, 2004.
Alvarez Fernando, Patrick J. Kehoe and Pablo A. Neumeyer, 2004. "The Time Consistency of Optimal Monetary and Fiscal Policies," Econometrica, Econometric Society, vol. 72(2), pages 541-567 

F.3. Continuous Time Models

[[Xie Danyang, “On Time Inconsistency: A Technical Issue in Stackelberg Differential Games,” Journal of Economic Theory, Vol. 76, 1997: 412–430.|http://ihome.ust.hk/~dxie/Papers/xiejet1997.pdf]]
[[Karp Larry and In Ho Lee, “Time Consistent Policies,” Journal of Economic Theory, Vol. 112, 2003: 353-364.|http://ihome.ust.hk/~dxie/Econ5250/Karp and Lee Consistency.pdf]]
Lansing K, “Optimal redistributive capital taxation in a neoclassical growth model,” Journal of Public Economics, 1999: 423-453. 
[[Note on Lansing JPubE 1999|http://ihome.ust.hk/~dxie/Econ5250/Note Lansing Optimal Redistributive Capital Taxation.pdf]]

''G. New Public Finance (if time permits)''
#Golosov M. and R. Kocherlakota,"Optimal indirect and capital taxation," Review of Economic Studies, 2003.
#Golosov, M. A. Tsyvinski, and I. Werning, "New Dynamic Public Finance: A User’s Guide", 2007.

''H.	Economics of Cities (if time permits)''
	
Henderson Vernon, “Urbanization and Growth,” Chapter 5, Handbook of Economic Growth, Volume 1, Elsevier, 2005.
Lucas R. E. Jr. and E. ~Rossi-Hansberg, “On the Internal Structure of Cities,” Econometrica, Vol. 70, No. 4. July 2002: 1445-1476.
Xie D., “Technical Progress and Urbanization Process,” The B.E. Journal of Macroeconomics: Vol. 8 : Iss. 1 (Contributions), 2008..
Wang Ping and D. Xie, “Housing Dynamics: Theory Behind Empirics,” Manuscript, 2012.
/***
Description: Contains the stuff you need to use Tiddlyspot
Note, you also need UploadPlugin, PasswordOptionPlugin and LoadRemoteFileThroughProxy
from http://tiddlywiki.bidix.info for a complete working Tiddlyspot site.
***/
//{{{

// edit this if you are migrating sites or retrofitting an existing TW
config.tiddlyspotSiteId = 'econ5250';

// make it so you can by default see edit controls via http
config.options.chkHttpReadOnly = false;
window.readOnly = false; // make sure of it (for tw 2.2)
window.showBackstage = true; // show backstage too

// disable autosave in d3
if (window.location.protocol != "file:")
	config.options.chkGTDLazyAutoSave = false;

// tweak shadow tiddlers to add upload button, password entry box etc
with (config.shadowTiddlers) {
	SiteUrl = 'http://'+config.tiddlyspotSiteId+'.tiddlyspot.com';
	SideBarOptions = SideBarOptions.replace(/(<<saveChanges>>)/,"$1<<tiddler TspotSidebar>>");
	OptionsPanel = OptionsPanel.replace(/^/,"<<tiddler TspotOptions>>");
	DefaultTiddlers = DefaultTiddlers.replace(/^/,"[[WelcomeToTiddlyspot]] ");
	MainMenu = MainMenu.replace(/^/,"[[WelcomeToTiddlyspot]] ");
}

// create some shadow tiddler content
merge(config.shadowTiddlers,{

'TspotOptions':[
 "tiddlyspot password:",
 "<<option pasUploadPassword>>",
 ""
].join("\n"),

'TspotControls':[
 "| tiddlyspot password:|<<option pasUploadPassword>>|",
 "| site management:|<<upload http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/store.cgi index.html . .  " + config.tiddlyspotSiteId + ">>//(requires tiddlyspot password)//<br>[[control panel|http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/controlpanel]], [[download (go offline)|http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/download]]|",
 "| links:|[[tiddlyspot.com|http://tiddlyspot.com/]], [[FAQs|http://faq.tiddlyspot.com/]], [[blog|http://tiddlyspot.blogspot.com/]], email [[support|mailto:support@tiddlyspot.com]] & [[feedback|mailto:feedback@tiddlyspot.com]], [[donate|http://tiddlyspot.com/?page=donate]]|"
].join("\n"),

'WelcomeToTiddlyspot':[
 "This document is a ~TiddlyWiki from tiddlyspot.com.  A ~TiddlyWiki is an electronic notebook that is great for managing todo lists, personal information, and all sorts of things.",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //What now?// &nbsp;&nbsp;@@ Before you can save any changes, you need to enter your password in the form below.  Then configure privacy and other site settings at your [[control panel|http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/controlpanel]] (your control panel username is //" + config.tiddlyspotSiteId + "//).",
 "<<tiddler TspotControls>>",
 "See also GettingStarted.",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //Working online// &nbsp;&nbsp;@@ You can edit this ~TiddlyWiki right now, and save your changes using the \"save to web\" button in the column on the right.",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //Working offline// &nbsp;&nbsp;@@ A fully functioning copy of this ~TiddlyWiki can be saved onto your hard drive or USB stick.  You can make changes and save them locally without being connected to the Internet.  When you're ready to sync up again, just click \"upload\" and your ~TiddlyWiki will be saved back to tiddlyspot.com.",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //Help!// &nbsp;&nbsp;@@ Find out more about ~TiddlyWiki at [[TiddlyWiki.com|http://tiddlywiki.com]].  Also visit [[TiddlyWiki.org|http://tiddlywiki.org]] for documentation on learning and using ~TiddlyWiki. New users are especially welcome on the [[TiddlyWiki mailing list|http://groups.google.com/group/TiddlyWiki]], which is an excellent place to ask questions and get help.  If you have a tiddlyspot related problem email [[tiddlyspot support|mailto:support@tiddlyspot.com]].",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //Enjoy :)// &nbsp;&nbsp;@@ We hope you like using your tiddlyspot.com site.  Please email [[feedback@tiddlyspot.com|mailto:feedback@tiddlyspot.com]] with any comments or suggestions."
].join("\n"),

'TspotSidebar':[
 "<<upload http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/store.cgi index.html . .  " + config.tiddlyspotSiteId + ">><html><a href='http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/download' class='button'>download</a></html>"
].join("\n")

});
//}}}
| !date | !user | !location | !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |
| 30/10/2013 08:52:09 | YourName | [[/|http://econ5250.tiddlyspot.com/]] | [[store.cgi|http://econ5250.tiddlyspot.com/store.cgi]] | . | [[index.html | http://econ5250.tiddlyspot.com/index.html]] | . |
| 31/10/2013 18:07:57 | YourName | [[/|http://econ5250.tiddlyspot.com/]] | [[store.cgi|http://econ5250.tiddlyspot.com/store.cgi]] | . | [[index.html | http://econ5250.tiddlyspot.com/index.html]] | . |
| 01/11/2013 16:18:20 | YourName | [[/|http://econ5250.tiddlyspot.com/]] | [[store.cgi|http://econ5250.tiddlyspot.com/store.cgi]] | . | [[index.html | http://econ5250.tiddlyspot.com/index.html]] | . |
| 02/11/2013 14:56:07 | YourName | [[/|http://econ5250.tiddlyspot.com/]] | [[store.cgi|http://econ5250.tiddlyspot.com/store.cgi]] | . | [[index.html | http://econ5250.tiddlyspot.com/index.html]] | . |
| 04/11/2013 15:03:42 | Danyang Xie | [[/|http://econ5250.tiddlyspot.com/]] | [[store.cgi|http://econ5250.tiddlyspot.com/store.cgi]] | . | [[index.html | http://econ5250.tiddlyspot.com/index.html]] | . |
| 04/11/2013 15:04:43 | Danyang Xie | [[/|http://econ5250.tiddlyspot.com/]] | [[store.cgi|http://econ5250.tiddlyspot.com/store.cgi]] | . | [[index.html | http://econ5250.tiddlyspot.com/index.html]] | . |
| 05/11/2013 22:00:13 | Danyang Xie | [[/|http://econ5250.tiddlyspot.com/]] | [[store.cgi|http://econ5250.tiddlyspot.com/store.cgi]] | . | [[index.html | http://econ5250.tiddlyspot.com/index.html]] | . |
| 16/11/2013 13:53:12 | Danyang Xie | [[/|http://econ5250.tiddlyspot.com/]] | [[store.cgi|http://econ5250.tiddlyspot.com/store.cgi]] | . | [[index.html | http://econ5250.tiddlyspot.com/index.html]] | . |
| 16/11/2013 17:59:25 | Danyang Xie | [[/|http://econ5250.tiddlyspot.com/]] | [[store.cgi|http://econ5250.tiddlyspot.com/store.cgi]] | . | [[index.html | http://econ5250.tiddlyspot.com/index.html]] | . |
| 18/02/2014 14:34:54 | Danyang Xie | [[/|http://econ5250.tiddlyspot.com/]] | [[store.cgi|http://econ5250.tiddlyspot.com/store.cgi]] | . | [[index.html | http://econ5250.tiddlyspot.com/index.html]] | . |
/***
|''Name:''|UploadPlugin|
|''Description:''|Save to web a TiddlyWiki|
|''Version:''|4.1.3|
|''Date:''|Feb 24, 2008|
|''Source:''|http://tiddlywiki.bidix.info/#UploadPlugin|
|''Documentation:''|http://tiddlywiki.bidix.info/#UploadPluginDoc|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0|
|''Requires:''|PasswordOptionPlugin|
***/
//{{{
version.extensions.UploadPlugin = {
	major: 4, minor: 1, revision: 3,
	date: new Date("Feb 24, 2008"),
	source: 'http://tiddlywiki.bidix.info/#UploadPlugin',
	author: 'BidiX (BidiX (at) bidix (dot) info',
	coreVersion: '2.2.0'
};

//
// Environment
//

if (!window.bidix) window.bidix = {}; // bidix namespace
bidix.debugMode = false;	// true to activate both in Plugin and UploadService
	
//
// Upload Macro
//

config.macros.upload = {
// default values
	defaultBackupDir: '',	//no backup
	defaultStoreScript: "store.php",
	defaultToFilename: "index.html",
	defaultUploadDir: ".",
	authenticateUser: true	// UploadService Authenticate User
};
	
config.macros.upload.label = {
	promptOption: "Save and Upload this TiddlyWiki with UploadOptions",
	promptParamMacro: "Save and Upload this TiddlyWiki in %0",
	saveLabel: "save to web", 
	saveToDisk: "save to disk",
	uploadLabel: "upload"	
};

config.macros.upload.messages = {
	noStoreUrl: "No store URL in parmeters or options",
	usernameOrPasswordMissing: "Username or password missing"
};

config.macros.upload.handler = function(place,macroName,params) {
	if (readOnly)
		return;
	var label;
	if (document.location.toString().substr(0,4) == "http") 
		label = this.label.saveLabel;
	else
		label = this.label.uploadLabel;
	var prompt;
	if (params[0]) {
		prompt = this.label.promptParamMacro.toString().format([this.destFile(params[0], 
			(params[1] ? params[1]:bidix.basename(window.location.toString())), params[3])]);
	} else {
		prompt = this.label.promptOption;
	}
	createTiddlyButton(place, label, prompt, function() {config.macros.upload.action(params);}, null, null, this.accessKey);
};

config.macros.upload.action = function(params)
{
		// for missing macro parameter set value from options
		if (!params) params = {};
		var storeUrl = params[0] ? params[0] : config.options.txtUploadStoreUrl;
		var toFilename = params[1] ? params[1] : config.options.txtUploadFilename;
		var backupDir = params[2] ? params[2] : config.options.txtUploadBackupDir;
		var uploadDir = params[3] ? params[3] : config.options.txtUploadDir;
		var username = params[4] ? params[4] : config.options.txtUploadUserName;
		var password = config.options.pasUploadPassword; // for security reason no password as macro parameter	
		// for still missing parameter set default value
		if ((!storeUrl) && (document.location.toString().substr(0,4) == "http")) 
			storeUrl = bidix.dirname(document.location.toString())+'/'+config.macros.upload.defaultStoreScript;
		if (storeUrl.substr(0,4) != "http")
			storeUrl = bidix.dirname(document.location.toString()) +'/'+ storeUrl;
		if (!toFilename)
			toFilename = bidix.basename(window.location.toString());
		if (!toFilename)
			toFilename = config.macros.upload.defaultToFilename;
		if (!uploadDir)
			uploadDir = config.macros.upload.defaultUploadDir;
		if (!backupDir)
			backupDir = config.macros.upload.defaultBackupDir;
		// report error if still missing
		if (!storeUrl) {
			alert(config.macros.upload.messages.noStoreUrl);
			clearMessage();
			return false;
		}
		if (config.macros.upload.authenticateUser && (!username || !password)) {
			alert(config.macros.upload.messages.usernameOrPasswordMissing);
			clearMessage();
			return false;
		}
		bidix.upload.uploadChanges(false,null,storeUrl, toFilename, uploadDir, backupDir, username, password); 
		return false; 
};

config.macros.upload.destFile = function(storeUrl, toFilename, uploadDir) 
{
	if (!storeUrl)
		return null;
		var dest = bidix.dirname(storeUrl);
		if (uploadDir && uploadDir != '.')
			dest = dest + '/' + uploadDir;
		dest = dest + '/' + toFilename;
	return dest;
};

//
// uploadOptions Macro
//

config.macros.uploadOptions = {
	handler: function(place,macroName,params) {
		var wizard = new Wizard();
		wizard.createWizard(place,this.wizardTitle);
		wizard.addStep(this.step1Title,this.step1Html);
		var markList = wizard.getElement("markList");
		var listWrapper = document.createElement("div");
		markList.parentNode.insertBefore(listWrapper,markList);
		wizard.setValue("listWrapper",listWrapper);
		this.refreshOptions(listWrapper,false);
		var uploadCaption;
		if (document.location.toString().substr(0,4) == "http") 
			uploadCaption = config.macros.upload.label.saveLabel;
		else
			uploadCaption = config.macros.upload.label.uploadLabel;
		
		wizard.setButtons([
				{caption: uploadCaption, tooltip: config.macros.upload.label.promptOption, 
					onClick: config.macros.upload.action},
				{caption: this.cancelButton, tooltip: this.cancelButtonPrompt, onClick: this.onCancel}
				
			]);
	},
	options: [
		"txtUploadUserName",
		"pasUploadPassword",
		"txtUploadStoreUrl",
		"txtUploadDir",
		"txtUploadFilename",
		"txtUploadBackupDir",
		"chkUploadLog",
		"txtUploadLogMaxLine"		
	],
	refreshOptions: function(listWrapper) {
		var opts = [];
		for(i=0; i<this.options.length; i++) {
			var opt = {};
			opts.push();
			opt.option = "";
			n = this.options[i];
			opt.name = n;
			opt.lowlight = !config.optionsDesc[n];
			opt.description = opt.lowlight ? this.unknownDescription : config.optionsDesc[n];
			opts.push(opt);
		}
		var listview = ListView.create(listWrapper,opts,this.listViewTemplate);
		for(n=0; n<opts.length; n++) {
			var type = opts[n].name.substr(0,3);
			var h = config.macros.option.types[type];
			if (h && h.create) {
				h.create(opts[n].colElements['option'],type,opts[n].name,opts[n].name,"no");
			}
		}
		
	},
	onCancel: function(e)
	{
		backstage.switchTab(null);
		return false;
	},
	
	wizardTitle: "Upload with options",
	step1Title: "These options are saved in cookies in your browser",
	step1Html: "<input type='hidden' name='markList'></input><br>",
	cancelButton: "Cancel",
	cancelButtonPrompt: "Cancel prompt",
	listViewTemplate: {
		columns: [
			{name: 'Description', field: 'description', title: "Description", type: 'WikiText'},
			{name: 'Option', field: 'option', title: "Option", type: 'String'},
			{name: 'Name', field: 'name', title: "Name", type: 'String'}
			],
		rowClasses: [
			{className: 'lowlight', field: 'lowlight'} 
			]}
};

//
// upload functions
//

if (!bidix.upload) bidix.upload = {};

if (!bidix.upload.messages) bidix.upload.messages = {
	//from saving
	invalidFileError: "The original file '%0' does not appear to be a valid TiddlyWiki",
	backupSaved: "Backup saved",
	backupFailed: "Failed to upload backup file",
	rssSaved: "RSS feed uploaded",
	rssFailed: "Failed to upload RSS feed file",
	emptySaved: "Empty template uploaded",
	emptyFailed: "Failed to upload empty template file",
	mainSaved: "Main TiddlyWiki file uploaded",
	mainFailed: "Failed to upload main TiddlyWiki file. Your changes have not been saved",
	//specific upload
	loadOriginalHttpPostError: "Can't get original file",
	aboutToSaveOnHttpPost: 'About to upload on %0 ...',
	storePhpNotFound: "The store script '%0' was not found."
};

bidix.upload.uploadChanges = function(onlyIfDirty,tiddlers,storeUrl,toFilename,uploadDir,backupDir,username,password)
{
	var callback = function(status,uploadParams,original,url,xhr) {
		if (!status) {
			displayMessage(bidix.upload.messages.loadOriginalHttpPostError);
			return;
		}
		if (bidix.debugMode) 
			alert(original.substr(0,500)+"\n...");
		// Locate the storeArea div's 
		var posDiv = locateStoreArea(original);
		if((posDiv[0] == -1) || (posDiv[1] == -1)) {
			alert(config.messages.invalidFileError.format([localPath]));
			return;
		}
		bidix.upload.uploadRss(uploadParams,original,posDiv);
	};
	
	if(onlyIfDirty && !store.isDirty())
		return;
	clearMessage();
	// save on localdisk ?
	if (document.location.toString().substr(0,4) == "file") {
		var path = document.location.toString();
		var localPath = getLocalPath(path);
		saveChanges();
	}
	// get original
	var uploadParams = new Array(storeUrl,toFilename,uploadDir,backupDir,username,password);
	var originalPath = document.location.toString();
	// If url is a directory : add index.html
	if (originalPath.charAt(originalPath.length-1) == "/")
		originalPath = originalPath + "index.html";
	var dest = config.macros.upload.destFile(storeUrl,toFilename,uploadDir);
	var log = new bidix.UploadLog();
	log.startUpload(storeUrl, dest, uploadDir,  backupDir);
	displayMessage(bidix.upload.messages.aboutToSaveOnHttpPost.format([dest]));
	if (bidix.debugMode) 
		alert("about to execute Http - GET on "+originalPath);
	var r = doHttp("GET",originalPath,null,null,username,password,callback,uploadParams,null);
	if (typeof r == "string")
		displayMessage(r);
	return r;
};

bidix.upload.uploadRss = function(uploadParams,original,posDiv) 
{
	var callback = function(status,params,responseText,url,xhr) {
		if(status) {
			var destfile = responseText.substring(responseText.indexOf("destfile:")+9,responseText.indexOf("\n", responseText.indexOf("destfile:")));
			displayMessage(bidix.upload.messages.rssSaved,bidix.dirname(url)+'/'+destfile);
			bidix.upload.uploadMain(params[0],params[1],params[2]);
		} else {
			displayMessage(bidix.upload.messages.rssFailed);			
		}
	};
	// do uploadRss
	if(config.options.chkGenerateAnRssFeed) {
		var rssPath = uploadParams[1].substr(0,uploadParams[1].lastIndexOf(".")) + ".xml";
		var rssUploadParams = new Array(uploadParams[0],rssPath,uploadParams[2],'',uploadParams[4],uploadParams[5]);
		var rssString = generateRss();
		// no UnicodeToUTF8 conversion needed when location is "file" !!!
		if (document.location.toString().substr(0,4) != "file")
			rssString = convertUnicodeToUTF8(rssString);	
		bidix.upload.httpUpload(rssUploadParams,rssString,callback,Array(uploadParams,original,posDiv));
	} else {
		bidix.upload.uploadMain(uploadParams,original,posDiv);
	}
};

bidix.upload.uploadMain = function(uploadParams,original,posDiv) 
{
	var callback = function(status,params,responseText,url,xhr) {
		var log = new bidix.UploadLog();
		if(status) {
			// if backupDir specified
			if ((params[3]) && (responseText.indexOf("backupfile:") > -1))  {
				var backupfile = responseText.substring(responseText.indexOf("backupfile:")+11,responseText.indexOf("\n", responseText.indexOf("backupfile:")));
				displayMessage(bidix.upload.messages.backupSaved,bidix.dirname(url)+'/'+backupfile);
			}
			var destfile = responseText.substring(responseText.indexOf("destfile:")+9,responseText.indexOf("\n", responseText.indexOf("destfile:")));
			displayMessage(bidix.upload.messages.mainSaved,bidix.dirname(url)+'/'+destfile);
			store.setDirty(false);
			log.endUpload("ok");
		} else {
			alert(bidix.upload.messages.mainFailed);
			displayMessage(bidix.upload.messages.mainFailed);
			log.endUpload("failed");			
		}
	};
	// do uploadMain
	var revised = bidix.upload.updateOriginal(original,posDiv);
	bidix.upload.httpUpload(uploadParams,revised,callback,uploadParams);
};

bidix.upload.httpUpload = function(uploadParams,data,callback,params)
{
	var localCallback = function(status,params,responseText,url,xhr) {
		url = (url.indexOf("nocache=") < 0 ? url : url.substring(0,url.indexOf("nocache=")-1));
		if (xhr.status == 404)
			alert(bidix.upload.messages.storePhpNotFound.format([url]));
		if ((bidix.debugMode) || (responseText.indexOf("Debug mode") >= 0 )) {
			alert(responseText);
			if (responseText.indexOf("Debug mode") >= 0 )
				responseText = responseText.substring(responseText.indexOf("\n\n")+2);
		} else if (responseText.charAt(0) != '0') 
			alert(responseText);
		if (responseText.charAt(0) != '0')
			status = null;
		callback(status,params,responseText,url,xhr);
	};
	// do httpUpload
	var boundary = "---------------------------"+"AaB03x";	
	var uploadFormName = "UploadPlugin";
	// compose headers data
	var sheader = "";
	sheader += "--" + boundary + "\r\nContent-disposition: form-data; name=\"";
	sheader += uploadFormName +"\"\r\n\r\n";
	sheader += "backupDir="+uploadParams[3] +
				";user=" + uploadParams[4] +
				";password=" + uploadParams[5] +
				";uploaddir=" + uploadParams[2];
	if (bidix.debugMode)
		sheader += ";debug=1";
	sheader += ";;\r\n"; 
	sheader += "\r\n" + "--" + boundary + "\r\n";
	sheader += "Content-disposition: form-data; name=\"userfile\"; filename=\""+uploadParams[1]+"\"\r\n";
	sheader += "Content-Type: text/html;charset=UTF-8" + "\r\n";
	sheader += "Content-Length: " + data.length + "\r\n\r\n";
	// compose trailer data
	var strailer = new String();
	strailer = "\r\n--" + boundary + "--\r\n";
	data = sheader + data + strailer;
	if (bidix.debugMode) alert("about to execute Http - POST on "+uploadParams[0]+"\n with \n"+data.substr(0,500)+ " ... ");
	var r = doHttp("POST",uploadParams[0],data,"multipart/form-data; ;charset=UTF-8; boundary="+boundary,uploadParams[4],uploadParams[5],localCallback,params,null);
	if (typeof r == "string")
		displayMessage(r);
	return r;
};

// same as Saving's updateOriginal but without convertUnicodeToUTF8 calls
bidix.upload.updateOriginal = function(original, posDiv)
{
	if (!posDiv)
		posDiv = locateStoreArea(original);
	if((posDiv[0] == -1) || (posDiv[1] == -1)) {
		alert(config.messages.invalidFileError.format([localPath]));
		return;
	}
	var revised = original.substr(0,posDiv[0] + startSaveArea.length) + "\n" +
				store.allTiddlersAsHtml() + "\n" +
				original.substr(posDiv[1]);
	var newSiteTitle = getPageTitle().htmlEncode();
	revised = revised.replaceChunk("<title"+">","</title"+">"," " + newSiteTitle + " ");
	revised = updateMarkupBlock(revised,"PRE-HEAD","MarkupPreHead");
	revised = updateMarkupBlock(revised,"POST-HEAD","MarkupPostHead");
	revised = updateMarkupBlock(revised,"PRE-BODY","MarkupPreBody");
	revised = updateMarkupBlock(revised,"POST-SCRIPT","MarkupPostBody");
	return revised;
};

//
// UploadLog
// 
// config.options.chkUploadLog :
//		false : no logging
//		true : logging
// config.options.txtUploadLogMaxLine :
//		-1 : no limit
//      0 :  no Log lines but UploadLog is still in place
//		n :  the last n lines are only kept
//		NaN : no limit (-1)

bidix.UploadLog = function() {
	if (!config.options.chkUploadLog) 
		return; // this.tiddler = null
	this.tiddler = store.getTiddler("UploadLog");
	if (!this.tiddler) {
		this.tiddler = new Tiddler();
		this.tiddler.title = "UploadLog";
		this.tiddler.text = "| !date | !user | !location | !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |";
		this.tiddler.created = new Date();
		this.tiddler.modifier = config.options.txtUserName;
		this.tiddler.modified = new Date();
		store.addTiddler(this.tiddler);
	}
	return this;
};

bidix.UploadLog.prototype.addText = function(text) {
	if (!this.tiddler)
		return;
	// retrieve maxLine when we need it
	var maxLine = parseInt(config.options.txtUploadLogMaxLine,10);
	if (isNaN(maxLine))
		maxLine = -1;
	// add text
	if (maxLine != 0) 
		this.tiddler.text = this.tiddler.text + text;
	// Trunck to maxLine
	if (maxLine >= 0) {
		var textArray = this.tiddler.text.split('\n');
		if (textArray.length > maxLine + 1)
			textArray.splice(1,textArray.length-1-maxLine);
			this.tiddler.text = textArray.join('\n');		
	}
	// update tiddler fields
	this.tiddler.modifier = config.options.txtUserName;
	this.tiddler.modified = new Date();
	store.addTiddler(this.tiddler);
	// refresh and notifiy for immediate update
	story.refreshTiddler(this.tiddler.title);
	store.notify(this.tiddler.title, true);
};

bidix.UploadLog.prototype.startUpload = function(storeUrl, toFilename, uploadDir,  backupDir) {
	if (!this.tiddler)
		return;
	var now = new Date();
	var text = "\n| ";
	var filename = bidix.basename(document.location.toString());
	if (!filename) filename = '/';
	text += now.formatString("0DD/0MM/YYYY 0hh:0mm:0ss") +" | ";
	text += config.options.txtUserName + " | ";
	text += "[["+filename+"|"+location + "]] |";
	text += " [[" + bidix.basename(storeUrl) + "|" + storeUrl + "]] | ";
	text += uploadDir + " | ";
	text += "[[" + bidix.basename(toFilename) + " | " +toFilename + "]] | ";
	text += backupDir + " |";
	this.addText(text);
};

bidix.UploadLog.prototype.endUpload = function(status) {
	if (!this.tiddler)
		return;
	this.addText(" "+status+" |");
};

//
// Utilities
// 

bidix.checkPlugin = function(plugin, major, minor, revision) {
	var ext = version.extensions[plugin];
	if (!
		(ext  && 
			((ext.major > major) || 
			((ext.major == major) && (ext.minor > minor))  ||
			((ext.major == major) && (ext.minor == minor) && (ext.revision >= revision))))) {
			// write error in PluginManager
			if (pluginInfo)
				pluginInfo.log.push("Requires " + plugin + " " + major + "." + minor + "." + revision);
			eval(plugin); // generate an error : "Error: ReferenceError: xxxx is not defined"
	}
};

bidix.dirname = function(filePath) {
	if (!filePath) 
		return;
	var lastpos;
	if ((lastpos = filePath.lastIndexOf("/")) != -1) {
		return filePath.substring(0, lastpos);
	} else {
		return filePath.substring(0, filePath.lastIndexOf("\\"));
	}
};

bidix.basename = function(filePath) {
	if (!filePath) 
		return;
	var lastpos;
	if ((lastpos = filePath.lastIndexOf("#")) != -1) 
		filePath = filePath.substring(0, lastpos);
	if ((lastpos = filePath.lastIndexOf("/")) != -1) {
		return filePath.substring(lastpos + 1);
	} else
		return filePath.substring(filePath.lastIndexOf("\\")+1);
};

bidix.initOption = function(name,value) {
	if (!config.options[name])
		config.options[name] = value;
};

//
// Initializations
//

// require PasswordOptionPlugin 1.0.1 or better
bidix.checkPlugin("PasswordOptionPlugin", 1, 0, 1);

// styleSheet
setStylesheet('.txtUploadStoreUrl, .txtUploadBackupDir, .txtUploadDir {width: 22em;}',"uploadPluginStyles");

//optionsDesc
merge(config.optionsDesc,{
	txtUploadStoreUrl: "Url of the UploadService script (default: store.php)",
	txtUploadFilename: "Filename of the uploaded file (default: in index.html)",
	txtUploadDir: "Relative Directory where to store the file (default: . (downloadService directory))",
	txtUploadBackupDir: "Relative Directory where to backup the file. If empty no backup. (default: ''(empty))",
	txtUploadUserName: "Upload Username",
	pasUploadPassword: "Upload Password",
	chkUploadLog: "do Logging in UploadLog (default: true)",
	txtUploadLogMaxLine: "Maximum of lines in UploadLog (default: 10)"
});

// Options Initializations
bidix.initOption('txtUploadStoreUrl','');
bidix.initOption('txtUploadFilename','');
bidix.initOption('txtUploadDir','');
bidix.initOption('txtUploadBackupDir','');
bidix.initOption('txtUploadUserName','');
bidix.initOption('pasUploadPassword','');
bidix.initOption('chkUploadLog',true);
bidix.initOption('txtUploadLogMaxLine','10');


// Backstage
merge(config.tasks,{
	uploadOptions: {text: "upload", tooltip: "Change UploadOptions and Upload", content: '<<uploadOptions>>'}
});
config.backstageTasks.push("uploadOptions");


//}}}
bidix.UploadLog.prototype.endUpload = function(status) {
if (this.tiddler) this.addText(" "+status+" |");
window.location.reload( false );
};
if (!version.extensions.YourSearchPlugin) {

version.extensions.YourSearchPlugin = {
	major: 2, minor: 1, revision: 5,
	source: "http://tiddlywiki.abego-software.de/#YourSearchPlugin",
	licence: "[[BSD open source license (abego Software)|http://www.abego-software.de/legal/apl-v10.html]]",
	copyright: "Copyright (c) abego Software GmbH, 2005-2010 (www.abego-software.de)"
};

if (!window.abego) window.abego = {};

// define the Array forEach when not yet defined (e.g. by Mozilla)
if (!Array.forEach) {
    Array.forEach = function(obj, callback, thisObj) {
        for (var i = 0,len = obj.length; i < len; i++)
            callback.call(thisObj, obj[i], i, obj);
    };
    Array.prototype.forEach = function(callback, thisObj) {
        for (var i = 0,len = this.length; i < len; i++)
            callback.call(thisObj,  this[i], i, this);
    };
}

abego.toInt = function(s, defaultValue) {
	if (!s) return defaultValue;
	var n = parseInt(s);
	return (n == NaN) ? defaultValue : n;
};

abego.createEllipsis = function(place) {
	var e = createTiddlyElement(place,"span");
	e.innerHTML = "&hellip;";
};

//#concept Object
//
abego.shallowCopy = function(object) {
	if (!object)
		return object;
	var result = {};
	for (var n in object) 
		result[n] = object[n];
	return result;
};

// Returns a shallow copy of the options, or a new, empty object if options is null/undefined.
//
// @param options [may be null/undefined]
//
//#concept Object, Options
//#import abego.shallowCopy
//
abego.copyOptions = function(options) {
	return !options ? {} : abego.shallowCopy(options);
};

//#import abego.define-namespace
// returns the number of occurances of s in the text
abego.countStrings = function(text, s) {
	if (!s)
		return 0;
		
	var len = s.length;
	var n = 0;
	var lastIndex = 0;
	while (1) {
		var i = text.indexOf(s, lastIndex);
		if (i < 0)
			return n;
		n++;
		lastIndex = i+len;
	}
	return n;
};// Returns the content of the first "braced" text {...}
// Also takes care of nested braces
//
// Returns undefined when no braced text is found or it is not properly nested
//
// @param [optional] when defined and a braced text is found lastIndexRef.lastIndex will contain the index of the char following the (final) closing brace on return.
//
abego.getBracedText = function(text, offset,lastIndexRef) {
	if (!offset) offset = 0;
	var re = /\{([^\}]*)\}/gm;
	re.lastIndex = offset;
	var m = re.exec(text);
	if (m) {
		// The matching stopped at the first closing brace.
		// But if the matched text contains opening braces 
		// this is not the final closing brace.
		// Handle this case specially, find the "corresponding" closing brace
		var s = m[1];
		var nExtraOpenBrace = abego.countStrings(s,"{");
		
		if (!nExtraOpenBrace) {
			if (lastIndexRef)
				lastIndexRef.lastIndex = re.lastIndex;
			// simple case: no nested braces
			return s;
		}

		// special case: "nested braces"
		var len = text.length;
		for (var i = re.lastIndex; i < len && nExtraOpenBrace; i++) {
			var c = text.charAt(i);
			if (c == "{") 
				nExtraOpenBrace++;
			else if (c == "}")
				nExtraOpenBrace--;
		}
		if (!nExtraOpenBrace) {
			// found the corresponding "}".
			if (lastIndexRef)
				lastIndexRef.lastIndex = i-1;
			return text.substring(m.index+1, i-1);
		}
	}
	
	// no return means: return undefined;
};

// Returns an array with those items from the array that pass the given test
//
// @param test an one-arg boolean function that returns true when the item should be added.
// @param testObj [optional] the receiver for the test function (global if undefined or null)
// @param result [optional] an array. When define the selected items are added to this array, otherwise a new array is used.
//
//#import Array.prototype.forEach
//
abego.select = function(array,test,testObj,result) {
	if (!result) result = [];
	array.forEach(function(t) {
		if (test.call(testObj,t)) 
			result.push(t);
		});
	return result;
};

// A portable way to "consume an event"
// 
// (Uses "stopPropagation" and "preventDefault", but will also "cancelBubble",
// even though this is a "non-standard method" , just in case).
//
abego.consumeEvent = function(e) {
	if (e.stopPropagation) e.stopPropagation();
	if (e.preventDefault) e.preventDefault();
	e.cancelBubble = true;
	e.returnValue = true;
};

// Class abego.TiddlerFilterTerm =================================================================
//
// Used to check if a tiddler contains a given text.
//
// A list of fields (standard and/or extended) may be specified to restrict the search to certain fields. 
//
// When no explicit fields are given the fields defined by defaultFields are checked, plus all extended 
// fields (when options.withExtendedFields is true).
//
// @param options [may be null/undefined]
//		options.fields @seeParam abego.MultiFieldRegExpTester.fields
// 		options.withExtendedFields @seeParam abego.MultiFieldRegExpTester.withExtendedFields  
// 		options.caseSensitive [Default: false]
// 		options.fullWordMatch [Default: false]
// 		options.textIsRegExp [Default: false] when true the given text is already a regExp
//
//#import abego.MultiFieldRegExpTester
//
abego.TiddlerFilterTerm = function(text,options) {
	if (!options) options = {};

	var reText = text;
	if (!options.textIsRegExp) {
		reText = text.escapeRegExp();
		if (options.fullWordMatch) 
			reText = "\\b"+reText+"\\b";
	}
	var regExp = new RegExp(reText, "m"+(options.caseSensitive ? "" : "i"));

	this.tester = new abego.MultiFieldRegExpTester(regExp, options.fields, options.withExtendedFields);
}

abego.TiddlerFilterTerm.prototype.test = function(tiddler) {
	return this.tester.test(tiddler);
}

// Recognize a string like
//     "Some Title. Some content text #Tag1 #Tag2 Tag3"
// with the tags and the text being optional.
// Also the period at the end of the title is optional when no content text is specified)
//
// Returns the result in an object with properties "title" and "params",
// with "params" following the parseParams format, containing the "tag" and "text" arguments.
//
abego.parseNewTiddlerCommandLine = function(s) {
	var m = /(.*?)\.(?:\s+|$)([^#]*)(#.*)?/.exec(s);
	if (!m) 
		m = /([^#]*)()(#.*)?/.exec(s);
	if (m) {
		var r;
		if (m[3]) {
			var s2 = m[3].replace(/#/g,"");
			r = s2.parseParams("tag");
		} else
			r = [[]];
			
		// add the text parameter
		var text = m[2]?m[2].trim():"";
		r.push({name: "text", value: text});
		r[0].text = [text];
		
		return {title: m[1].trim(), params: r}; 
	} else
		return {title: s.trim(),params: [[]]};
}	
// 		options.defaultFields [@seeOptionDefault abego.TiddlerFilterTerm.fields] fields to check when no fields are explicitly specified in queryText.
// 		options.withExtendedFields [@seeOptionDefault abego.TiddlerFilterTerm.withExtendedFields] when true and no fields are explicitly specified in queryText also the extended fields are considered (in addition to the ones in defaultFields).
// @seeOptions abego.TiddlerFilterTerm (-fields -fullWordMatch -withExtendedFields)
//
//#import abego.getBracedText
//#import abego.copyOptions
//#import abego.TiddlerFilterTerm
//
abego.parseTiddlerFilterTerm = function(queryText,offset,options) {
	
	// group 1: {...} 		(JavaScript expression)
	// group 2: '=' 		(full word match (optional))
	// group 3: [!%#] 		(field selection short cuts)
	// group 4: fieldName ':'
	// group 5: String literal "..."
	// group 6: RegExp literal /.../
	// group 7: scheme '://' nonSpaceChars
	// group 8: word
	var re = /\s*(?:(?:\{([^\}]*)\})|(?:(=)|([#%!])|(?:(\w+)\s*\:(?!\/\/))|(?:(?:("(?:(?:\\")|[^"])+")|(?:\/((?:(?:\\\/)|[^\/])+)\/)|(\w+\:\/\/[^\s]+)|([^\s\)\-\"]+)))))/mg; // " <- The syntax highlighting of my editors gets confused without this quote
	var shortCuts = {'!':'title','%':'text','#':'tags'};
	
	var fieldNames = {};
	var fullWordMatch;
	re.lastIndex = offset;
	while (1) {
		var i = re.lastIndex;
		var m = re.exec(queryText);
		if (!m || m.index != i) 
			throw "Word or String literal expected";
		if (m[1]) {
			var lastIndexRef = {};
			var code = abego.getBracedText(queryText,0,lastIndexRef);
			if (!code)
				throw "Invalid {...} syntax";
			var f = Function("tiddler","return ("+code+");");
			return {func: f,
					lastIndex:lastIndexRef.lastIndex,
					markRE: null};
		}
		if (m[2])
			fullWordMatch = true;
		else if (m[3]) 
			fieldNames[shortCuts[m[3]]] = 1;
		else if (m[4]) 
			fieldNames[m[4]] = 1;
		else {
			var textIsRegExp = m[6];
			var text = m[5] ? window.eval(m[5]) : m[6] ? m[6] :  m[7] ? m[7] : m[8];
			
			var options = abego.copyOptions(options);
			options.fullWordMatch = fullWordMatch;
			options.textIsRegExp = textIsRegExp;

			var fields = [];
			for (var n in fieldNames)
				fields.push(n);
			if (fields.length == 0) {
				options.fields = options.defaultFields;
			} else {
				options.fields = fields;
				options.withExtendedFields	= false;
			}	
			var term = new abego.TiddlerFilterTerm(text,options);
			var markREText = textIsRegExp ? text : text.escapeRegExp();
			if (markREText && fullWordMatch)
				markREText = "\\b"+markREText+"\\b";
			return {func: function(tiddler) {return term.test(tiddler);},
					lastIndex:re.lastIndex,
					markRE: markREText ? "(?:"+markREText+")" : null};
		}
	}
};

// Class abego.BoolExp =================================================================
//
// Allows the execution/evaluation of a boolean expression, according to this syntax:
//
// boolExpression    : unaryExpression (("AND"|"OR"|"&&"|"||")? unaryExpression)*
//                   ;
//
// unaryExpression   : ("not"|"-")? primaryExpression
//                   ;
//
// primaryExpression : "(" boolExpression ")" 
//                   | Term
//                   ;
//
// For flexibility the Term syntax is defined by a separate parse function.
//
// Notice that there is no precedence between "AND" and "OR" operators, i.e. they are evaluated from left to right.
//
// To evaluate the expression in a given context use code like this:
//
//	var be = new abego.BoolExp(s, termParseFunc);
//  var result = be.exec(context);
// 
// @param s the text defining the expression 
// @param parseTermFunc a Function(text,offset,options) that parses the text starting at offset for a "Term" and returns an object with properties {func: Function(context), lastIndex: ...}. func is the function to be used to evaluate the term in the given context.
// @param options [may be null/undefined] (is also passed to the parseTermFunc)
// 			options.defaultOperationIs_OR [Default: false] When true the concatenation of unaryExpressions (without an operator) is interpreted as an "OR", otherwise as an "AND".
// 			options.caseSensitive [default: false]
//
abego.BoolExp = function(s, parseTermFunc, options) {
	this.s = s;
	var defaultOperationIs_OR = options && options.defaultOperationIs_OR;
	
	var reStart = /\s*(?:(\-|not)|(\())/gi; 		// group 1: NOT, group2 "("
	var reCloseParenthesis = /\s*\)/g;  			// match )
	var reAndOr = /\s*(?:(and|\&\&)|(or|\|\|))/gi; 	// group 1: AND, group 2: OR
	var reNonWhiteSpace = /\s*[^\)\s]/g;
	
	var reNot_Parenthesis = /\s*(\-|not)?(\s*\()?/gi;
	
	var parseBoolExpression; //#Pre-declare function name to avoid problem with "shrinkSafe"
	
	var parseUnaryExpression = function(offset) {
		reNot_Parenthesis.lastIndex = offset;
		var m = reNot_Parenthesis.exec(s);
		var negate;
		var result;
		if (m && m.index == offset) {
			offset += m[0].length;
			negate = m[1];
			if (m[2]) {
				// case:  (...)
				var e = parseBoolExpression(offset);
				reCloseParenthesis.lastIndex = e.lastIndex;
				if (!reCloseParenthesis.exec(s))
					throw "Missing ')'";
				result = {func: e.func, lastIndex: reCloseParenthesis.lastIndex, markRE: e.markRE};
			}
		}
		if (!result)
			result = parseTermFunc(s,offset,options);

		if (negate) {
			result.func = (function(f){return function(context) {return !f(context);}})(result.func);
			// don't mark patterns that are negated
			// (This is essential since the marking may also be used to calculate "ranks". If we
			// would also count the negated matches (i.e. that should not exist) the rank may get too high)
			result.markRE = null;
		}
		return result;
	};

	parseBoolExpression = function(offset) {
		var result = parseUnaryExpression(offset);
		while (1) {
			var l = result.lastIndex;
			reAndOr.lastIndex = l;
			var m = reAndOr.exec(s);
			var isOrCase;
			var nextExp;
			if (m && m.index == l) {
				isOrCase = !m[1];
				nextExp = parseUnaryExpression(reAndOr.lastIndex);
			} else {
				// no "AND" or "OR" found. 
				// Maybe it is a concatenations of parseUnaryExpression without operators
				try {
					nextExp = parseUnaryExpression(l);
				} catch (e) {
					// no unary expression follows. We are done
					return result;
				}
				isOrCase = defaultOperationIs_OR;
			}
			result.func = (function(func1, func2, isOrCase) {
					return isOrCase
						? function(context) {return func1(context) || func2(context);}
						: function(context) {return func1(context) && func2(context);};
				})(result.func,nextExp.func,isOrCase);
			result.lastIndex = nextExp.lastIndex;
			if (!result.markRE)
				result.markRE = nextExp.markRE;
			else if (nextExp.markRE) 
				result.markRE = result.markRE + "|" + nextExp.markRE;
		}
	};
	
	var expr = parseBoolExpression(0);
	this.evalFunc = expr.func;
	if (expr.markRE)
		this.markRegExp = new RegExp(expr.markRE, options.caseSensitive ? "mg" : "img");
}

abego.BoolExp.prototype.exec = function() {
	return this.evalFunc.apply(this,arguments);
};

abego.BoolExp.prototype.getMarkRegExp = function() {
	return this.markRegExp;
};

abego.BoolExp.prototype.toString = function() {
	return this.s;
};

// Class abego.MultiFieldRegExpTester ==================================================================
//
// @param fields [optional; Default: ["title","text","tags"]] array of names of fields to be considered
// @param withExtendedFields [optional; Default: false] when true also extended fields are considered (in addition to the ones given in 'fields')
//
abego.MultiFieldRegExpTester = function(re, fields, withExtendedFields) {
	this.re = re;
	this.fields = fields ? fields : ["title","text","tags"];
	this.withExtendedFields = withExtendedFields;
}

// Returns the name of the first field found that value succeeds the given test,
// or null when no such field is found
//
abego.MultiFieldRegExpTester.prototype.test = function(tiddler) {
	var re = this.re;
	// Check the fields explicitly specified
	for (var i = 0; i < this.fields.length; i++) {
		var s = store.getValue(tiddler, this.fields[i]);
		if (typeof s == "string" && re.test(s))
			return this.fields[i];		
	}
	// Check the extended fields (if required)
	if (this.withExtendedFields) 
		return store.forEachField(
				tiddler,
				function(tiddler, fieldName, value) {
					return typeof value == "string" && re.test(value)?fieldName:null;
				}, true);
		
	return null;
}

// Class abego.TiddlerQuery ==================================================================
//
//#import abego.select
//#import abego.MultiFieldRegExpTester
//
abego.TiddlerQuery = function(queryText,caseSensitive,useRegExp,defaultFields,withExtendedFields) {
	if (useRegExp) {
		this.regExp = new RegExp(queryText, caseSensitive ? "mg" : "img");
		this.tester = new abego.MultiFieldRegExpTester(this.regExp, defaultFields, withExtendedFields);
	} else {
		this.expr = new abego.BoolExp(
				queryText,
				abego.parseTiddlerFilterTerm, {
				defaultFields: defaultFields,
				caseSensitive: caseSensitive,
				withExtendedFields: withExtendedFields});
	}
	
	this.getQueryText = function() {
		return queryText;
	};
	this.getUseRegExp = function() {
		return useRegExp;
	};
	this.getCaseSensitive = function() {
		return caseSensitive;
	};
	this.getDefaultFields = function() {
		return defaultFields;
	};
	this.getWithExtendedFields = function() {
		return withExtendedFields;
	};
}

// Returns true iff the query includes the given tiddler
//
// @param tiddler [may be null/undefined]
//
abego.TiddlerQuery.prototype.test = function(tiddler) {
	if (!tiddler) return false;
	if (this.regExp) {
		return this.tester.test(tiddler);
	}
	return this.expr.exec(tiddler);
};

// Returns an array with those tiddlers from the tiddlers array that match the query.
//
abego.TiddlerQuery.prototype.filter = function(tiddlers) {
	return abego.select(tiddlers,this.test,this);
};

abego.TiddlerQuery.prototype.getMarkRegExp = function() {
	if (this.regExp) {
		// Only use the regExp for marking when it does not match the empty string.
		return "".search(this.regExp) >= 0 ? null :  this.regExp;
	}
	return this.expr.getMarkRegExp();
};

abego.TiddlerQuery.prototype.toString = function() {
	return (this.regExp ? this.regExp : this.expr).toString();
};

// Class abego.PageWiseRenderer ================================================
//
// Subclass or instance must implement getItemsPerPage function;
// They should also implement onPageChanged and refresh the container of the
// PageWiseRenderer on that event.
//
//#import abego.toInt
//
abego.PageWiseRenderer = function() {
	this.firstIndexOnPage = 0; // The index of the first item of the lastResults list displayed on the search result page
};

merge(abego.PageWiseRenderer.prototype, {
	setItems: function(items) {
		this.items = items;
		this.setFirstIndexOnPage(0);
	},
	
	// Maximum number of pages listed in the navigation bar (before or after the current page)
	//
	getMaxPagesInNavigation: function() {
		return 10;
	},
	
	getItemsCount: function(items) {
		return this.items ? this.items.length : 0;
	},
	
	getCurrentPageIndex: function() {
		return Math.floor(this.firstIndexOnPage / this.getItemsPerPage());
	},
	
	getLastPageIndex: function() {
		return Math.floor((this.getItemsCount()-1) / this.getItemsPerPage())
	},
	
	setFirstIndexOnPage: function(index) {
		this.firstIndexOnPage = Math.min(Math.max(0, index), this.getItemsCount()-1);
	},
	
	getFirstIndexOnPage: function() {
		// Ensure that the firstIndexOnPage is really a page start. 
		// This may have become violated when getItemsPerPage has changed,
		// (e.g. when switching between previewText and simple mode.)
		this.firstIndexOnPage = Math.floor(this.firstIndexOnPage / this.getItemsPerPage()) * this.getItemsPerPage();
	
		return this.firstIndexOnPage;
	},
	
	getLastIndexOnPage: function() {
		return Math.min(this.getFirstIndexOnPage()+this.getItemsPerPage()-1, this.getItemsCount()-1);
	},
	
	onPageChanged: function(pageIndex,oldPageIndex) {
	},
	
	renderPage: function(itemRenderer) {
		if (itemRenderer.beginRendering)
			itemRenderer.beginRendering(this);
		try {
			// When there are items found add them to the result page (pagewise)
			if (this.getItemsCount()) {
				// Add the items of the current page
				var lastIndex = this.getLastIndexOnPage();
				var iInPage = -1;
				for (var i=this.getFirstIndexOnPage(); i <= lastIndex; i++) {
					iInPage++;
					
					itemRenderer.render(this,this.items[i],i,iInPage);
				}
			}
		} finally {
			if (itemRenderer.endRendering)
				itemRenderer.endRendering(this);
		}
	},
	
	addPageNavigation: function(place) {
		if (!this.getItemsCount()) return;
	
		var self = this;
		var onNaviButtonClick = function(e) {
			if (!e) var e = window.event;

			abego.consumeEvent(e);

			var pageIndex = abego.toInt(this.getAttribute("page"),0);
			var oldPageIndex = self.getCurrentPageIndex();
			if (pageIndex == oldPageIndex)
				return;
			var index = pageIndex * self.getItemsPerPage();
			self.setFirstIndexOnPage(index);
			self.onPageChanged(pageIndex,oldPageIndex);	
		};
	
		var button;
		var currentPageIndex = this.getCurrentPageIndex();
		var lastPageIndex = this.getLastPageIndex();
		if (currentPageIndex > 0) {
			button = createTiddlyButton(place, "Previous", "Go to previous page (Shortcut: Alt-'<')", onNaviButtonClick, "prev");
			button.setAttribute("page",(currentPageIndex-1).toString());
			button.setAttribute("accessKey","<");
		}
	
		for (var i = -this.getMaxPagesInNavigation(); i < this.getMaxPagesInNavigation(); i++) {
			var pageIndex = currentPageIndex+i;
			if (pageIndex < 0) continue;
			if (pageIndex > lastPageIndex) break;
	
			var pageNo = (i+currentPageIndex+1).toString();
			var buttonClass = pageIndex == currentPageIndex ? "currentPage" : "otherPage";
			button = createTiddlyButton(place, pageNo, "Go to page %0".format([pageNo]), onNaviButtonClick, buttonClass);
			button.setAttribute("page",(pageIndex).toString());
		}
		
		if (currentPageIndex < lastPageIndex) {
			button = createTiddlyButton(place, "Next", "Go to next page (Shortcut: Alt-'>')", onNaviButtonClick, "next");
			button.setAttribute("page",(currentPageIndex+1).toString());
			button.setAttribute("accessKey",">");
		}
	}
});

// Class abego.LimitedTextRenderer ===========================================================
//
// Renders a given text, ensuring that a given limit of number of characters 
// is not exceeded.
//
// A "markRegExp" may be specified. Substring matching this regular expression 
// ("matched strings") are rendered with the class "marked". 
//
// if the given text is longer than the limit the matched strings are preferred 
// to be included in the rendered text (with some leading and trailing "context text"). 
// 
// Example:
//     var renderer = new abego.LimitedTextRenderer();
//
//     var place = ... // a DOM element that should contain the rendered (limited) text
//     var s = "This is another 'Hello World' example, as saying 'Hello' is always nice. So let's say it again: >Hello!<";
//     var maxLen = 50;
//     var markRE = /hello/gi;
//     renderer.render(place,s,maxLen,markRE);
// 
//#import abego.createEllipsis
//
abego.LimitedTextRenderer = function() {
	var minMatchWithContextSize = 40; 
	var maxMovementForWordCorrection = 4; // When a "match" context starts or end on a word the context borders may be changed to at most this amount to include or exclude the word.
	
	
	//----------------------------------------------------------------------------
	//
	// Ranges
	//
	// Objects with a "start" and "end" property (not a specific class). 
	// 
	// In a corresponding "Ranges array" these objects are sorted by their start 
	// and no Range object intersects/touches any other in the array.
	//
	//----------------------------------------------------------------------------
	
	// Adds the Range [startIndex,endIndex[ to the ranges, ensuring that the Ranges
	// in the array are sorted by their start and no Range object 
	// intersects/touches any other in the array (i.e. possibly the new Range is 
	// "merged" with existing ranges)
	//
	// @param ranges array of Range objects
	//
	var addRange = function(ranges, startIndex, endIndex) {
		var n = ranges.length;
		
		// When there are no ranges in ranges, just add it.
		if (n == 0) {
			ranges.push({start: startIndex, end: endIndex});
			return;
		}
		
		var i = 0;
		for (; i < n; i++) {
			var range = ranges[i];
			
			// find the first range that intersects or "touches" [startIndex, endIndex[
			if (range.start <= endIndex && startIndex <= range.end) {
				// Found.
				
				var r;
				// find the first range behind the new range that does not interfere
				var rIndex = i+1;
				for (; rIndex < n; rIndex++) {
					r = ranges[rIndex];
					if (r.start > endIndex || startIndex > range.end) {
						break;
					}
				}
				
				// Replace the ranges i to rIndex-1 with the union of the new range with these ranges.
				var unionStart = startIndex;
				var unionEnd = endIndex;
				for (var j = i; j < rIndex; j++) {
					r = ranges[j];
					unionStart = Math.min(unionStart, r.start);
					unionEnd = Math.max(unionEnd, r.end);
				}
				ranges.splice(i, rIndex-i, {start: unionStart, end: unionEnd});
				return;			
			}
			
			// if we found a range R that is right of the new range there is no
			// intersection and we can insert the new range before R.
			if (range.start > endIndex) {
				break;
			}
		}
	
		// When we are here the new range does not interfere with any range in ranges and
		// i is the index of the first range right to it (or ranges.length, when the new range
		// becomes the right most range). 
	
		ranges.splice(i, 0, {start: startIndex, end: endIndex});
	};
	
	// Returns the total size of all Ranges in ranges
	//
	var getTotalRangesSize = function(ranges) {
		var totalRangeSize = 0;
		for (var i=0; i < ranges.length; i++) {
			var range = ranges[i];
			totalRangeSize += range.end-range.start;
		}
		return totalRangeSize;
	};
	
	//----------------------------------------------------------------------------
	
	
	var isWordChar = function(c) {
		return (c >= "a" && c <= "z") || (c >= "A" && c <= "Z") || c == "_";
	};
	
	// Returns the bounds of the word in s around offset as a {start: , end:} object.
	//
	// Returns null when the char at offset is not a word char.
	//
	var getWordBounds = function(s, offset) {
		// Handle the "offset is not in word" case
		if (!isWordChar(s[offset])) return null;
	
		for (var i = offset-1; i >= 0 && isWordChar(s[i]); i--) 
			{/*empty*/}
			
		var startIndex = i+1;
		var n = s.length;
		for (i = offset+1; i < n && isWordChar(s[i]); i++) 
			{/*empty*/}
		
		return {start: startIndex, end: i};
	};
	
	var moveToWordBorder = function(s, offset, isStartOffset) {
		var wordBounds;
		if (isStartOffset) {
			wordBounds = getWordBounds(s, offset);
		} else {
			if (offset <= 0) return offset;
			wordBounds = getWordBounds(s, offset-1);
		}
		if (!wordBounds) return offset;
		
		if (isStartOffset) {
			if (wordBounds.start >= offset-maxMovementForWordCorrection) return wordBounds.start;
			if (wordBounds.end <= offset+maxMovementForWordCorrection) return wordBounds.end;
		} else {
			if (wordBounds.end <= offset+maxMovementForWordCorrection) return wordBounds.end;
			if (wordBounds.start >= offset-maxMovementForWordCorrection) return wordBounds.start;
		}
		return offset;
	};
	
	
	
	// Splits s into a sequence of "matched" and "unmatched" substrings, using the 
	// matchRegExp to do the matching.
	// 
	// Returns an array of objects with a "text" property containing the substring text. 
	// Substrings that are "matches" also contain a boolean "isMatch" property set to true.
	// 
	// @param matchRegExp [may be null] when null no matching is performed and the returned 
	// 			array just contains one item with s as its text
	// 
	var getTextAndMatchArray = function(s, matchRegExp) {
		var result = [];
		if (matchRegExp) {
			var startIndex = 0;
			var n = s.length;
			var currentLen = 0;
			do {
				matchRegExp.lastIndex = startIndex;
				var match = matchRegExp.exec(s);
				if (match) {
					if (startIndex < match.index) {
						var t = s.substring(startIndex, match.index);
						result.push({text:t});
					}
					result.push({text:match[0], isMatch:true});
					startIndex = match.index + match[0].length;
				} else {
					result.push({text: s.substr(startIndex)});
					break;
				}
			} while (true);
		} else {
			result.push({text: s});
		}
		return result;
	};
	
	
	
	var getMatchedTextCount = function(textAndMatches) {
		var result = 0;
		for (var i=0; i < textAndMatches.length; i++) {
			if (textAndMatches[i].isMatch) {
				result++;
			}
		}
		return result;	
	};
	
	
	
	var getContextRangeAround = function(s, startIndex, endIndex, matchCount, maxLen) {
		// Partition the available space into equal sized areas for each match and one 
		// for the text start.
		// But the size should not go below a certain limit
		var size = Math.max(Math.floor(maxLen/(matchCount+1)), minMatchWithContextSize);
		
		// Substract the size of the range to get the size of the context.
		var contextSize = Math.max(size-(endIndex-startIndex), 0);
		// Two thirds of the context should be before the match, one third after.
		var contextEnd = Math.min(Math.floor(endIndex+contextSize/3), s.length);
		var contextStart = Math.max(contextEnd - size, 0);
	
		// If the contextStart/End is inside a word and the end of the word is
		// close move the pointers accordingly to make the text more readable.
		contextStart = moveToWordBorder(s, contextStart, true);
		contextEnd = moveToWordBorder(s, contextEnd, false);
		
		return {start: contextStart, end: contextEnd};
	};
	
	// Get all ranges around matched substrings with their contexts
	//
	var getMatchedTextWithContextRanges = function(textAndMatches, s, maxLen) {
		var ranges = [];
		var matchCount = getMatchedTextCount(textAndMatches);
		var pos = 0;
		for (var i=0; i < textAndMatches.length; i++) {
			var t = textAndMatches[i];
			var text = t.text;
			if (t.isMatch) {
				var range = getContextRangeAround(s, pos, pos+text.length, matchCount, maxLen);
				addRange(ranges, range.start, range.end);
			}
			pos += text.length;
		}
		return ranges;
	};
	
	var fillUpRanges = function(s, ranges, maxLen) {
		var remainingLen = maxLen - getTotalRangesSize(ranges);
		while (remainingLen > 0) {
			if (ranges.length == 0) {
				// No matches added yet. Make one large range.
				addRange(ranges, 0, moveToWordBorder(s, maxLen, false));
				return;
			} else {
				var range = ranges[0];
				var startIndex;
				var maxEndIndex;
				if (range.start == 0) {
					// The first range already starts at the beginning of the string.
	
					// When there is a second range fill to the next range start or to the maxLen.
					startIndex = range.end;
					if (ranges.length > 1) {
						maxEndIndex =  ranges[1].start;
					} else {
						// Only one range. Add a range after that with the complete remaining len 
						// (corrected to "beautify" the output)
						addRange(ranges, startIndex, moveToWordBorder(s, startIndex+remainingLen, false));
						return;
					}
				} else {
					// There is unused space between the start of the text and the first range.
					startIndex = 0;
					maxEndIndex = range.start;
				}
				var endIndex = Math.min(maxEndIndex, startIndex+remainingLen);
				addRange(ranges, startIndex, endIndex);
				remainingLen -= (endIndex-startIndex);
			}
		}
	};
	
	
	// Write the given ranges of s, using textAndMatches for marking portions of the text.
	//
	var writeRanges = function(place, s, textAndMatches, ranges, maxLen) {
		if (ranges.length == 0) return;
		
		// Processes the text between startIndex and endIndex of the textAndMatches
		// "writes" them (as DOM elements) at the given place, possibly as "marked" text.
		//
		// When endIndex is not the end of the full text an ellisis is appended. 
		//
		var writeTextAndMatchRange = function(place, s, textAndMatches, startIndex, endIndex) {
			var t;
			var text;
			
			// find the first text item to write
			var pos = 0;
			var i = 0;
			var offset = 0;
			for (;i < textAndMatches.length; i++) {
				t = textAndMatches[i];
				text = t.text;
				if (startIndex < pos+text.length) {
					offset = startIndex - pos;
					break;
				}
				pos += text.length;
			}
			
			var remainingLen = endIndex - startIndex;
			for (; i < textAndMatches.length && remainingLen > 0; i++) {
				t = textAndMatches[i];
				text = t.text.substr(offset);
				offset = 0;
				if (text.length > remainingLen) text = text.substr(0,remainingLen);
				
				if (t.isMatch) {
					createTiddlyElement(place,"span",null,"marked",text);
				} else {
					createTiddlyText(place, text);
				}
				remainingLen -= text.length;
			}
			
			if (endIndex < s.length) {
				abego.createEllipsis(place);
			}
		};
		
		// When the first range is not at the start of the text write an ellipsis("...")
		// (Ellipses between ranges are written in the writeTextAndMatchRange method)
		if (ranges[0].start > 0) abego.createEllipsis(place);
	
		var remainingLen = maxLen;
		for (var i = 0; i < ranges.length && remainingLen > 0; i++) {
			var range = ranges[i];
			var len = Math.min(range.end - range.start, remainingLen);
			writeTextAndMatchRange(place, s, textAndMatches, range.start, range.start+len);
			remainingLen -= len;
		}
	};
	
	this.render = function(place,s,maxLen,markRegExp) {
		if (s.length < maxLen) maxLen = s.length;
		
		var textAndMatches = getTextAndMatchArray(s, markRegExp);
		
		var ranges = getMatchedTextWithContextRanges(textAndMatches, s, maxLen);
		
		// When the maxLen is not yet reached add more ranges 
		// starting from the beginning until either maxLen or 
		// the end of the string is reached.
		fillUpRanges(s, ranges, maxLen);
	
		writeRanges(place, s, textAndMatches, ranges, maxLen);
	};
};



(function() {

function alertAndThrow(msg) {
	alert(msg);
	throw msg;
};

if (version.major < 2 || (version.major == 2 && version.minor < 1)) 
	alertAndThrow("YourSearchPlugin requires TiddlyWiki 2.1 or newer.\n\nCheck the archive for YourSearch plugins\nsupporting older versions of TiddlyWiki.\n\nArchive: http://tiddlywiki.abego-software.de/archive");

abego.YourSearch = {};

//----------------------------------------------------------------------------
// The Search Core
//----------------------------------------------------------------------------

// Model Variables
var lastResults; // Array of tiddlers that matched the last search
var lastQuery; // The last Search query (TiddlerQuery)

var setLastResults = function(array) {
	lastResults = array;
};

var getLastResults = function() {
	return lastResults ? lastResults : [];
};

var getLastResultsCount = function() {
	return lastResults ? lastResults.length : 0;
};

// Standard Ranking Weights
var matchInTitleWeight = 4;
var precisionInTitleWeight = 10;
var matchInTagsWeight = 2;

var getMatchCount = function(s, re) {
	var m = s.match(re);
	return m ? m.length : 0;
};

var standardRankFunction = function(tiddler, query) {	
	// Count the matches in the title and the tags
	var markRE = query.getMarkRegExp();
	if (!markRE) return 1;
	
	var matchesInTitle = tiddler.title.match(markRE);
	var nMatchesInTitle =  matchesInTitle ? matchesInTitle.length : 0;
	var nMatchesInTags = getMatchCount(tiddler.getTags(), markRE);

	// Calculate the "precision" of the matches in the title as the ratio of
	// the length of the matches to the total length of the title.
	var lengthOfMatchesInTitle = matchesInTitle ? matchesInTitle.join("").length : 0;
	var precisionInTitle = tiddler.title.length > 0 ? lengthOfMatchesInTitle/tiddler.title.length : 0;
	
	// calculate a weighted score
	var rank= nMatchesInTitle * matchInTitleWeight 
			+ nMatchesInTags * matchInTagsWeight 
			+ precisionInTitle * precisionInTitleWeight 
			+ 1;

	return rank;
};

// @return Tiddler[]
//
var findMatches = function(store, searchText,caseSensitive,useRegExp,sortField,excludeTag) {
	lastQuery = null;
	
	var candidates = store.reverseLookup("tags",excludeTag,false);
	try {
		var defaultFields = [];
		if (config.options.chkSearchInTitle) defaultFields.push("title");
		if (config.options.chkSearchInText) defaultFields.push("text");
		if (config.options.chkSearchInTags) defaultFields.push("tags");
		lastQuery = new abego.TiddlerQuery(
				searchText,caseSensitive, useRegExp,defaultFields,config.options.chkSearchExtendedFields); 
	} catch (e) {
		// when an invalid query is given no tiddlers are matched
		return [];
	}

	var results = lastQuery.filter(candidates);

	// Rank the results
	var rankFunction = abego.YourSearch.getRankFunction();
	for (var i = 0; i < results.length; i++) {
		var tiddler = results[i];
		var rank = rankFunction(tiddler, lastQuery);
		// Add the rank information to the tiddler.
		// This is used during the sorting, but it may also
		// be used in the result, e.g. to display some "relevance" 
		// information in the result	
		tiddler.searchRank = rank;	
	}
	
	// sort the result, taking care of the rank and the sortField	
	if(!sortField) {
		sortField = "title";
	}
	
	var sortFunction = function (a,b) {
		var searchRankDiff = a.searchRank - b.searchRank;
		if (searchRankDiff == 0) {
			if (a[sortField] == b[sortField]) {
				return(0); 
			} else {
				return (a[sortField] < b[sortField]) ? -1 : +1; 
			}
		} else {
			return (searchRankDiff > 0) ? -1 : +1; 
		}
	};
	results.sort(sortFunction);
	return results;
};

//----------------------------------------------------------------------------
// The Search UI (Result page)
//----------------------------------------------------------------------------


// Visual appearance of the result page
var maxCharsInTitle = 80;
var maxCharsInTags = 50;
var maxCharsInText = 250;
var maxCharsInField = 50;

var itemsPerPageDefault = 25; // Default maximum number of items on one search result page
var itemsPerPageWithPreviewDefault = 10; // Default maximum number of items on one search result page when PreviewText is on

// DOM IDs
var yourSearchResultID = "yourSearchResult";
var yourSearchResultItemsID = "yourSearchResultItems";

var lastSearchText; // The last search text, as passed to findMatches

var resultElement; // The (popup) DOM element containing the search result [may be null]
var searchInputField; // The "search" input field
var searchButton; // The "search" button
var lastNewTiddlerButton;

var initStylesheet = function() {
	if (version.extensions.YourSearchPlugin.styleSheetInited) 
		return;
		
	version.extensions.YourSearchPlugin.styleSheetInited = true;
	setStylesheet(store.getTiddlerText("YourSearchStyleSheet"),"yourSearch");
}

var isResultOpen = function() {
	return resultElement != null && resultElement.parentNode == document.body;
};

var closeResult = function() {
	if (isResultOpen()) {
		document.body.removeChild(resultElement);
	}
};

// Closes the Search Result window and displays the tiddler 
// defined by the "tiddlyLink" attribute of this element
//
var closeResultAndDisplayTiddler = function(e)
{
	closeResult();
	
	var title = this.getAttribute("tiddlyLink");
	if(title) {
		var withHilite = this.getAttribute("withHilite");
		var oldHighlightHack = highlightHack;
		if (withHilite && withHilite=="true" && lastQuery) {
			highlightHack = lastQuery.getMarkRegExp();
		}
		story.displayTiddler(this,title);
		highlightHack = oldHighlightHack;
	}
	return(false);
};

// Adjusts the resultElement's size and position, relative to the search input field.
//
var adjustResultPositionAndSize = function() {
	if (!searchInputField) return;
	
	var root = searchInputField;
	
	// Position the result below the root and resize it if necessary.
	var rootLeft = findPosX(root);
	var rootTop = findPosY(root);
	var rootHeight = root.offsetHeight;
	var popupLeft = rootLeft;
	var popupTop = rootTop + rootHeight;

	// Make sure the result is not wider than the window
	var winWidth = findWindowWidth();
	if (winWidth < resultElement.offsetWidth) {
		resultElement.style.width = (winWidth - 100)+"px";
		winWidth = findWindowWidth();
	}

	// Ensure that the left and right of the result are not
	// clipped by the window. Move it to the left or right, if necessary.	
	var popupWidth = resultElement.offsetWidth;
	if(popupLeft + popupWidth > winWidth)
		popupLeft = winWidth - popupWidth-30;
	if (popupLeft < 0) popupLeft = 0;
	
	// Do the actual moving
	resultElement.style.left = popupLeft + "px";
	resultElement.style.top = popupTop + "px";
	resultElement.style.display = "block";
};

var scrollVisible = function() {
	// Scroll the window to make the result page (and the search Input field) visible.
	if (resultElement) window.scrollTo(0,ensureVisible(resultElement));
	if (searchInputField) window.scrollTo(0,ensureVisible(searchInputField));
};

// Makes sure the result page has a good size and position and visible
// (may scroll the window)
//
var	ensureResultIsDisplayedNicely = function() {
	adjustResultPositionAndSize();
	scrollVisible();
};



var indexInPage; // The index (in the current page) of the tiddler currently rendered.
var currentTiddler; // While rendering the page the tiddler that is currently rendered.

var pager = new abego.PageWiseRenderer();

var MyItemRenderer = function(parent) {
	// Load the template how to display the items that represent a found tiddler
	this.itemHtml = store.getTiddlerText("YourSearchItemTemplate");
	if (!this.itemHtml) alertAndThrow("YourSearchItemTemplate not found");
	
	// Locate the node that shall contain the list of found tiddlers
	this.place = document.getElementById(yourSearchResultItemsID);
	if(!this.place)
		this.place = createTiddlyElement(parent,"div",yourSearchResultItemsID);
};

merge(MyItemRenderer.prototype,{
	render: function(pager,object,index,indexOnPage) {
		// Define global variables, referenced by macros during applyHtmlMacros
		indexInPage = indexOnPage;
		currentTiddler = object;
		
		var item = createTiddlyElement(this.place,"div",null, "yourSearchItem");
		item.innerHTML = this.itemHtml;
		applyHtmlMacros(item,null);
		refreshElements(item,null);
	},

	endRendering: function(pager) {
		// The currentTiddler must only be defined while rendering the found tiddlers
		currentTiddler = null;
	}
});

// Refreshes the content of the result with the current search result
// of the selected page.
//
// Assumes that the result is already open. 
//
var refreshResult = function() {
	if (!resultElement || !searchInputField) return;

	// Load the template for the YourSearchResult
	var html = store.getTiddlerText("YourSearchResultTemplate");
	if (!html) html = "<b>Tiddler YourSearchResultTemplate not found</b>";
	resultElement.innerHTML = html;

	// Expand the template macros etc.
	applyHtmlMacros(resultElement,null);
	refreshElements(resultElement,null);
	
	var itemRenderer = new MyItemRenderer(resultElement);
	pager.renderPage(itemRenderer);

	ensureResultIsDisplayedNicely();
};

pager.getItemsPerPage = function() {
	var n = (config.options.chkPreviewText) 
			? abego.toInt(config.options.txtItemsPerPageWithPreview, itemsPerPageWithPreviewDefault) 
			: abego.toInt(config.options.txtItemsPerPage, itemsPerPageDefault);
	return (n > 0) ? n : 1;
};

pager.onPageChanged = function() {
	refreshResult();
};

var	reopenResultIfApplicable = function() {
	if (searchInputField == null || !config.options.chkUseYourSearch) return;
	
	if ((searchInputField.value == lastSearchText) && lastSearchText && !isResultOpen()) {
		// For speedup we check re-use the previously created resultElement, if possible.
		if (resultElement && (resultElement.parentNode != document.body)) {
			document.body.appendChild(resultElement);
			ensureResultIsDisplayedNicely();
		} else {
			abego.YourSearch.onShowResult(true);
		}
	}
};


var invalidateResult = function() {
	closeResult();
	resultElement = null;
	lastSearchText = null;
};



//-------------------------------------------------------------------------
// Close the search result page when the user clicks on the document
// (and not into the searchInputField, on the search button or in the result)
// or presses the ESC key

// Returns true if e is either self or a descendant (child, grandchild,...) of self.
//
// @param self DOM:Element
// @param e DOM:Element or null
//
var isDescendantOrSelf = function(self, e) {
	while (e != null) {
		if (self == e) return true;
		e = e.parentNode;
	}
	return false;
};

var onDocumentClick = function(e) {
	if (e.target == searchInputField) return; 
	if (e.target == searchButton) return; 
	if (resultElement && isDescendantOrSelf(resultElement, e.target)) return; 
	
	closeResult();
};

var onDocumentKeyup = function(e) {
	// Close the search result page when the user presses "ESC"
	if (e.keyCode == 27) closeResult();
};
addEvent(document,"click",onDocumentClick);
addEvent(document,"keyup",onDocumentKeyup);


// Our Search Macro Hijack Function ==========================================

// Helper
var myStorySearch = function(text,useCaseSensitive,useRegExp)
{
	lastSearchText = text;
	setLastResults(findMatches(store, text,useCaseSensitive,useRegExp,"title","excludeSearch"));

	abego.YourSearch.onShowResult();
};


var myMacroSearchHandler = function(place,macroName,params,wikifier,paramString,tiddler)
{
	initStylesheet();

	lastSearchText = "";
	var searchTimeout = null;
	var doSearch = function(txt)
		{
		if (config.options.chkUseYourSearch)
			myStorySearch(txt.value,config.options.chkCaseSensitiveSearch,config.options.chkRegExpSearch);
		else
			story.search(txt.value,config.options.chkCaseSensitiveSearch,config.options.chkRegExpSearch);
		lastSearchText = txt.value;
		};
	var clickHandler = function(e)
		{
		doSearch(searchInputField);
		return false;
		};
	var keyHandler = function(e)
		{
		if (!e) var e = window.event;
		searchInputField = this;
		switch(e.keyCode)
			{
			case 13:
				if (e.ctrlKey && lastNewTiddlerButton && isResultOpen())
					lastNewTiddlerButton.onclick.apply(lastNewTiddlerButton,[e]);
				else
					doSearch(this);
				break;
			case 27:
				// When the result is open, close it, 
				// otherwise clear the content of the input field
				if (isResultOpen()) {
					closeResult();
				} else {
					this.value = "";
					clearMessage();
				}
				break;
			}
		if (String.fromCharCode(e.keyCode) == this.accessKey || e.altKey) 
			{
			reopenResultIfApplicable();
			}

		if(this.value.length<3 && searchTimeout) clearTimeout(searchTimeout);
		if(this.value.length > 2)
			{
		 	if (this.value != lastSearchText)
		 		{
				if (!config.options.chkUseYourSearch || config.options.chkSearchAsYouType)
					{
					if(searchTimeout)
						clearTimeout(searchTimeout);
					var txt = this;
					searchTimeout = setTimeout(function() {doSearch(txt);},500);
					}
				}
			else
				{
				if(searchTimeout)
					clearTimeout(searchTimeout);
				}
			};
		if (this.value.length == 0) 
			{
			closeResult();
			}
		};


	var focusHandler = function(e)
		{
		this.select();
		clearMessage();
		reopenResultIfApplicable();
		};

	
	var args = paramString.parseParams("list",null,true);
	var buttonAtRight = getFlag(args, "buttonAtRight");
	var sizeTextbox = getParam(args, "sizeTextbox", this.sizeTextbox);
	
	var btn;
	if (!buttonAtRight)
		btn = createTiddlyButton(place,this.label,this.prompt,clickHandler);
		
	var txt = createTiddlyElement(null,"input",null,"txtOptionInput searchField",null);
	if(params[0])
		txt.value = params[0];
	txt.onkeyup = keyHandler;
	txt.onfocus = focusHandler;
	txt.setAttribute("size",sizeTextbox);
	txt.setAttribute("accessKey",this.accessKey);
	txt.setAttribute("autocomplete","off");
	if(config.browser.isSafari)
		{
		txt.setAttribute("type","search");
		txt.setAttribute("results","5");
		}
	else
		txt.setAttribute("type","text");

	if(place)
		place.appendChild(txt);

	if (buttonAtRight)
		btn = createTiddlyButton(place,this.label,this.prompt,clickHandler);

	searchInputField = txt;
	searchButton = btn;
};

//----------------------------------------------------------------------------
// Support for Macros
//----------------------------------------------------------------------------

var openAllFoundTiddlers = function() {
	closeResult();
	var results = getLastResults();
	var n = results.length;
	if (n) {
		var titles=[];
		for(var i = 0; i<n; i++)
			titles.push(results[i].title);
		story.displayTiddlers(null,titles);
	}
};

var createOptionWithRefresh = function(place, optionParams, wikifier,tiddler) {
	invokeMacro(place,"option",optionParams,wikifier,tiddler);
	// The option macro appended the component at the end of the place.
	var elem = place.lastChild;
	var oldOnClick = elem.onclick;
	elem.onclick = function(e) {
		var result = oldOnClick.apply(this, arguments);
		refreshResult();
		return result;
	};
	return elem;
};

var removeTextDecoration = function(s) {
	var removeThis = ["''", "{{{", "}}}", "//", "<<<", "/***", "***/"];
	var reText = "";
	for (var i = 0; i < removeThis.length; i++) {
		if (i != 0) reText += "|";
		reText += "("+removeThis[i].escapeRegExp()+")";
	}
	return s.replace(new RegExp(reText, "mg"), "").trim();
};



// Returns the "shortcut number" of the currentTiddler. 
// I.e. When the user presses Alt-n the given tiddler is opened/display.
//
// @return 0-9 or -1 when no number is defined
//
var getShortCutNumber = function() {
	var i = indexInPage;
	return (i >= 0 && i <= 9) 
		? (i < 9 ? (i+1) : 0)
		: -1;
};

var limitedTextRenderer = new abego.LimitedTextRenderer();
var renderLimitedText = function(place, s, maxLen) {
	limitedTextRenderer.render(place,s,maxLen,lastQuery.getMarkRegExp())
}

// When any tiddler are changed reset the result.
// 
var oldTiddlyWikiSaveTiddler = TiddlyWiki.prototype.saveTiddler;
TiddlyWiki.prototype.saveTiddler = function(title,newTitle,newBody,modifier,modified,tags,fields) {
	oldTiddlyWikiSaveTiddler.apply(this, arguments);
	invalidateResult();
};
var oldTiddlyWikiRemoveTiddler = TiddlyWiki.prototype.removeTiddler;
TiddlyWiki.prototype.removeTiddler = function(title) {
	oldTiddlyWikiRemoveTiddler.apply(this, arguments);
	invalidateResult();
};

//----------------------------------------------------------------------------
// Macros
//----------------------------------------------------------------------------

// ====Macro yourSearch ================================================

config.macros.yourSearch = {
	// Standard Properties
	label: "yourSearch",
	prompt: "Gives access to the current/last YourSearch result",
	
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		if (params.length == 0) return;
	
		var name = params[0];
		var func = config.macros.yourSearch.funcs[name];
		if (func) func(place,macroName,params,wikifier,paramString,tiddler);
	},
	
	tests: {
		"true" : function() {return true;},
		"false" : function() {return false;},
		"found" : function() {return getLastResultsCount() > 0;},
		"previewText" : function() {return config.options.chkPreviewText;}
	},

	funcs: {
		itemRange: function(place) {
			if (getLastResultsCount()) {
				var lastIndex = pager.getLastIndexOnPage();
				var s = "%0 - %1".format([pager.getFirstIndexOnPage()+1,lastIndex+1]);
				createTiddlyText(place, s);
			}
		},
		
		count: function(place) {
			createTiddlyText(place, getLastResultsCount().toString());
		},
		
		query: function(place) {
			if (lastQuery) {
				createTiddlyText(place, lastQuery.toString());
			}
		},
		
		version: function(place) {
			var t = "YourSearch %0.%1.%2".format(
					[version.extensions.YourSearchPlugin.major, 
					 version.extensions.YourSearchPlugin.minor, 
					 version.extensions.YourSearchPlugin.revision]);
			var e = createTiddlyElement(place, "a");
			e.setAttribute("href", "http://tiddlywiki.abego-software.de/#YourSearchPlugin");
			e.innerHTML = '<font color="black" face="Arial, Helvetica, sans-serif">'+t+'<font>';
		},
		
		copyright: function(place) {
			var e = createTiddlyElement(place, "a");
			e.setAttribute("href", "http://www.abego-software.de");
			e.innerHTML = '<font color="black" face="Arial, Helvetica, sans-serif">&copy; 2005-2008 <b><font color="red">abego</font></b> Software<font>';
		},
		
		newTiddlerButton: function(place) {
			if (lastQuery) {
				var r = abego.parseNewTiddlerCommandLine(lastQuery.getQueryText());
				var btn = config.macros.newTiddler.createNewTiddlerButton(place,r.title,r.params,"new tiddler","Create a new tiddler based on search text. (Shortcut: Ctrl-Enter; Separators: '.', '#')",null,"text");				
				// Close the result before the new tiddler is created.
				var oldOnClick = btn.onclick;
				btn.onclick = function() {
					closeResult();
					oldOnClick.apply(this,arguments);
				}
				lastNewTiddlerButton = btn;
			}
		},
		
		linkButton: function(place,macroName,params,wikifier,paramString,tiddler) {
			if (params < 2) return;
			
			var	tiddlyLink = params[1];
			var text = params < 3 ? tiddlyLink : params[2];
			var tooltip = params < 4 ? text : params[3];
			var accessKey = params < 5 ? null : params[4];
			
			var btn = createTiddlyButton(place,text,tooltip,closeResultAndDisplayTiddler,null,null, accessKey);
			btn.setAttribute("tiddlyLink",tiddlyLink);
		},
		
		closeButton: function(place,macroName,params,wikifier,paramString,tiddler) {
			var button = createTiddlyButton(place, "close", "Close the Search Results (Shortcut: ESC)", closeResult);
		},
		
		openAllButton: function(place,macroName,params,wikifier,paramString,tiddler) {
			var n = getLastResultsCount();
			if (n == 0) return;
		
			var title = n == 1 ? "open tiddler" : "open all %0 tiddlers".format([n]);
			var button = createTiddlyButton(place, title, "Open all found tiddlers (Shortcut: Alt-O)", openAllFoundTiddlers);
			button.setAttribute("accessKey","O");
		},
		
		naviBar: function(place,macroName,params,wikifier,paramString,tiddler) {
			pager.addPageNavigation(place);
		},
		
		"if": function(place,macroName,params,wikifier,paramString,tiddler) {
			if (params.length < 2) return;
			
			var testName = params[1];
			var negate = (testName == "not");
			if (negate) {
				if (params.length < 3) return;
				testName = params[2];
			}
			
			var test = config.macros.yourSearch.tests[testName];
			var showIt = false;
			try {
				if (test) {
					showIt = test(place,macroName,params,wikifier,paramString,tiddler) != negate;
				} else {
					// When no predefined test is specified try to evaluate it as a JavaScript expression.
					showIt = (!eval(testName)) == negate;
				}
			} catch (ex) {
			}
			
			if (!showIt) {
				place.style.display="none";
			}
		},
		
		chkPreviewText: function(place,macroName,params,wikifier,paramString,tiddler) {
			var optionParams = params.slice(1).join(" ");
			
			var elem = createOptionWithRefresh(place, "chkPreviewText", wikifier,tiddler);
			elem.setAttribute("accessKey", "P");
			elem.title = "Show text preview of found tiddlers (Shortcut: Alt-P)";	
			return elem;
		}
	}
};


// ====Macro foundTiddler ================================================

config.macros.foundTiddler = {
	// Standard Properties
	label: "foundTiddler",
	prompt: "Provides information on the tiddler currently processed on the YourSearch result page",
	
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var name = params[0];
		var func = config.macros.foundTiddler.funcs[name];
		if (func) func(place,macroName,params,wikifier,paramString,tiddler);
	},
		
	funcs: {
		title: function(place,macroName,params,wikifier,paramString,tiddler) {
			if (!currentTiddler) return;
			
			var shortcutNumber = getShortCutNumber();
			var tooltip = shortcutNumber >= 0 
					? "Open tiddler (Shortcut: Alt-%0)".format([shortcutNumber.toString()])
					: "Open tiddler";
		
			var btn = createTiddlyButton(place,null,tooltip,closeResultAndDisplayTiddler,null);
			btn.setAttribute("tiddlyLink",currentTiddler.title);
			btn.setAttribute("withHilite","true");
			
			renderLimitedText(btn, currentTiddler.title, maxCharsInTitle);
		
			if (shortcutNumber >= 0) {
				btn.setAttribute("accessKey",shortcutNumber.toString());
			}
		},
		
		tags: function(place,macroName,params,wikifier,paramString,tiddler) {
			if (!currentTiddler) return;
		
			renderLimitedText(place, currentTiddler.getTags(), maxCharsInTags);
		},
		
		text: function(place,macroName,params,wikifier,paramString,tiddler) {
			if (!currentTiddler) return;
		
			renderLimitedText(place, removeTextDecoration(currentTiddler.text), maxCharsInText);
		},
		
		field:  function(place,macroName,params,wikifier,paramString,tiddler) {
			if (!currentTiddler) return;
			var	name = params[1];
			var len = params.length > 2 ? abego.toInt(params[2],maxCharsInField) : maxCharsInField;
			var v = store.getValue(currentTiddler,name);
			if (v)
				renderLimitedText(place, removeTextDecoration(v), len);
		},
		
		// Renders the "shortcut number" of the current tiddler, to indicate to the user
		// what number to "Alt-press" to open the tiddler.
		//
		number: function(place,macroName,params,wikifier,paramString,tiddler) {
			var numberToDisplay = getShortCutNumber();
			if (numberToDisplay >= 0) {
				var text = "%0)".format([numberToDisplay.toString()]);
				createTiddlyElement(place,"span",null,"shortcutNumber",text);
			}
		}
	}
};


//----------------------------------------------------------------------------
// Configuration Stuff
//----------------------------------------------------------------------------

var opts = {chkUseYourSearch:true,
	chkPreviewText:true,
	chkSearchAsYouType:true,
	chkSearchInTitle:true,
	chkSearchInText:true,
	chkSearchInTags:true,
	chkSearchExtendedFields:true,
	txtItemsPerPage:itemsPerPageDefault,
	txtItemsPerPageWithPreview:itemsPerPageWithPreviewDefault};
for (var n in opts) 
	if (config.options[n] == undefined) config.options[n] = opts[n];



//----------------------------------------------------------------------------
// Shadow Tiddlers
//----------------------------------------------------------------------------

config.shadowTiddlers.AdvancedOptions += "\n<<option chkUseYourSearch>> Use 'Your Search' //([[more options|YourSearch Options]]) ([[help|YourSearch Help]])// ";

config.shadowTiddlers["YourSearch Help"] =
"!Field Search\nWith the Field Search you can restrict your search to certain fields of a tiddler, e.g"+
" only search the tags or only the titles. The general form is //fieldname//'':''//textToSearch// (e."+
"g. {{{title:intro}}}). In addition one-character shortcuts are also supported for the standard field"+
"s {{{title}}}, {{{text}}} and {{{tags}}}:\n|!What you want|!What you type|!Example|\n|Search ''titles "+
"only''|start word with ''!''|{{{!jonny}}} (shortcut for {{{title:jonny}}})|\n|Search ''contents/text "+
"only''|start word with ''%''|{{{%football}}} (shortcut for {{{text:football}}})|\n|Search ''tags only"+
"''|start word with ''#''|{{{#Plugin}}} (shortcut for {{{tags:Plugin}}})|\n\nUsing this feature you may"+
" also search the extended fields (\"Metadata\") introduced with TiddlyWiki 2.1, e.g. use {{{priority:1"+
"}}} to find all tiddlers with the priority field set to \"1\".\n\nYou may search a word in more than one"+
" field. E.g. {{{!#Plugin}}} (or {{{title:tags:Plugin}}} in the \"long form\") finds tiddlers containin"+
"g \"Plugin\" either in the title or in the tags (but does not look for \"Plugin\" in the text). \n\n!Boole"+
"an Search\nThe Boolean Search is useful when searching for multiple words.\n|!What you want|!What you "+
"type|!Example|\n|''All words'' must exist|List of words|{{{jonny jeremy}}} (or {{{jonny and jeremy}}}"+
")|\n|''At least one word'' must exist|Separate words by ''or''|{{{jonny or jeremy}}}|\n|A word ''must "+
"not exist''|Start word with ''-''|{{{-jonny}}} (or {{{not jonny}}})|\n\n''Note:'' When you specify two"+
" words, separated with a space, YourSearch finds all tiddlers that contain both words, but not neces"+
"sarily next to each other. If you want to find a sequence of word, e.g. '{{{John Brown}}}', you need"+
" to put the words into quotes. I.e. you type: {{{\"john brown\"}}}.\n\nUsing parenthesis you may change "+
"the default \"left to right\" evaluation of the boolean search. E.g. {{{not (jonny or jeremy)}}} finds"+
" all tiddlers that contain neither \"jonny\" nor \"jeremy. In contrast to this {{{not jonny or jeremy}}"+
"} (i.e. without parenthesis) finds all tiddlers that either don't contain \"jonny\" or that contain \"j"+
"eremy\".\n\n!'Exact Word' Search\nBy default a search result all matches that 'contain' the searched tex"+
"t. E.g. if you search for {{{Task}}} you will get all tiddlers containing 'Task', but also '~Complet"+
"edTask', '~TaskForce' etc.\n\nIf you only want to get the tiddlers that contain 'exactly the word' you"+
" need to prefix it with a '='. E.g. typing '=Task' will find the tiddlers that contain the word 'Tas"+
"k', ignoring words that just contain 'Task' as a substring.\n\n!~CaseSensitiveSearch and ~RegExpSearch"+
"\nThe standard search options ~CaseSensitiveSearch and ~RegExpSearch are fully supported by YourSearc"+
"h. However when ''~RegExpSearch'' is on Filtered and Boolean Search are disabled.\n\nIn addition you m"+
"ay do a \"regular expression\" search even with the ''~RegExpSearch'' set to false by directly enterin"+
"g the regular expression into the search field, framed with {{{/.../}}}. \n\nExample: {{{/m[ae][iy]er/"+
"}}} will find all tiddlers that contain either \"maier\", \"mayer\", \"meier\" or \"meyer\".\n\n!~JavaScript E"+
"xpression Filtering\nIf you are familiar with JavaScript programming and know some TiddlyWiki interna"+
"ls you may also use JavaScript expression for the search. Just enter a JavaScript boolean expression"+
" into the search field, framed with {{{ { ... } }}}. In the code refer to the variable tiddler and e"+
"valuate to {{{true}}} when the given tiddler should be included in the result. \n\nExample: {{{ { tidd"+
"ler.modified > new Date(\"Jul 4, 2005\")} }}} returns all tiddler modified after July 4th, 2005.\n\n!Com"+
"bined Search\nYou are free to combine the various search options. \n\n''Examples''\n|!What you type|!Res"+
"ult|\n|{{{!jonny !jeremy -%football}}}|all tiddlers with both {{{jonny}}} and {{{jeremy}}} in its tit"+
"les, but no {{{football}}} in content.|\n|{{{#=Task}}}|All tiddlers tagged with 'Task' (the exact wor"+
"d). Tags named '~CompletedTask', '~TaskForce' etc. are not considered.|\n\n!Access Keys\nYou are encour"+
"aged to use the access keys (also called \"shortcut\" keys) for the most frequently used operations. F"+
"or quick reference these shortcuts are also mentioned in the tooltip for the various buttons etc.\n\n|"+
"!Key|!Operation|\n|{{{Alt-F}}}|''The most important keystroke'': It moves the cursor to the search in"+
"put field so you can directly start typing your query. Pressing {{{Alt-F}}} will also display the pr"+
"evious search result. This way you can quickly display multiple tiddlers using \"Press {{{Alt-F}}}. S"+
"elect tiddler.\" sequences.|\n|{{{ESC}}}|Closes the [[YourSearch Result]]. When the [[YourSearch Resul"+
"t]] is already closed and the cursor is in the search input field the field's content is cleared so "+
"you start a new query.|\n|{{{Alt-1}}}, {{{Alt-2}}},... |Pressing these keys opens the first, second e"+
"tc. tiddler from the result list.|\n|{{{Alt-O}}}|Opens all found tiddlers.|\n|{{{Alt-P}}}|Toggles the "+
"'Preview Text' mode.|\n|{{{Alt-'<'}}}, {{{Alt-'>'}}}|Displays the previous or next page in the [[Your"+
"Search Result]].|\n|{{{Return}}}|When you have turned off the 'as you type' search mode pressing the "+
"{{{Return}}} key actually starts the search (as does pressing the 'search' button).|\n\n//If some of t"+
"hese shortcuts don't work for you check your browser if you have other extensions installed that alr"+
"eady \"use\" these shortcuts.//";

config.shadowTiddlers["YourSearch Options"] =
"|>|!YourSearch Options|\n|>|<<option chkUseYourSearch>> Use 'Your Search'|\n|!|<<option chkPreviewText"+
">> Show Text Preview|\n|!|<<option chkSearchAsYouType>> 'Search As You Type' Mode (No RETURN required"+
" to start search)|\n|!|Default Search Filter:<<option chkSearchInTitle>>Title ('!')     <<option chk"+
"SearchInText>>Text ('%')     <<option chkSearchInTags>>Tags ('#')    <<option chkSearchExtendedFiel"+
"ds>>Extended Fields<html><br><font size=\"-2\">The fields of a tiddlers that are searched when you don"+
"'t explicitly specify a filter in the search text <br>(Explictly specify fields using one or more '!"+
"', '%', '#' or 'fieldname:' prefix before the word/text to find).</font></html>|\n|!|Number of items "+
"on search result page: <<option txtItemsPerPage>>|\n|!|Number of items on search result page with pre"+
"view text: <<option txtItemsPerPageWithPreview>>|\n";
			
config.shadowTiddlers["YourSearchStyleSheet"] = 
"/***\n!~YourSearchResult Stylesheet\n***/\n/*{{{*/\n.yourSearchResult {\n\tposition: absolute;\n\twidth: 800"+
"px;\n\n\tpadding: 0.2em;\n\tlist-style: none;\n\tmargin: 0;\n\n\tbackground: #ffd;\n\tborder: 1px solid DarkGra"+
"y;\n}\n\n/*}}}*/\n/***\n!!Summary Section\n***/\n/*{{{*/\n.yourSearchResult .summary {\n\tborder-bottom-width:"+
" thin;\n\tborder-bottom-style: solid;\n\tborder-bottom-color: #999999;\n\tpadding-bottom: 4px;\n}\n\n.yourSea"+
"rchRange, .yourSearchCount, .yourSearchQuery   {\n\tfont-weight: bold;\n}\n\n.yourSearchResult .summary ."+
"button {\n\tfont-size: 10px;\n\n\tpadding-left: 0.3em;\n\tpadding-right: 0.3em;\n}\n\n.yourSearchResult .summa"+
"ry .chkBoxLabel {\n\tfont-size: 10px;\n\n\tpadding-right: 0.3em;\n}\n\n/*}}}*/\n/***\n!!Items Area\n***/\n/*{{{*"+
"/\n.yourSearchResult .marked {\n\tbackground: none;\n\tfont-weight: bold;\n}\n\n.yourSearchItem {\n\tmargin-to"+
"p: 2px;\n}\n\n.yourSearchNumber {\n\tcolor: #808080;\n}\n\n\n.yourSearchTags {\n\tcolor: #008000;\n}\n\n.yourSearc"+
"hText {\n\tcolor: #808080;\n\tmargin-bottom: 6px;\n}\n\n/*}}}*/\n/***\n!!Footer\n***/\n/*{{{*/\n.yourSearchFoote"+
"r {\n\tmargin-top: 8px;\n\tborder-top-width: thin;\n\tborder-top-style: solid;\n\tborder-top-color: #999999;"+
"\n}\n\n.yourSearchFooter a:hover{\n\tbackground: none;\n\tcolor: none;\n}\n/*}}}*/\n/***\n!!Navigation Bar\n***/"+
"\n/*{{{*/\n.yourSearchNaviBar a {\n\tfont-size: 16px;\n\tmargin-left: 4px;\n\tmargin-right: 4px;\n\tcolor: bla"+
"ck;\n\ttext-decoration: underline;\n}\n\n.yourSearchNaviBar a:hover {\n\tbackground-color: none;\n}\n\n.yourSe"+
"archNaviBar .prev {\n\tfont-weight: bold;\n\tcolor: blue;\n}\n\n.yourSearchNaviBar .currentPage {\n\tcolor: #"+
"FF0000;\n\tfont-weight: bold;\n\ttext-decoration: none;\n}\n\n.yourSearchNaviBar .next {\n\tfont-weight: bold"+
";\n\tcolor: blue;\n}\n/*}}}*/\n";

config.shadowTiddlers["YourSearchResultTemplate"] =
"<!--\n{{{\n-->\n<span macro=\"yourSearch if found\">\n<!-- The Summary Header ============================"+
"================ -->\n<table class=\"summary\" border=\"0\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\">"+
"<tbody>\n  <tr>\n\t<td align=\"left\">\n\t\tYourSearch Result <span class=\"yourSearchRange\" macro=\"yourSearc"+
"h itemRange\"></span>\n\t\t&nbsp;of&nbsp;<span class=\"yourSearchCount\" macro=\"yourSearch count\"></span>\n"+
"\t\tfor&nbsp;<span class=\"yourSearchQuery\" macro=\"yourSearch query\"></span>\n\t</td>\n\t<td class=\"yourSea"+
"rchButtons\" align=\"right\">\n\t\t<span macro=\"yourSearch chkPreviewText\"></span><span class=\"chkBoxLabel"+
"\">preview text</span>\n\t\t<span macro=\"yourSearch newTiddlerButton\"></span>\n\t\t<span macro=\"yourSearch openAllButton\"></span>\n\t\t<span macro=\"yourSearch lin"+
"kButton 'YourSearch Options' options 'Configure YourSearch'\"></span>\n\t\t<span macro=\"yourSearch linkB"+
"utton 'YourSearch Help' help 'Get help how to use YourSearch'\"></span>\n\t\t<span macro=\"yourSearch clo"+
"seButton\"></span>\n\t</td>\n  </tr>\n</tbody></table>\n\n<!-- The List of Found Tiddlers ================="+
"=========================== -->\n<div id=\"yourSearchResultItems\" itemsPerPage=\"25\" itemsPerPageWithPr"+
"eview=\"10\"></div>\n\n<!-- The Footer (with the Navigation) ==========================================="+
"= -->\n<table class=\"yourSearchFooter\" border=\"0\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\"><tbody"+
">\n  <tr>\n\t<td align=\"left\">\n\t\tResult page: <span class=\"yourSearchNaviBar\" macro=\"yourSearch naviBar"+
"\"></span>\n\t</td>\n\t<td align=\"right\"><span macro=\"yourSearch version\"></span>, <span macro=\"yourSearc"+
"h copyright\"></span>\n\t</td>\n  </tr>\n</tbody></table>\n<!-- end of the 'tiddlers found' case ========="+
"================================== -->\n</span>\n\n\n<!-- The \"No tiddlers found\" case ================="+
"========================== -->\n<span macro=\"yourSearch if not found\">\n<table class=\"summary\" border="+
"\"0\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\"><tbody>\n  <tr>\n\t<td align=\"left\">\n\t\tYourSearch Resu"+
"lt: No tiddlers found for <span class=\"yourSearchQuery\" macro=\"yourSearch query\"></span>.\n\t</td>\n\t<t"+
"d class=\"yourSearchButtons\" align=\"right\">\n\t\t<span macro=\"yourSearch newTiddlerButton\"></span>\n\t\t<span macro=\"yourSearch linkButton 'YourSearch Options'"+
" options 'Configure YourSearch'\"></span>\n\t\t<span macro=\"yourSearch linkButton 'YourSearch Help' help"+
" 'Get help how to use YourSearch'\"></span>\n\t\t<span macro=\"yourSearch closeButton\"></span>\n\t</td>\n  <"+
"/tr>\n</tbody></table>\n</span>\n\n\n<!--\n}}}\n-->\n";

config.shadowTiddlers["YourSearchItemTemplate"] = 
"<!--\n{{{\n-->\n<span class='yourSearchNumber' macro='foundTiddler number'></span>\n<span class='yourSea"+
"rchTitle' macro='foundTiddler title'/></span>&nbsp;-&nbsp;\n<span class='yourSearchTags' macro='found"+
"Tiddler field tags 50'/></span>\n<span macro=\"yourSearch if previewText\"><div class='yourSearchText' macro='fo"+
"undTiddler field text 250'/></div></span>\n<!--\n}}}\n-->";

config.shadowTiddlers["YourSearch"] = "<<tiddler [[YourSearch Help]]>>";

config.shadowTiddlers["YourSearch Result"] = "The popup-like window displaying the result of a YourSearch query.";

//----------------------------------------------------------------------------
// Install YourSearch
//----------------------------------------------------------------------------

// Overwrite the TiddlyWiki search handler and verify after a while 
// that nobody else has overwritten it.
config.macros.search.handler = myMacroSearchHandler;

var checkForOtherHijacker = function() {
	// Check that still our search handler is installed
    if (config.macros.search.handler != myMacroSearchHandler) {
    	alert(
"Message from YourSearchPlugin:\n\n\nAnother plugin has disabled the 'Your Search' features.\n\n\nYou may "+
"disable the other plugin or change the load order of \nthe plugins (by changing the names of the tidd"+
"lers)\nto enable the 'Your Search' features.");
    }
};

setTimeout(checkForOtherHijacker, 5000);

// === Public API =================================

abego.YourSearch.getStandardRankFunction = function() {
	return standardRankFunction;
};

abego.YourSearch.getRankFunction = function() {
	return abego.YourSearch.getStandardRankFunction();
};

abego.YourSearch.getCurrentTiddler = function() {
	return currentTiddler;
};

abego.YourSearch.closeResult = function() {
	closeResult();
};

// Returns an array of tiddlers that matched the last search
abego.YourSearch.getFoundTiddlers = function() {
	return lastResults;
};

// The last Search query (TiddlerQuery), or null
abego.YourSearch.getQuery = function() {
	return lastQuery;
};

abego.YourSearch.onShowResult = function(useOldResult) {
	highlightHack = lastQuery ? lastQuery.getMarkRegExp() : null;
	if (!useOldResult)
		pager.setItems(getLastResults());
	if (!resultElement) {
		resultElement = createTiddlyElement(document.body,"div",yourSearchResultID,"yourSearchResult");
	} else if (resultElement.parentNode != document.body) {
		document.body.appendChild(resultElement);
	}
	refreshResult();
	highlightHack = null;
};

})();
} // of "install only once"
// Used Globals (for JSLint) ==============

// ... JavaScript Core
/*global 	alert,clearTimeout,confirm */
// ... TiddlyWiki Core
/*global 	Tiddler, applyHtmlMacros, clearMessage, createTiddlyElement, createTiddlyButton, createTiddlyText, ensureVisible ,findPosX, highlightHack, findPosY,findWindowWidth, invokeMacro, saveChanges, refreshElements, story */
//}}}
/***
!Licence and Copyright
Copyright (c) abego Software ~GmbH, 2005-2010 ([[www.abego-software.de|http://www.abego-software.de]])

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.

Neither the name of abego Software nor the names of its contributors may be
used to endorse or promote products derived from this software without specific
prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
***/