Welcome to TiddlyWiki created by Jeremy Ruston, Copyright © 2007 UnaMesa Association
Ancient Domains of Mystery is a freeware, roguelike game, it's a classic one.
It takes place in the Drakalor Chain on the planet Ancardia. A Chaos Gate has been opened by Andor Drakon, the ElDeR cHaOs GoD. It was first discovered by the sage Khelavaster, who tried to close it but disappeared. Now Chaos beasts are roaming Ancardia. You are one of the many hero(ine)s who seeks to defeat Chaos and restore peace to the world.
The easiest way to defeat Chaos is to close the gate. However, a holy champion of order or balance, if equipped with certain unique artifacts, may instead enter it, slay Andor Drakon, become a demigod and keep Ancardia safe from Chaos for evermore. Those who have turned to the dark side may also slay Andor Drakon in hopes of becoming a more powerful Chaos God - perhaps even an Ultimate Chaos God.
alter table TB add foreign key (TB1_COLUMN) reference TB2 (TB2_COLUMN);
Для TB1_COLUMN должен быть создан индекс.
TB1_COLUMN и TB2_COLUMN должны быть одного типа (int(10) != int(11))
alter table t1 add index (column1), add index (column2);
*http://wiki.agiledev.ru/doku.php - {{{AgileDev}}} - это проект, посвященный описанию методик создания качественного программного обеспечения. Последние изменения: 2010/09/15 16:43
Объект XMLHttpRequest дает возможность браузеру делать HTTP-запросы к серверу без перезагрузки страницы.
Несмотря на слово XML в названии, XMLHttpRequest может работать с данными в любом текстовом формате, и даже c бинарными данными.
Различают два использования XmlHttpRequest: синхронное и асинхронное.
При синхронном запросе браузер "подвисает" и ждет на строчке 3, пока сервер не ответит на запрос.
При асинхронном запросе браузер не ждет выполнения запроса для продолжения скрипта, т.е. функция send() не останавливает выполнение скрипта, а просто отправляет запрос.
To open terminal hit Alt+Ctrl+T and run following commands: sudo apt-get install compizconfig-settings-manager. Or search for compizconfig-settings-manager in Software Center and install from there. Then go to system tools > preferences > compizconfig
Go at the very bottom where it says windows management
Put a checkmark in application switcher
That should fix it.
!!version 1.3
*[[directives|http://httpd.apache.org/docs/1.3/mod/directives.html]]
Ctrl-Q (V on Linux), then move, then press : and enter s/pattern/newtext/
http://vim.wikia.com/wiki/VimTip63
не глобальная замена
no global substitution
replace
http://stackoverflow.com/questions/1711/what-is-the-single-most-influential-book-every-programmer-should-read
Structure and Interpretation of Computer Programs, second edition:
http://mitpress.mit.edu/sicp/full-text/book/book.html
The Art of Unix Programming, 2003 Eric S. Raymond
http://www.faqs.org/docs/artu/
The mechanism for recognizing multiple requests from the same browser is called a session. A session recognizes requests from the same browser. A session also supports the maintaining of a Web application state among multiple Web interactions within the same browser instance and with the Web server. The Web server does not recognize whether multiple requests originate from the same browser or not because the HTTP protocol is stateless.
Conceptually, a session can be thought of as an invisible "container" maintained by the WebSphere Application Server. It keeps track of the specific browser instance that communicates with the Web server. A separate session exists for every separate browser instance communicating to the Web server.
Information generated during a series of Web interactions can be placed into the session. This information can be retrieved for use in other parts of the Web application. The information stored is private to your browser instance and cannot be accessed by other browser instances. You can consider the session as a place to store your global information, or variables.
*[[Dude, where's my business logic?|http://www.codeproject.com/KB/architecture/DudeWheresMyBusinessLogic.aspx]]
*[[A Working Definition of Business Logic, with Implications for CRUD Code|http://database-programmer.blogspot.com/2010/12/working-definition-of-business-logic.html]]
*[[What exactly consists of 'Business Logic' in an application?|http://stackoverflow.com/questions/39288/what-exactly-consists-of-business-logic-in-an-application]]
*[[Fowler: Domain Logic and SQL|http://martinfowler.com/articles/dblogic.html]]
*[[RSDN:Ах эта бизнес-логика!|http://www.rsdn.ru/forum/design/468244.flat.aspx#468244]]
*[[Вносить ли бизнес-логику в модель предметной области?|http://www.rsdn.ru/forum/design/4091491.flat.aspx#4091491]]
*[[Careers 2.0 matches great programmers on Stack Overflow with great jobs|http://careers.stackoverflow.com]]
You can change your password from your control panel.
Get to your control panel using a URL like this:
http://your-site-name.tiddlyspot.com/controlpanel/
http://faq.tiddlyspot.com/
|Character |Description |Example|h
|[ |Starts a character class. A character class matches a single character out of all the possibilities offered by the character class. Inside a character class, different rules apply. The rules in this section are only valid inside character classes. The rules outside this section are not valid in character classes, except for a few character escapes that are indicated with "can be used inside character classes".| |
|Any character except ^-]\ add that character to the possible matches for the character class. |All characters except the listed special characters. |[abc] matches a, b or c|
|\ (backslash) followed by any of ^-]\ |A backslash escapes special characters to suppress their special meaning. |[\^\]] matches ^ or ]|
|- (hyphen) except immediately after the opening [ Specifies a range of characters. (Specifies a hyphen if placed immediately after the opening [) [a-zA-Z0-9] matches any letter or digit|
|^ (caret) immediately after the opening [ |Negates the character class, causing it to match a single character not listed in the character class. (Specifies a caret if placed anywhere except after the opening [) |[^a-d] matches x (any character except a, b, c or d)|
|\d, \w and \s |Shorthand character classes matching digits, word characters (letters, digits, and underscores), and whitespace (spaces, tabs, and line breaks). Can be used inside and outside character classes. |[\d\s] matches a character that is a digit or whitespace|
|\D, \W and \S |Negated versions of the above. Should be used only outside character classes. (Can be used inside, but that is confusing.) |\D matches a character that is not a digit|
|[\b] |Inside a character class, \b is a backspace character. |[\b\t] matches a backspace or tab character|
/***
|Name:|CloseOnCancelPlugin|
|Description:|Closes the tiddler if you click new tiddler then cancel. Default behaviour is to leave it open|
|Version:|3.0.1 ($Rev: 3861 $)|
|Date:|$Date: 2008-03-08 10:53:09 +1000 (Sat, 08 Mar 2008) $|
|Source:|http://mptw.tiddlyspot.com/#CloseOnCancelPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
***/
//{{{
merge(config.commands.cancelTiddler,{
handler_mptw_orig_closeUnsaved: config.commands.cancelTiddler.handler,
handler: function(event,src,title) {
this.handler_mptw_orig_closeUnsaved(event,src,title);
if (!story.isDirty(title) && !store.tiddlerExists(title) && !store.isShadowTiddler(title))
story.closeTiddler(title,true);
return false;
}
});
//}}}
* Tar directory
<code class="brush:">
tar cfzv magick_arrays.tgz magick_arrays
</code>
* Extract directory
<code class="brush:">
tar xfzv magick_arrays.tgz magick_arrays
</code>
/*
TiddlyWiki Comments Plugin - Online demo at http://tiddlyguv.org/CommentsPlugin.html
TODO:
- Support Cascade comment delete when the top-level tiddler is deleted
- Support more than one < <comments> > per tiddler. This will probably entail creating an invisible root tiddler to
hold all the comments for a macro together. The user will need to provide an ID for this tiddler.
- Don't use global "macro" var (use "macro" param a la jquery)
- Sort by tiddler title or duration
*/
/***
|Name|CommentsPlugin|
|Description|Macro for nested comments, where each comment is a separate tiddler.|
|Source|http://tiddlyguv.org/CommentsPlugin.html#CommentsPlugin|
|Documentation|http://tiddlyguv.org/CommentsPlugin.html#CommentsPluginInfo|
|Version|0.1|
|Author|Michael Mahemoff, Osmosoft|
|''License:''|[[BSD open source license]]|
|~CoreVersion|2.2|
***/
/*{{{*/
if(!version.extensions.CommentsPlugin) {
version.extensions.CommentsPlugin = {installed:true};
(function(plugin) {
var cmacro = config.macros.comments = {
init: function() {
var stylesheet = store.getTiddlerText(tiddler.title + "##StyleSheet");
if (stylesheet) { // check necessary because it happens more than once for some reason
config.shadowTiddlers["StyleSheetCommentsPlugin"] = stylesheet;
store.addNotification("StyleSheetCommentsPlugin", refreshStyles);
}
if (!version.extensions.CommentsPlugin.retainViewTemplate) cmacro.enhanceViewTemplate();
},
enhanceViewTemplate: function() {
var template = config.shadowTiddlers.ViewTemplate;
if ((/commentBreadcrumb/g).test(template)) return; // already enhanced
var TITLE_DIV = "<div class='title' macro='view title'></div>";
var commentsDiv = "<div class='commentBreadcrumb' macro='commentBreadcrumb'></div>";
config.shadowTiddlers.ViewTemplate = template.replace(TITLE_DIV,commentsDiv+"\n"+TITLE_DIV);
},
handler: function(place,macroName,params,wikifier,paramString,tiddler) {
var macroParams = paramString.parseParams();
var tiddlerParam = getParam(macroParams, "tiddler");
tiddler = tiddlerParam ? store.getTiddler(tiddlerParam) : tiddler;
if (!tiddler || !store.getTiddler(tiddler.title)) return;
cmacro.buildCommentsArea(tiddler, place, macroParams);
// cmacro.refreshCommentsFromRoot(story.getTiddler(tiddler.title).commentsEl, tiddler, macroParams);
cmacro.refreshCommentsFromRoot(place.commentsEl, tiddler, macroParams);
},
buildCommentsArea: function(rootTiddler, place, macroParams) {
var commentsArea = createTiddlyElement(place, "div", null, "comments");
var heading = getParam(macroParams, "heading");
if (heading) createTiddlyElement(commentsArea, "h1", null, null, heading);
var comments = createTiddlyElement(commentsArea, "div", null, "");
place.commentsEl = comments;
if (cmacro.editable(macroParams)) {
var newCommentArea = createTiddlyElement(commentsArea, "div", null, "newCommentArea", "New comment:");
cmacro.forceLoginIfRequired(params, newCommentArea, function() {
var newCommentEl = cmacro.makeTextArea(newCommentArea, macroParams);
// var addComment = createTiddlyElement(newCommentArea, "button", null, "addComment button", "Add Comment");
var addComment = createTiddlyButton(newCommentArea, "Add Comment", null, function() {
var comment = cmacro.createComment(newCommentEl.value, rootTiddler, macroParams);
newCommentEl.value = "";
cmacro.refreshCommentsFromRoot(comments, rootTiddler, macroParams);
}, "addComment button");
});
}
},
makeTextArea: function(container, macroParams) {
var textArea = createTiddlyElement(container, "textarea");
textArea.rows = getParam(macroParams, "textRows") || 4;
textArea.cols = getParam(macroParams, "textCols") || 20;
textArea.value = getParam(macroParams, "text") || "";
return textArea;
},
refreshCommentsFromRoot: function(rootCommentsEl, rootTiddler, macroParams) {
cmacro.treeifyComments(rootTiddler);
cmacro.refreshComments(rootCommentsEl, rootTiddler, macroParams);
},
refreshComments: function(daddyCommentsEl, tiddler, macroParams) {
var commentsEl;
if (tiddler.fields.daddy) {
var commentEl = cmacro.buildCommentEl(daddyCommentsEl, tiddler, macroParams);
daddyCommentsEl.appendChild(commentEl);
commentsEl = commentEl.commentsEl;
} else { // root element
removeChildren(daddyCommentsEl);
// refreshedEl = story.getTiddler(tiddler.title);
commentsEl = daddyCommentsEl;
}
for (var child = tiddler.firstChild; child; child = child.next) {
cmacro.refreshComments(commentsEl, child, macroParams);
}
},
// This has become more complex due to "confused comments" - multiple comments
// pointing back to the same daddy (which implies they all think they're the first
// child) or a single "2nd-last" sibling (which implies they all think they're the
// last sibling). This happens in the typical "atomic transaction 101" scenario -
// user A opens wiki, user B opens wiki, one of the users submits a comment,
// the other user submits a comment.
//
// Normally, each comment says "make my daddy's first child be me", or "make my prev
// sibling's next sibling be me". That's how the tree gets built. But to deal
// with confused comments, we now have to check if daddy/prev is already pointing
// to something. If so, we will have to walk through the list to find the right place
// for the new item.
//
// We begin by sorting by date; if we can assume we are walking through the comments by date,
// the confused comments will appear in the right order.
treeifyComments: function(rootTiddler) {
// First, clear the tree data
// We sort the comments to ensure "confused" comments
var comments = cmacro.findCommentsFromRoot(rootTiddler).sort(function(a,b) {
return a.modified > b.modified;
});
var nodes=comments.concat(rootTiddler);
for (var i=0; i<nodes.length; i++) {
delete nodes[i]["firstChild"];
delete nodes[i]["next"];
}
// Now walk through each comment
cmacro.forEach(comments, function(comment) {
var prev = comment.fields.prev;
var daddy = comment.fields.daddy;
if (prev) {
var prevTiddler = store.getTiddler(prev);
if (prevTiddler.next) {
for (var lastChild=prevTiddler.next; lastChild.next; lastChild=lastChild.next)
;
lastChild.next = comment;
// } else {
} else {
prevTiddler.next = comment;
}
} else {
var daddyTiddler = store.getTiddler(daddy);
if (daddyTiddler.firstChild) {
for (var lastChild=daddyTiddler.firstChild; lastChild.next; lastChild=lastChild.next)
;
lastChild.next = comment;
} else {
daddyTiddler.firstChild = comment;
}
}
});
for (var i=0; i<comments.length; i++) {
var c=comments.sort()[i];
}
},
logComments: function(comments) {
for (var i=0; i<comments.length; i++) {
var comment = comments[i];
}
},
findCommentsFromRoot: function(rootTiddler) {
var comments = [];
store.forEachTiddler(function(title,tiddler) {
if (tiddler.fields.root==rootTiddler.title) comments.push(tiddler);
});
return comments;
},
findChildren: function(daddyTiddler) {
var comments = [];
store.forEachTiddler(function(title,tiddler) {
if (tiddler.fields.daddy==daddyTiddler.title) comments.push(tiddler);
});
return comments;
},
buildCommentEl: function(daddyCommentsEl, comment, macroParams) {
// COMMENT ELEMENT
var commentEl = document.createElement("div");
commentEl.className = "comment";
// HEADING <- METAINFO AND DELETE
var headingEl = createTiddlyElement(commentEl, "div", null, "heading");
var metaInfoEl = createTiddlyElement(headingEl, "div", null, "commentTitle", comment.modifier + '@' + comment.modified.formatString(getParam(macroParams,"dateFormat") || "DDD, MMM DDth, YYYY hh12:0mm:0ss am"));
metaInfoEl.onclick = function() {
// story.closeAllTiddlers();
story.displayTiddler("top", comment.title, null, true);
// document.location.hash = "#" + comment.title;
};
var deleteEl = createTiddlyElement(headingEl, "div", null, "deleteComment", "X");
deleteEl.onclick = function() {
if (true || confirm("Delete this comment and all of its replies?")) {
cmacro.deleteTiddlerAndDescendents(comment);
commentEl.parentNode.removeChild(commentEl);
}
};
// TEXT
commentEl.text = createTiddlyElement(commentEl, "div", null, "commentText");
wikify(comment.text, commentEl.text);
// REPLY LINK
if (cmacro.editable(macroParams)) {
var replyLinkZone = createTiddlyElement(commentEl, "div", null, "replyLinkZone");
var replyLink = createTiddlyElement(replyLinkZone, "span", null, "replyLink", "reply to this comment");
replyLink.onclick = function() { cmacro.openReplyLink(comment, commentEl, replyLink, macroParams); };
}
// var clearance = createTiddlyElement(commentEl, "clearance", null, "clearance");
// clearance.innerHTML = " ";
// COMMENTS AREA
commentEl.commentsEl = createTiddlyElement(commentEl, "div", null, "comments");
// RETURN
return commentEl;
},
openReplyLink: function(commentTiddler, commentEl, replyLink, macroParams) {
if (commentEl.replyEl) {
commentEl.replyEl.style.display = "block";
return;
}
commentEl.replyEl = document.createElement("div");
commentEl.replyEl.className = "reply";
replyLink.style.display = "none";
var newReplyHeading = createTiddlyElement(commentEl.replyEl, "div", null, "newReply");
createTiddlyElement(newReplyHeading, "div", null, "newReplyLabel", "New Reply:");
var closeNewReply = createTiddlyElement(newReplyHeading, "div", null, "closeNewReply", "close");
closeNewReply.onclick = function() {
commentEl.replyEl.style.display = "none";
replyLink.style.display = "block";
};
cmacro.forceLoginIfRequired(params, commentEl.replyEl, function() {
var replyText = cmacro.makeTextArea(commentEl.replyEl, macroParams);
var submitReply = createTiddlyButton(commentEl.replyEl, "Reply", null, function() {
var newComment = cmacro.createComment(replyText.value, commentTiddler, macroParams);
replyText.value = "";
closeNewReply.onclick();
cmacro.refreshComments(commentEl.commentsEl, newComment, macroParams);
});
});
commentEl.insertBefore(commentEl.replyEl, commentEl.commentsEl);
},
createComment: function(text, daddy, macroParams) {
var rootTitle = daddy.fields.root ? daddy.fields.root : daddy.title;
// second case is the situation where daddy *is* root
var newComment = cmacro.createCommentTiddler(macroParams, rootTitle);
var fieldsParam = getParam(macroParams, "fields") || "";
var fields = fieldsParam.decodeHashMap();
var inheritedFields = (getParam(macroParams, "inheritedFields") || "").split(",");
cmacro.forEach(inheritedFields, function(field) {
if (field!="") fields[field] = daddy.fields[field];
});
var tagsParam = getParam(macroParams, "tags") || "comment";
var now = new Date();
newComment.set(null, text, config.options.txtUserName, now, tagsParam.split(","), now, fields);
var youngestSibling = cmacro.findYoungestChild(daddy)
if (youngestSibling) newComment.fields.prev = youngestSibling.title;
newComment.fields.daddy = daddy.title;
newComment.fields.root = rootTitle;
cmacro.saveTiddler(newComment.title);
autoSaveChanges(false);
return newComment;
},
findYoungestChild: function(daddy) {
var siblingCount = 0;
var elderSiblings = cmacro.mapize(cmacro.selectTiddlers(function(tiddler) {
isChild = (tiddler.fields.daddy==daddy.title);
if (isChild) siblingCount++;
return isChild;
}));
if (!siblingCount) return null;
// Find the only sibling that doesn't have a prev pointing at it
var youngestSiblings = cmacro.clone(elderSiblings) // as a starting point
cmacro.forEachMap(elderSiblings, function(tiddler) {
delete youngestSiblings[tiddler.fields.prev];
});
for (title in youngestSiblings) { return youngestSiblings[title]; }
},
// The recursive delete is run by a separate function (nested inside
// this one, for encapsulation purposes).
deleteTiddlerAndDescendents: function(tiddler) {
function deleteRecursively(tiddler) {
for (var child = tiddler.firstChild; child; child = child.next) {
deleteRecursively(child);
}
store.removeTiddler(tiddler.title);
}
cmacro.treeifyComments(store.getTiddler(tiddler.fields.root));
// save some info prior to deleting
var prev = tiddler.fields.prev;
var next = tiddler.next;
deleteRecursively(tiddler);
// used saved info
if (next) {
next.fields.prev = prev;
cmacro.saveTiddler(next.title);
}
autoSaveChanges(false);
},
forEach: function(list, visitor) { for (var i=0; i<list.length; i++) visitor(list[i]); },
forEachMap: function(map, visitor) { for (var key in map) visitor(map[key]); },
select: function(list, selector) {
var selection = [];
cmacro.forEach(list, function(currentItem) {
if (selector(currentItem)) { selection.push(currentItem); }
});
return selection;
},
selectTiddlers: function(selector) {
var tiddlers = [];
store.forEachTiddler(function(title, tiddler) {
var wanted = selector(tiddler);
if (wanted) tiddlers.push(tiddler);
});
return tiddlers;
},
map: function(list, mapper) {
var mapped = [];
cmacro.forEach(list, function(currentItem) { mapped.push(mapper(currentItem)); });
return mapped;
},
remove: function(list, unwantedItem) {
return cmacro.select(list,
function(currentItem) { return currentItem!=unwantedItem; });
},
mapize: function(tiddlerList) {
var map = {};
cmacro.forEach(tiddlerList, function(tiddler) { map[tiddler.title] = tiddler; });
return map;
},
clone: function(map) { return merge({}, map); },
editable: function(params) {
var editable = getParam(params, "editable");
return (!editable || editable!="false");
},
needsLogin: function(params) {
var loginCheck = getParam(params, "loginCheck");
return loginCheck && !window[loginCheck]();
},
forceLoginIfRequired: function(params, loginPromptContainer, authenticatedBlock) {
if (cmacro.needsLogin(params)) wikify("<<"+getParam(macroParams, "loginPrompt")+">>", loginPromptContainer);
else authenticatedBlock();
},
mergeReadOnly: function(first, second) {
var merged = {};
for (var field in first) { merged[field] = first[field]; }
for (var field in second) { merged[field] = second[field]; }
return merged;
},
// callers may replace this with their own ID generation algorithm
createCommentTiddler: function(macroParams, rootTitle) {
// var titleFormat = getParam(macroParams, "titleFormat") || "%root%Comment";
var prefix = rootTitle+"Comment"; // was "_comment"
if (!store.createGuidTiddler) return store.createTiddler(prefix+((new Date()).getTime()));
return store.createGuidTiddler(prefix);
},
saveTiddler: function(tiddler) {
var tiddler = (typeof(tiddler)=="string") ? store.getTiddler(tiddler) : tiddler;
store.saveTiddler(tiddler.title, tiddler.title, tiddler.text, tiddler.modifier, tiddler.modified, tiddler.tags, cmacro.mergeReadOnly(config.defaultCustomFields, tiddler.fields), false, tiddler.created)
},
log: function() { if (console && console.firebug) console.log.apply(console, arguments); },
assert: function() { if (console && console.firebug) console.assert.apply(console, arguments); },
copyFields: function(fromTiddler, toTiddler, field1, field2, fieldN) {
for (var i=2; i<arguments.length; i++) {
fieldKey = arguments[i];
if (fromTiddler.fields[fieldKey]) toTiddler.fields[fieldKey] = fromTiddler.fields[fieldKey];
}
}
}
config.macros.commentsCount = {
handler: function(place,macroName,params,wikifier,paramString,tiddler) {
var count = 0;
if (tiddler && store.getTiddler(tiddler.title)) {
var rootTiddler = paramString.length ? paramString : tiddler.title;
count = config.macros.comments.findCommentsFromRoot(store.getTiddler(rootTiddler)).length;
}
createTiddlyText(place, count);
}
},
config.macros.commentBreadcrumb = {
handler: function(place,macroName,params,wikifier,paramString,tiddler) {
if (!tiddler.fields.root) return;
var rootLink = createTiddlyElement(place, "span", null, null);
createTiddlyLink(rootLink, tiddler.fields.root, true);
var rootIsParent = tiddler.fields.daddy==tiddler.fields.root;
var rootIsGrandparent = (store.getTiddler(tiddler.fields.daddy)).fields.daddy==tiddler.fields.root;
if (!rootIsParent) {
if (!rootIsGrandparent) createTiddlyElement(place, "span", null, null, " > ... ");
createTiddlyElement(place, "span", null, null, " > ");
var daddyLink = createTiddlyElement(place, "span", null, null);
createTiddlyLink(daddyLink, tiddler.fields.daddy, true);
}
createTiddlyElement(place, "span", null, null, " > ");
// place.appendChild(createTiddlyLink(tiddler.fields.root));
}
}
config.macros.tiddlyWebComments = {};
config.macros.tiddlyWebComments.handler =
function(place,macroName,params,wikifier,paramString,tiddler) {
paramString = "fields:'server.workspace:bags/comments' inheritedFields:'server.host,server.type'";
config.macros.comments.handler(place,macroName,params,wikifier, paramString,tiddler);
};
function log() { if (console && console.firebug) console.log.apply(console, arguments); }
})(version.extensions.CommentsPlugin);
/***
!StyleSheet
.comments h1 { margin-bottom: 0; padding-bottom: 0; }
.comments { padding: 0; }
.comment .comments { margin-left: 1em; }
.comment { padding: 0; margin: 1em 0 0; }
.comment .comment { margin 0; }
.comment .toolbar .button { border: 0; color: #9a4; }
.comment .heading { background: [[ColorPalette::PrimaryPale]]; color: [[ColorPalette::PrimaryDark]]; border-bottom: 1px solid [[ColorPalette::PrimaryLight]]; border-right: 1px solid [[ColorPalette::PrimaryLight]]; padding: 0.5em; height: 1.3em; }
.commentTitle { float: left; }
.commentTitle:hover { text-decoration: underline; cursor: pointer; }
.commentText { clear: both; padding: 1em 1em; }
.deleteComment { float: right; cursor: pointer; text-decoration:underline; color:[[ColorPalette::SecondaryDark]]; padding-right: 0.3em; }
.comment .reply { margin-left: 1em; }
.comment .replyLink { color:[[ColorPalette::SecondaryDark]]; font-style: italic;
cursor: pointer; text-decoration: underline; margin: 0 1em; }
.comment .created { }
.comment .newReply { color:[[ColorPalette::SecondaryDark]]; margin-top: 1em; }
.newReplyLabel { float: left; }
.closeNewReply { cursor: pointer; float: right; text-decoration: underline; }
.comments textarea { width: 100%; padding: 0.3em; margin-bottom: 0.6em; }
.newCommentArea { margin-top: 0.5em; }
.clearance { clear: both; }
!(end of StyleSheet)
***/
config.macros.comments.init();
} // end of 'install only once'
/*}}}*/
// function log() { if (console && console.firebug) console.log.apply(console, arguments); }
Laravel Mix Version: 4.1.2
I solved this incident by doing the following:
npm uninstall sass-loader
npm install sass-loader@7.1.0
http://sisadmin55.ru/services.html
<code class="brush:">
exec bash -l
</code>
http://stackoverflow.com/questions/400212/how-to-copy-to-clipboard-in-javascript
http://rokr-blargh.appspot.com/copying-text-into-the-clipboard-with-javascript-in-firefox-safari-ie-opera-292559a2cc6c4ebf9724d23e8bc5ad8a
In the past I’ve wondered if it was possible to make a cross-browser (JavaScript) script that a webpage could execute to copy some text to the windows clipboard. Would be handy and would save the user from pulling the whole CTRL+C trick out.
It was pretty easy to do with Internet Explorer with the code below… but we all don’t use IE.
<code class="brush:javascript">
holdtext.innerText = copytext.innerText;
Copied = holdtext.createTextRange();
Copied.execCommand("Copy");
</code>
Credit to Mark O’Sullivan of http://lussumo.com/ since he has a solution for this problem. In his file browser / photo gallery application, there is a link to copy the URL of the file to the clipboard… works in both Firefox and IE (I also checked in Opera 8.5 and it didn’t seem to work).
Here is the solution implemented in a javascript function:
Update: I have updated the copy() function in the script to use encodeURIComponent() instead of escape() which will allow use of ‘+’ to be copied as well.
<code class="brush:javascript">
function copy(inElement) {
if (inElement.createTextRange) {
var range = inElement.createTextRange();
if (range && BodyLoaded==1)
range.execCommand('Copy');
} else {
var flashcopier = 'flashcopier';
if(!document.getElementById(flashcopier)) {
var divholder = document.createElement('div');
divholder.id = flashcopier;
document.body.appendChild(divholder);
}
document.getElementById(flashcopier).innerHTML = '';
var divinfo = '<embed src="_clipboard.swf" FlashVars="clipboard='+encodeURIComponent(inElement.value)+'" width="0" height="0" type="application/x-shockwave-flash"></embed>';
document.getElementById(flashcopier).innerHTML = divinfo;
}
}
</code>
Pretty slick I’d say, he’s using a Macromedia Flash file to perform the copy on the Browser’s behalf (since Firefox/Netscape’s security settings do not allow access to the clipboard by default).
I’ve uploaded the [[SWF file|http://www.jeffothy.com/weblog/uploads/clipboard.php]] that you can use in your own webpage.
This software is licensed under the GPL so you can take this solution, change it, whatever, free.
Взято с http://www.jeffothy.com/weblog/clipboard-copy/
"+yy or "*yy to copy to clipboard
"+p or "*p to paste from clipboard
Just press Shift key while blocking the text in mcedit, or copy item in popup menu will remain inactive on right click. :P
копировать из midnight commander в буфер
<code class="brush:">
CREATE TABLE IF NOT EXISTS t1 LIKE t2;
INSERT INTO t1 SELECT * FROM t2 WHERE ;
</code>
ADOM allows you to customize the keybindings used during the game for invoking commands to a certain extent. When ADOM is started it searches for a file called 'adom.kbd' (or '.adom.kbd' on Linux systems) in your data directory (call 'adom -d' to determine your data directory). This file contains a description of its syntax, which should answer all questions. Customizing a keymap to a very specific system requires quite some work on your side if you want to use special keys and such stuff (you will need to know the ASCII codes your system generates when a special key is pressed).
Note that customization is possible only to a certain extent.
If you would like to have a printed reference of your own keymap bindings at hand, you can enter
adom -r
at your command prompt. This will make ADOM to create a file called 'keyref.kbd', which contains the current bindings and can be printed on any line printer. Check it for the details about how to define new key bindings.
*[[Portable Cygwin|http://bitsofwizardry.wordpress.com/2010/01/29/cygwin-portable-some-linux-power-on-a-usb-for-windows/]]
*[[Windows and Cygwin symlinks|http://stackoverflow.com/questions/3343988/accessing-a-cygwin-symlink-from-windows]]
* [[download|http://www.vim.org/scripts/script.php?script_id=90]]
Information has taken [[from here|http://developers.blog.box.com/2007/06/20/how-to-debug-php-with-vim-and-xdebug-on-linux/]].
Here is the scenario: You have multiple developers logged into a Linux server which is running Apache and PHP using Vim to write PHP code. They’re using error_log and echo statements to debug their code. It takes forever, it’s tedious and can result in bugs from forgotten debug statements. You stare enviously at .NET programmers with fancy debuggers (while you snicker knowing that you edit 10x faster with Vim anyways). But still, you know there has to be a better way. There is. Here’s how it works. You’re coding away in vim. You hit F5; Vim waits for a connection from the PHP server. You refresh the PHP page you’re working on. It attempts to contact Vim — connection successful. You are launched into a debugging session right inside Vim. You can step into, over, and out of statements, eval statements, get all variables in context, get and set properties, remove and set breakpoints, all on the fly. Finally, some real programming tools.
''The environment: Vim''
First, we need to make sure vim is compiled correctly. Type :version in your Vim and check the features section. If you have +python and +signs, you’re good to go. Skip ahead to the next section. Otherwise, you need to compile from source. On Linux, download and untar the source code, and open up src/feature.h. You need to comment out the conditional statements around the +signs feature. In Vim 7.1, it looks like this:
<code class="brush:">
/* * +signs Allow signs to be displayed to the left of text lines. * Adds the ":sign" command. */ #if defined(FEAT_BIG) ||
defined(FEAT_SUN_WORKSHOP) || defined(FEAT_NETBEANS_INTG) # define FEAT_SIGNS # if ((defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA))
&& defined(HAVE_X11_XPM_H)) || defined(FEAT_GUI_GTK) || (defined(WIN32) && defined(FEAT_GUI)) # define FEAT_SIGN_ICONS #
endif #endif
</code>
You need to comment out both if statements and their respective endif’s, so it looks like this:
<code class="brush:">
/* * +signs Allow signs to be displayed to the left of text lines. * Adds the ":sign" command. */ /*#if defined(FEAT_BIG) ||
defined(FEAT_SUN_WORKSHOP) || defined(FEAT_NETBEANS_INTG)*/ # define FEAT_SIGNS /*# if ((defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA))
&& defined(HAVE_X11_XPM_H)) || defined(FEAT_GUI_GTK) || (defined(WIN32) && defined(FEAT_GUI))*/ # define FEAT_SIGN_ICONS /*#
endif #endif*/
</code>
then cd back to the top source directory and run:
<code class="brush:">
./configure --enable-pythoninterp
</code>
If on a 64-bit system or a system with a strange python installation, you may have to add """--"""with-python-config-dir=/usr/lib64/python2.3/config to the configure string. If the configure script can’t find the config directory it will say so in the script output, but the configure won’t explicitly fail — so you have to be sure that all the python stuff is OK. After configuration, do
<code class="brush:">
make && make install
</code>
to install your newly python’d vim.
''The client: Debugger.vim (and Debugger.py)''
Now that vim is ready, download the DBGp client script. Extract the two files (debugger.vim and debugger.py) to your vim plugin directory or your .vim home directory. In Vim 7.1 compiled on Linux, the default load-for-everyone plugin location is /usr/local/share/vim/vim71/plugin/, so you would put both files in that directory. Try to run vim — if you get no errors, everything should be good. If you get an error, double check :version to make sure +python and +signs are there. If they are, post a comment here with the vi error you get. If they aren’t, the vim compilation/installation didn’t work — go back and try it again. Now your debugging client is ready. Now let’s setup the server.
''The server (engine): XDebug''
[[Download XDebug|http://xdebug.org/]]. Download the source, compile the .so and add the following lines to your php.ini:
<code class="brush:">
[Zend]
zend_extension = /full/path/to/xdebug.so
xdebug.remote_enable = 1
xdebug.remote_port = 9000
xdebug.remote_host = localhost
</code>
Open a file in your browser which outputs <?php phpinfo(); ?> to make sure xdebug is loaded.
Now, with your site being example.com, go to http://example.com/index.php?XDEBUG_SESSION_START=1. This will set a cookie in your browser which expires in 1 hour which tells the PHP XDebug module to try to make a connection every time a page loads to a debugging client which is listening on port 9000. The cool thing is that if it can’t make a connection, it just keeps loading the page, so there’s no issue just leaving the cookie on. Now go back to vim and press F5. You should see a message like “waiting for a new connection on port 9000 for 5 seconds…” at the bottom of the screen. You have five seconds to now refresh the PHP page. This will create a connection between the debugger and client. Now you’re debugging. Follow the instructions in the Help window to step into, over and out of code. Press F5 to run the code until a breakpoint (which you can set using :Bp).
''But what if I have multiple developers on the same machine?''
No problem. Simply set g:debuggerPort in each developer’s .vimrc to get the client listening on a different port. So if you wanted one developer to connect on 9001 instead of the standard 9000, you would add this line to their .vimrc:
<code class="brush:">
let g:debuggerPort = 9001
</code>
Getting the server to connect on a different port is a little trickier. You need to set a custom php.ini value (xdebug.remote_port) for each user. It works best if you’re using VirtualHost’s in Apache. Just add the following line to the VirtualHost section of your httpd.conf:
<code class="brush:">
php_value xdebug.remote_port 9001
</code>
Now restart Apache and if you use that VirtualHost and that vi user, then they should connect successfully.
''That’s about it''
Please post any questions or suggestions you may have. I hope this helps a few of you out there who want debugging tools but don’t want to give up Vim editing. Also be sure to post any alternate methods, or any patches or improvements to the remote PHP debugger vim script, and I’ll be sure to incorporate them. [Note: This is the first in a series of posts we'll be doing along the lines of tutorials, tools we've developed, tech commentary, and so on. Please feel free to subscribe, as well as leave any comments, thoughts or suggestions below so we can be sure to improve with each article! Thanks!]
''Open mc, push F9->Command->Edit extension file'', append to the end of the file this:
<code class="brush:">
# Default target for anything not described above
default/*
<------>Open=%var{EDITOR:vim} %f
<------>View=%var{EDITOR:vim} %f
<------>Edit=%var{EDITOR:vim} %f
</code>
*[[Справочник "паттерны проектирования"|http://design-pattern.ru/]]
*[[Проектирования больше нет?|http://www.maxkir.com/sd/designDead_RUS.html]] (оригинал [[Is Design dead?|http://www.martinfowler.com/articles/designDead.html]])
Изменил настройки в админке и теперь не можешь в нее войти, тогда надо сделать super_user='твой пользователь' в conf/local.php:
http://www.freelists.org/post/dokuwiki/restoring-admin-permissions,2
<code class="brush:">
ALTER TABLE tbl_name DROP FOREIGN KEY fk_symbol;
</code>
http://dev.mysql.com/doc/refman/5.5/en/innodb-foreign-key-constraints.html
drop index name_of_index on t;
drop index `PRIMARY` on t;
It is saying you have a duplicate entry in your Software Sources. Either use that applet to identify and disable the offending entry, or use gksu gedit /etc/apt/sources.list to look through the list and comment out or delete the line. Note there are also .list files in the /etc/apt/sources.list.d sub-folder which you will need to search if you can't find the entry in sources.list.
Here are some useful tips what to put to vim startup config file.
On linux, edit ~/.vimrc, on Windows C:\PATH\TO\VIM\INSTALATION\_vimrc (ie. C:\Program Files\vim\_vimrc) and put following lines in it:
<code class="brush:">
" this is a comment
color pablo " pablo color scheme, my favourite
set enc=UTF-8 " set encoding to UTF-8, no more local charsets
set backupdir=C:\\Temp " put backup and swap files in this dir, not in actual directory (annoying)
set dir=C:\\Temp " the same
set number " show line numbers
</code>
Highlighting Qt4 keywords (class names, connect, SIGNAL, SLOT)
!!The fast way
Download c.vim and replace VIMDIR\syntax\c.vim (backup original file first, one never knows). All done :]
!!A little bit slower way
Open your VIMDIR\syntax\c.vim and search for:
<code class="brush:">
" A bunch of useful C keywords
syn keyword cStatement goto break return continue asm
...
..
</code>
Replace syn keyword ... line with this one:
<code class="brush:">
syn keyword cStatement goto break return continue asm connect SIGNAL SLOT
</code>
Open vim-qt4-keywords.txt. Copy that huge line and put it somwhere in the c.vim (I've placed it after line 157). Be aware of trailing newlines. They may cause vim not to load properly c.vim file.
Perl script to extract Qt4 class names from include sources
As you probable assume I didn't produced class list "by hand". Here is simple perl script I wrote for this task.
make_vim_class_list.pl
''Usage:''
Script uses module File::Listing.
Most simple use of this script is the following:
<code class="brush:">
Copy include directory from QTDIR to some directory (ie. MYDIR)
Put make_vim_class_list.pl script to MYDIR
Run script like this: ./make_vim_class_list.pl . (note actual directory [dot] as an argument)
</code>
This produces 2 files c.vim (huge line to put in your c.vim) and qtclasslist.txt (each class name on new line, maybe it'll be usefull to you somehow).
''Notes:''
If your QTDIR environment variable is set, script scans includes in QTDIR/includes.
Works only with Qt4 includes, won't work for Qt3.x.
http://platypope.org/yada/emacs-demo/
Change ~/.bushrc, ~/.profile
<code class="brush:javascript">
var w = window.open("http://www.google.com", "_blank", 'top=442,width=480,height=460,resizable=yes', true);
var watchClose = setInterval(function() {
if (w.closed) {
clearTimeout(watchClose);
//Do something here...
}
}, 200);
</code>
<code class="brush:">
sudo svn export -r 33454 svn://autonew.autovl.loc/drom/trunk/www/common_drom_functions.inc.php
</code>
/***
|Name:|ExtentTagButtonPlugin|
|Description:|Adds a New tiddler button in the tag drop down|
|Version:|3.2 ($Rev: 3861 $)|
|Date:|$Date: 2008-03-08 10:53:09 +1000 (Sat, 08 Mar 2008) $|
|Source:|http://mptw.tiddlyspot.com/#ExtendTagButtonPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License|http://mptw.tiddlyspot.com/#TheBSDLicense|
***/
//{{{
window.onClickTag_mptw_orig = window.onClickTag;
window.onClickTag = function(e) {
window.onClickTag_mptw_orig.apply(this,arguments);
var tag = this.getAttribute("tag");
var title = this.getAttribute("tiddler");
// Thanks Saq, you're a genius :)
var popup = Popup.stack[Popup.stack.length-1].popup;
createTiddlyElement(createTiddlyElement(popup,"li",null,"listBreak"),"div");
wikify("<<newTiddler label:'New tiddler' tag:'"+tag+"'>>",createTiddlyElement(popup,"li"));
return false;
}
//}}}
Функции должны иметь небольшое количество аргументов. Лучше всего, когда
аргументов вообще нет; далее следуют функции с одним, двумя и тремя
аргументами. Функции с четырьмя и более аргументами весьма сомнительны;
старайтесь не использовать их в своих программах (см. «Аргументы функций» на
с. 64).
Выходные аргументы противоестественны. Читатель кода ожидает, что
аргументы используются для передачи входной, а не выходной информации. Если ваша
функция должна изменять чье-либо состояние, пусть она изменяет состояние
объекта, для которого она вызывалась (см. «Выходные аргументы», с. 70).
Логические аргументы явно указывают на то, что функция выполняет более
одной операции. Они сильно запутывают код. Исключите их из своих программ
(см. «Аргументы-флаги», с. 66).
Если метод ни разу не вызывается в программе, то его следует удалить. Хранить
«мертвый код» расточительно. Не бойтесь удалять мертвые функции. Не
забудьте, что система управления исходным кодом позволит восстановить их в случае
необходимости.
[[farmanager.com|http://www.farmanager.com/]]
* ''вызываем/скрываем эксплорер на Ctrl-E''
<<<
The 'Vexplore' command opens a vertical directory browser. You can build on this by adding the following code to your .vimrc file to toggle the vertical browser with Ctrl-E (for example):
<code class="">
" Toggle Vexplore with Ctrl-E
function! ToggleVExplorer()
if exists("t:expl_buf_num")
let expl_win_num = bufwinnr(t:expl_buf_num)
if expl_win_num != -1
let cur_win_nr = winnr()
exec expl_win_num . 'wincmd w'
close
exec cur_win_nr . 'wincmd w'
unlet t:expl_buf_num
else
unlet t:expl_buf_num
endif
else
exec '1wincmd w'
Vexplore
let t:expl_buf_num = bufnr("%")
endif
endfunction
map <silent> <C-E> :call ToggleVExplorer()<CR>
</code>
<<<
* ''при выборе файла в эксплорере, в каком окне он откороется? (0 - там же, 3 - в окне справа - это самое гуд поведение)''
<<<
<code class="">
let g:netrw_browse_split = n
</code>
где n
=0: re-using the same window
=1: horizontally splitting the window first
=2: vertically splitting the window first
=3: open file in new tab
=4: act like "P" (ie. open previous window)
<<<
http://stackoverflow.com/questions/542929/highlighting-unmatched-brackets-in-vim
Forward:
<code class="brush:">
/something
</code>
Backward:
<code class="brush:">
?something
</code>
[[How to become a freelance programmer|http://www.buzzle.com/articles/how-to-become-a-freelance-programmer.html]]
Обсуждение на RSDN.
''Выбор ЯП'':
> вообщето нужно не технологии выбирать а problem domain. То что ты перечислил — это всего лиш инструменты, сначала реши чем тебе нравиться заниматься, а уже потом думай каким инструментом это делаеться.
''Коньюнктура рынка — мерзкая тварь''
> Программеры на плюсах под линукс нужны, вакансии есть, и оплачиваются хорошо. Если тебе это нравится, то занимайся этим — не гонись за призрачной коньюнктурой рынка. Коньюнктура — мерзкая тварь — меняется она быстро и за ней не угонишся, потому что ты всегда будешь в роли догоняющего. Кроме того, 4-й курс инстика — это самое что нинаесть милое розовое время. Можно расслабленно искать работу по душе. Не парся о бабках — они придут, они всегджа приходят к тем, кто увлечен своей работой, и кто реально специалист.
Переменные и функции должны определяться вблизи от места их использования.
Локальные переменные должны объявляться непосредственно перед первым
использованием и должны обладать небольшой вертикальной областью
видимости. Объявление локальной переменной не должно отдаляться от места ее
использования на сотню строк.
Приватные функции должны определяться сразу же после первого
использования. Приватные функции принадлежат области видимости всего класса, но
вертикальное расстояние между вызовами и определениями все равно должно
быть минимальным. Приватная функция должна обнаруживаться простым
просмотром кода от места первого использования.
Если некая операция выполняется определенным образом, то и все похожие
операции должны выполняться так же. Это правило возвращает нас к «принципу
наименьшего удивления». Ответственно подходите к выбору новых схем и
обозначений, а если уж выбрали — продолжайте следовать им.
Если в функцию включена переменная response для хранения данных HttpServ-
letResponse, будьте последовательны и используйте такое же имя переменной
в других функциях, работающих с объектами HttpServl etResponse. Если метод
называется processVerificationRequest, присваивайте похожие имена (например,
processDeletionRequest) методам, обрабатывающим другие запросы.
Последовательное соблюдение подобных схем и правил существенно упрощает
чтение и модификацию кода.
Какой прок от конструктора по умолчанию, не имеющего реализации? Он только
попусту загромождает код. Неиспользуемые переменные, невызываемые
функции, бессодержательные комментарии — все это бесполезный балласт, который
следует удалить. Поддерживайте чистоту в своих исходных файлах, следите за
их структурой и не допускайте появления балласта.
То, что не зависит друг от друга, не должно объединяться искусственными
привязками. Например, обобщенные перечисления не должны содержаться в более
конкретных классах, потому что в этом случае информация о конкретном
классе должна быть доступна в любой точке приложения, в которой используется
перечисление. То же относится и к статическим функциям общего назначения,
объявляемым в конкретных классах.
В общем случае искусственной считается привязка между двумя модулями, не
имеющая явной, непосредственной цели. Искусственная привязка возникает
в результате размещения переменной, константы или функции во временно
удобном, но неподходящем месте. Главные причины для появления искусственных
привязок — лень и небрежность.
Не жалейте времени — разберитесь, где должно располагаться объявление той
или иной функции, константы или переменной. Слишком часто мы размещаем
их в удобном месте «под рукой», а потом оставляем там навсегда.
Это один из «запахов кода», описанных у Мартина Фаулера [Refactoring]. Для
методов класса должны быть важны переменные и функции того класса,
которому они принадлежат, а не переменные и функции других классов. Когда метод
использует методы доступа другого объекта для манипуляций с его данными, то
он завидует области видимости класса этого объекта. Он словно мечтает
находиться в другом классе, чтобы иметь прямой доступ к переменным, с которыми
он работает. Пример:
<code class="brush:java">
public class HourlyPayCalculator {
public Money calculateWeeklyPay(HourlyEmployee e) {
int tenthRate = e.getTenthRateO.getPenniesO;
int tenthsWorked = e.getTenthsWorkedO:
int straightTime = Math.min(400, tenthsWorked);
int overTime = Math.max(0, tenthsWorked - straightTime);
int straightPay = straightTime * tenthRate;
int overtimePay = (int)Math.round(overTime*tenthRate*1.5):
return new Money(straightPay + overtimePay);
}
}
</code>
Метод calculateWeeklyPay обращается к объекту HourlyEmployee за данными для
обработки. Метод calculateWeeklyPay завидует области видимости HourlyEmployee.
Он «желает» получить доступ к внутренней реализации HourlyEmployee.
В общем случае от функциональной зависти следует избавиться, потому что
она предоставляет доступ к «внутренностям» класса другому классу. Впрочем,
иногда функциональная зависть оказывается неизбежным злом. Рассмотрим
следующий пример:
<code class="brush:java">
public class HourlyEmployeeReport {
private HourlyEmployee employee;
public HourlyEmployeeReport(HourlyEmployee e) {
this.employee = e;
}
String reportHours() {
return String.format(
"Name: %s\tHours:%d.%ld\n".
employee.getName(),
employee.getTenthsWorked()/10.
employee.getTenthsWorked()%10);
}
}
</code>
Очевидно, метод reportHours завидует классу HourlyEmployee. С другой стороны,
мы не хотим, чтобы класс HourlyEmployee знал о формате отчета.
Перемещение форматной строки в класс HourlyEmployee нарушает некоторые принципы
объектно-ориентированного проектирования(принцип единой ответственности, принцип открытости/закрытости
и принцип сокрытия реализаций). Такое размещение привязывает
HourlyEmployee к формату отчета и делает его уязвимым для изменений в этом
формате.
Ничто так не раздражает, как висящий в конце вызова функции аргумент false.
Зачем он здесь? Что изменится, если этот аргумент будет равен true? Смысл
селектора трудно запомнить, но дело не только в этом — селектор указывает
на объединение нескольких функций в одну. Аргументы-селекторы помогают
ленивому программисту избежать разбиения большой функции на несколько
меньших. Пример:
<code class="brush:java">
public int calculateWeeklyPay(boolean overtime) {
int tenthRate = getTenthRate();
int tenthsWorked = getTenthsWorked();
int straightTime = Math.min(400, tenthsWorked);
int overTime = Math.max(0, tenthsWorked - straightTime);
int straightPay = straightTime * tenthRate;
double overtimeRate = overtime ? 1.5 : 1.O * tenthRate;
int overtimePay = (int)Math.round(overTime*overtimeRate);
return straightPay + overtimePay;
}
</code>
Функция вызывается с аргументом true при оплате сверхурочной работы по
полуторному тарифу или с аргументом false при оплате по стандартному тарифу
Каждый раз, когда вы встречаете вызов calculateWeeklyPay(false), вам приходится
вспоминать, что он означает, и это само по себе неприятно. Но по-настоящему
плохо то, что автор поленился использовать решение следующего вида:
<code class="brush:java">
public int straightPay() {
return getTenthsWorked() * getTenthRate():
}
public int overTimePay() {
int overTimeTenths = Math.max(0. getTenthsWorkedO - 400);
int overTimePay = overTimeBonus(overTimeTenths);
return straightPay() + overTimePay;
}
private int overTimeBonus(int overTimeTenths) {
double bonus = 0.5 * getTenthRate() * overTimeTenths;
return (int) Math.round(bonus);
}
</code>
Конечно, селекторы не обязаны быть логическими величинами. Это могут быть
элементы перечислений, целые числа или любые другие типы аргументов, в
зависимости от которых выбирается поведение функции. В общем случае лучше
иметь несколько функций, чем передавать функции признак для выбора
поведения.
Код должен быть как можно более выразительным. Слишком длинные
выражения, венгерская запись, «волшебные числа» — все это скрывает намерения
автора. Например, приводившаяся ранее функция overTimePay могла бы выглядеть
итак:
<code class="brush:java">
public int m_otCalc() {
return iThsWkd * iThsRte +
(int) Math.round(0.5 * iThsRte *
Math.max(0. IThsWkd - 400)
);
}
</code>
Такая запись выглядит компактной и плотной, но разбираться в ней — сущее
мучение. Не жалейте времени на то, чтобы сделать намерения своего кода
максимально прозрачными для читателей.
Одно из самых важных решений, принимаемых разработчиком, — выбор места
для размещения кода. Например, где следует объявить константу PI? В классе
Math? А может, ей место в классе Trigonometry? Или в классе Circle?
В игру вступает принцип наименьшего удивления. Код следует размещать там,
где читатель ожидает его увидеть. Константа PI должна находиться там, где
объявляются тригонометрические функции. Константа OVERTIMERATE объявляется
в классе HourlyPayCalculator.
Иногда мы пытаемся «творчески» подойти к размещению функциональности.
Мы размещаем ее в месте, удобном для нас, но это не всегда выглядит
естественно для читателя кода. Предположим, потребовалось напечатать отчет с общим
количеством отработанных часов. Мы можем просуммировать часы в коде,
печатающем отчет, или же накапливать сумму в коде обработки учетных карточек
рабочего времени.
Чтобы принять решение, можно посмотреть на имена функций. Допустим,
в модуле отчетов присутствует функция с именем getTotalHours, а в модуле
обработки учетных карточек присутствует функция saveTimeCard. Какая из этих
двух функций, если судить по имени, наводит на мысль о вычислении суммы?
Ответ очевиден.
Очевидно, по соображениям производительности сумму правильнее вычислять
при обработке карточек, а не при печати отчета. Все верно, но этот факт должен
быть отражен в именах функций. Например, в модуле обработки учетных
карточек должна присутствовать функция computeRunningTotalOfHours.
Math.maxCdouble a, double b)—хороший статический метод. Он работает не с
одним экземпляром; в самом деле, запись вида new Math().max(a ,b) или даже a .max(b)
выглядела бы довольно глупо. Все данные, используемые шах, берутся из двух
аргументов, а не из некоего объекта-«владельца». А главное, что метод Math max
почти наверняка не потребуется делать полиморфным.
Но иногда мы пишем статические функции, которые статическими быть не
должны. Пример:
HourlyPayCalculator.calculatePay(employee, overtimeRate)
Эта статическая функция тоже выглядит вполне разумно. Она не работает ни
с каким конкретным объектом и получает все данные из своих аргументов.
Однако нельзя исключать, что эту функцию потребуется сделать полиморфной.
Возможно, в будущем потребуется реализовать несколько разных алгоритмов для
вычисления почасовой оплаты — скажем, OvertimeHourlyPayCalculator и Straight-
TimeHourlyPayCal cul ator. В этом случае данная функция не может быть
статической. Ее следует оформить как нестатическую функцию Employee.
В общем случае отдавайте предпочтение нестатическим методам перед
статическими. Если сомневаетесь, сделайте функцию нестатической. Если вы твердо
уверены, что функция должна быть статической, удостоверьтесь в том, что от нее не
потребуется полиморфное поведение.
Кент Бек писал об этом в своей великой книге «Smalltalk Best Practice Patterns»
[Beck97, p. 108], а затем позднее — в столь же великой книге «Implementation
Patterns» [Beck07]. Один из самых эффективных способов улучшения
удобочитаемости программы заключается в том, чтобы разбить обработку данных
на промежуточные значения, хранящиеся в переменных с содержательными
именами.
Возьмем следующий пример из FitNesse:
<code class="brush:java">
Matcher match = headerPattern.matcher(1ine);
if(match.find())
{
String key = match.group(l);
String value = match.group(2);
headers.put(key.toLowerCase(), value);
}
</code>
Простое использование пояснительных переменных четко объясняет, что первое
совпадение содержит ключ (key), а второе — значение (value).
Перестараться в применении пояснительных переменных трудно. Как правило,
чем больше пояснительных переменных, тем лучше. Поразительно, насколько
очевидным иногда становится самый невразумительный модуль от простого
разбиения обработки данных на промежуточные значения с удачно выбранными
именами.
Современные среды программирования позволяют объединять в одном исходном
файле код, написанный на разных языках. Например, исходный файл на языке
Java может содержать вставки XML, HTML, YAML, JavaDoc, English, JavaScript
и т. д. Или, скажем, наряду с кодом HTML в файле JSP может присутствовать
код Java, синтаксис библиотеки тегов, комментарии на английском языке,
комментарии Javadoc, XML, JavaScript и т. д. В лучшем случае результат получается
запутанным, а в худшем — неаккуратным и ненадежным.
326 Глава 17. Запахи и эвристические правила
В идеале исходный файл должен содержать код на одном — и только одном! —
языке. На практике без смешения языков обойтись, скорее всего, не удастся. Но
по крайней мере следует свести к минимуму как количество, так и объем кода на
дополнительных языках в исходных файлах.
Взгляните на следующий код:
<code class="brush:java">
Date newDate = date.add(5);
</code>
Как вы думаете, что он делает — прибавляет пять дней к date? А может, пять
недель или часов? Изменяется ли экземпляр date, или функция возвращает новое
значение Date без изменения старого? По вызову невозможно понять, что делает
эта функция.
Если функция прибавляет пять дней с изменением date, то она должна
называться addDaysTo или increaseByDays. С другой стороны, если функция возвращает
новую дату, смещенную на пять дней, но не изменяет исходного экземпляра date,
то она должна называться daysLater или daysSince.
Если вам приходится обращаться к реализации (или документации), чтобы
понять, что делает та или иная функция, постарайтесь найти более удачное имя
или разбейте функциональность на меньшие функции с более понятными
именами.
Очень много странного кода пишется из-за того, что люди не утруждают себя
пониманием алгоритмов. Они заставляют программу работать «грубой силой»,
набивая ее командами if и флагами, вместо того чтобы остановиться и подумать,
что же в действительности происходит.
Программирование часто сопряжено с исследованиями. Вы думаете, что знаете
подходящий алгоритм для решения задачи, но йотом вам приходится возиться
с ним, подправлять и затыкать щели, пока вы не заставите его «работать». А как
вы определили, что он «работает»? Потому что алгоритм прошел все тесты,
которые вы смогли придумать.
В этом подходе нет ничего плохого. Более того, часто только так удается
заставить функцию делать то, что она должна делать (по вашему мнению). Однако
ограничиться «работой» в кавычках недостаточно.
Прежде чем откладывать в сторону готовую функцию, убедитесь в том, что вы
понимаете, как она работает. Прохождения всех тестов недостаточно. Вы должны
знать(знать, как работает ваш код, и знать, делает ли алгоритм то, что требуется, — не одно и то
же), что ваше решение правильно.
Один из лучших способов достичь этого знания и понимания — разбить функцию
на фрагменты настолько чистые и выразительные, что вам станет совершенно
очевидно, как работает данная функция.
Если один модуль зависит от другого, зависимость должна быть не только
логической, но и физической. Зависимый модуль не должен делать никаких
предположений (иначе говоря, создавать логические зависимости) относительно того
модуля, от которого он зависит. Вместо этого он должен явно запросить у этого
модуля всю необходимую информацию.
Допустим, вы пишете функцию, которая выводит текстовый отчет об
отработанном времени. Класс с именем HourlyReporter собирает все данные в
удобной форме и передает их классу HourlyReportFormatter для вывода.
<code class="brush:java">
public class HourlyReporter {
private HourlyReportFormatter formatter;
private List<LineItem> page;
private final int PAGE_SIZE = 55;
public HourlyReporter(HourlyReportFormatter formatter) {
this.formatter = formatter;
page = new ArrayList<LineItem>();
}
public void generateReport(List<HourlyEmployee> employees) {
for (HourlyEmployee e ; employees) {
addLineltemToPage(e);
if (page.size() == PAGE_SIZE)
printAndClearItemList();
}
if (page.size() > 0)
printAndClearltemListO;
}
private void printAndClearltemList() {
formatter.format(page);
page.clearO;
}
private void addLineItemToPage(HourlyEmployee e) {
Lineltem item = new Lineltem();
item, name = e.getName();
item.hours = e.getTenthsWorked() / 10;
item.tenths = e.getTenthsWorked() % 10;
page.add(item);
}
public class Lineltem {
public String name;
public int hours;
public int tenths;
}
}
</code>
У этого кода имеется логическая зависимость, лишенная физического
воплощения. Удастся ли вам найти ее? Речь идет о константе PAGE_SIZE. Почему класс
HourlyReporter должен знать размер страницы? За размер страницы должен
отвечать класс HourlyReportFormatter.
Факт объявления PAGESIZE в HourlyReporter указывает на неверное размещение
[ [[G17: Неверное размещение]] ]. Разработчик полагает, что классу HourlyReporter необходимо знать размер
страницы. Такое предположение является логической зависимостью. Работа
HourlyReporter зависит от того факта, что HourlyReportFormatter поддерживает
размер страницы до 55. Если какая-то реализация HourlyReportFormatter не сможет
работать с такими страницами, произойдет ошибка.
Чтобы создать физическое представление этой зависимости, мы можем включить
в HourlyReportFormatter новый метод с именем getMaxPageSize(). В дальнейшем
HourlyReporter вызывает эту функцию вместо того, чтобы использовать константу PAGE_SIZE.
Эта рекомендация может показаться странной, если вспомнить главу 6. Ведь
в этой главе говорилось, что в тех частях системы, в которые с большей
вероятностью будут добавляться новые функции, а не новые типы, команды switch
вполне уместны.
Во-первых, команды switch чаще всего используются только потому, что они
представляют очевидное решение методом «грубой силы», а не самое уместное
решение для конкретной ситуации. Таким образом, это эвристическое правило
напоминает нам о том, что до применения switch следует рассмотреть
возможность применения полиморфизма.
Во-вторых, ситуации, в которых состав функций менее стабилен, чем состав
типов, встречаются относительно редко. Следовательно, к каждой конструкции
switch следует относиться с подозрением.
Я использую правило «ОДНОЙ КОМАНДЫ SWITCH»: //для каждого типа
выбора программа не должна содержать более одной команды switch. Множественные
конструкции switch следует заменять полиморфными объектами. //
Все рабочие группы должны соблюдать единые стандарты кодирования,
основанные на отраслевых нормах. Стандарт кодирования определяет, где объявляются
переменные экземпляров; как присваиваются имена классов, методов и
переменных; где размещаются фигурные скобки и т. д. Документ с явным описанием
этих правил не нужен — сам код служит примером оформления.
Правила должны соблюдаться всеми участниками группы. Это означает, что
каждый участник группы должен быть достаточно разумным, чтобы понимать:
неважно, как именно размещаются фигурные скобки, если только все согласились
размещать их одинаковым образом.
Если вам захочется узнать, какие конвенции оформления использую я,
обратитесь к переработанному коду в листингах Б.7 (с. 442) — Б. 14.
Вероятно, это одно из самых древних правил разработки. Помню, оно встречалось
мне еще в 60-х годах, в учебниках COBOL, FORTRAN и PL/1 для начинающих.
В общем случае присутствие «сырых» чисел в коде нежелательно. Числа следует
скрыть в константах с содержательными именами.
Например, число 86,400 следует скрыть в константе SECONDS_PER_DAY. Если в
странице отчета выводится 55 строк, число 55 следует скрыть в константе LINES_PER_
PAGE.
Некоторые числа так легко узнаются, что их не обязательно скрывать за
именованными константами — при условии, что они используются в сочетании
с предельно ясным кодом. Пример:
<code class="brush:java">
double milesWalked = feetWalked/5280.0;
int dailyPay = hourlyRate * 8;
double circumference = radius * Math.PI * 2;
</code>
Нужны ли константы FEET_PER_MILE, W0RK_H0URS_PER_DAY и TWO в этих примерах?
Разумеется, последний случай выглядит особенно абсурдно. В некоторых
формулах константы попросту лучше воспринимаются в числовой записи. По поводу
WORK_HOURS_PER_DAY можно спорить, потому что законы и нормативы могут
изменяться. С другой стороны, формула с числом 8 читается настолько удобно, что
мне просто не хочется нагружать читателя кода лишними 17 символами. А число
5280 — количество футов в миле — настолько хорошо известно и уникально, что
читатель сразу узнает его, даже если оно будет располагаться вне какого-либо
контекста.
Такие константы, как 3.141592653589793, тоже хорошо известны и легко
узнаваемы. Однако вероятность ошибки слишком велика, чтобы оставлять их в числовой
форме. Встречая значение 3.1415927535890793, вы сразу догадываетесь, что перед
вами число п, и не проверяете его (а вы заметили ошибку в одной цифре?). Также
мы не хотим, чтобы в программах использовались сокращения 3.14,3.14159,3.142
и т. д. К счастью, значение Math. PI уже определено за нас.
Термин «волшебное число» относится не только к числам. Он распространяется
на все лексемы, значения которых не являются самодокументирующими.
Пример:
<code class="brush:java">
assertEquals(7777, Employee.find("John Doe").employeeNumber());
</code>
В этом проверочном условии задействованы два «волшебных числа». Очевидно,
первое — 7777, хотя его смысл далеко не так очевиден. Второе «волшебное
число» — строка "John Doe". Ее смысл тоже выглядит весьма загадочно.
Оказывается, "John Doe" — имя работника с табельным номером 7777 в тестовой
базе данных, созданной нашей группой. Все участники группы знают, как под-
340 Глава 17. Запахи и эвристические правила
ключаться к этой базе данных. В базе уже хранятся тестовые записи с заранее
известными значениями и атрибутами. Также выясняется, что "John Doe" —
единственный работник с почасовой оплатой в тестовой базе данных. Следовательно,
эта проверка должна выглядеть так:
<code class="brush:java">
assertEquals(HOURLY_EMPLOYEE_ID,
Employee.find(HOURLY_EMPLOYEE_NAME).employeeNumber());
</code>
Наивно ожидать, что первая запись, возвращаемая по запросу, является
единственной. Использовать числа с плавающей точкой для представления
денежных сумм — почти преступление. Отсутствие блокировок и/или
управления транзакциями только потому, что вы думаете, что одновременное
обновление маловероятно — в лучшем случае халатность. Объявление переменной
с типом ArrayList там, где более уместен тип List — чрезмерное ограничение.
Объявление всех переменных защищенными по умолчанию — недостаточное
ограничение.
Принимая решение в своем коде, убедитесь в том, что вы действуете предельно
точно и аккуратно. Знайте, почему принимается решение, и как вы собираетесь
поступать с исключениями из правила. Не ленитесь обеспечивать точность своих
решений. Если вы решили вызвать функцию, которая может вернуть nul 1 —
проверьте возвращаемое значение. Если вы запрашиваете из базы данных запись,
которая, по вашему мнению, является единственной — проверьте, не вернул ли
запрос дополнительные записи. Если вам нужно работать с денежными суммами,
используйте целые числа и округляйте результат по действующим правилам.
Если в программе существует возможность одновременного объявления,
реализуйте ту или иную разновидность блокировки. Неоднозначности и неточности
в коде объясняются либо недопониманием, либо ленью. В любом случае от них
следует избавиться.
Воплощайте архитектурные решения на уровне структуры кода; она важнее
стандартов и конвенций. Содержательные имена полезны, но структура,
заставляющая пользователя соблюдать установленные правила, важнее. Например,
конструкции switch/case с хорошо выбранными именами элементов
перечисления уступают базовым классам с абстрактными методами. Ничто не вынуждает
пользователя применять одинаковую реализацию switch/case во всех случаях;
с другой стороны, базовые классы заставляют его реализовать все абстрактные
методы в конкретных классах.
В булевской логике достаточно трудно разобраться и вне контекста команд i f
или while. Выделите в программе функции, объясняющие намерения условной
конструкции. Например, команда
<code class="brush:java">
if (shouldBeDeleted(timer))
</code>
выразительнее команды
<code class="brush:java">
if (timer.hasExpired() && !timer.isRecurrent())
</code>
Отрицательные условия немного сложнее для понимания, чем положительные.
Таким образом, по возможности старайтесь формулировать положительные
условия. Например, запись
<code class="brush:java">
if (buffer.shouldCompact())
</code>
предпочтительнее записи
<code class="brush:java">
if (!buffer.shouldNotCompact())
</code>
Согласно «принципу наименьшего удивления1», любая функция или класс
должны реализовать то поведение, которого от них вправе ожидать программист.
Допустим, имеется функция, которая преобразует название дня недели в элемент
перечисления, представляющий этот день.
<code class="brush:java">
Day day = DayDate.StringToDay(String dayName);
</code>
Логично ожидать, что строка "Monday" будет преобразована в Day.MONDAY. Также
можно ожидать, что будут поддерживаться стандартные сокращения дней недели,
а регистр символов будет игнорироваться.
Если очевидное поведение не реализовано, читатели и пользователи кода
перестают полагаться на свою интуицию в отношении имен функций. Они теряют
доверие к автору кода и им приходится разбираться во всех подробностях
реализации.
Часто возникает искушение разделить свою функцию на несколько секций для
выполнения разных операций. Такие функции выполняют несколько операций;
их следует преобразовать в группу меньших функций, каждая из которых
выполняет только одну операцию.
Пример:
<code class="brush:java">
public void pay() {
for (Employee e : employees) {
if (e.isPayday()) {
Money pay = e.calculatePay();
e.deliverPay(pay);
}
}
}
</code>
Эта функция выполняет сразу три операции: она перебирает всех работников;
проверяет, начислены ли работнику какие-то выплаты; и наконец, производит
оплату. Код лучше записать в следующем виде:
<code class="brush:java">
public void pay() {
for (Employee e : employees)
paylfNecessary(e);
}
private void payIfNecessary(Employee e) {
if (e.isPayday())
calculateAndDeliverPay(e);
}
private void calculateAndDeliverPay(Employee e) {
Money pay = e.calculatePay();
e.deliverPay(pay);
}
</code>
Каждая из этих функций выполняет только одну операцию (см. «Правило одной
операции», с. 59).
Временные привязки часто необходимы, но они не должны скрываться.
Структура аргументов функций должна быть такой, чтобы последовательность вызова
была абсолютно очевидной. Рассмотрим следующий пример:
<code class="brush:java">
public class MoogDiver {
Gradient gradient;
List<Spline> splines;
public void dive(String reason) {
saturateGradient();
reticulateSplines();
diveForMoog(reason);
}
//...
}
</code>
Порядок вызова трех функций важен. Сначала вызывается saturateGradient(),
затем reticulateSplines() и только после этого diveForMoog(). К сожалению, код
не обеспечивает принудительного соблюдения временной привязки. Ничто не
мешает другому программисту вызвать reticulateSplines до saturateGradient, и все
кончится исключением UnsaturatedGradientException.
Более правильное решение выглядит так:
<code class="brush:java">
public class MoogDiver {
Gradient gradient;
List<Spline> splines;
public void dive(String reason) {
Gradient gradient = saturateGradient();
List<Spline> splines = reticulateSplines(gradient);
diveForMoog(splines, reason);
}
//...
}
</code>
Временная привязка реализуется посредством создания «эстафеты». Каждая
функция выдает результат, необходимый для работы следующей функции, и
вызвать эти функции с нарушением порядка сколько-нибудь разумным способом
уже не удастся.
Пожалуй, кто-то сочтет, что это увеличивает сложность функций, и это
действительно так. Однако дополнительные синтаксические сложности лишь выявляют
реальную сложность ситуации, обусловленную необходимостью согласования
по времени.
Обратите внимание: переменные экземпляров остались на своих местах.
Предполагается, что они используются приватными методами класса. Использование
их в аргументах лишь явно выражает факт существования временной привязки.
Структура кода должна выбираться не произвольно, а по строго определенным
причинам. Позаботьтесь о том, чтобы эти причины были выражены в структуре
кода. Если при чтении кода создается впечатление, что его структура выбрана
произвольно, другим пользователям может показаться, что ее можно изменить.
Если во всей системе последовательно используется единая структура кода,
другие пользователи примут ее и сохранят действующие правила. Например,
недавно я занимался объединением изменений в FitNesse и обнаружил, что один
из наших авторов использовал следующую запись:
<code class="brush:java">
public class AliasLinkWidget extends ParentWidget
{
public static class VariableExpandingWidgetRoot {
//...
}
</code>
Проблема в том, что VariableExpandingWidgetRoot незачем находиться в облети
видимости AliasLinkWidget. Более того, класс
AliasLinkWidget.VariableExpandingWidgetRoot использовался посторонними классами, которые не имели никакого
отношения к AliasLinkWidget.
Возможно, программист разместил VariableExpandingWidgetRoot в AliasWidget по
соображениям удобства, а может, он действительно полагал, что область видимости
этого класса должна находиться внутри области видимости AliasWidget. Какими
бы причинами он ни руководствовался, результат выглядит необоснованным.
Открытые классы, не являющиеся вспомогательными по отношению к другому
классу (то есть используемыми только в его внутренних операциях), не должны
размещаться внутри других классов. По стандартным правилам такие классы
объявляются на верхнем уровне своих пакетов.
Отслеживать граничные условия нелегко. Разместите их обработку в одном
месте. Не позволяйте им «растекаться» по всему коду. Не допускайте, чтобы в вашей
программе кишели многочисленные +1 и -1. Возьмем простой пример из FIT:
<code class="brush:java">
if(level + 1 < tags.length)
{
parts = new Parse(body, tags, level + 1, offset + endTag);
body = null;
}
</code>
Обратите внимание: level+1 здесь встречается дважды. Это граничное
условие, которое следует инкапсулировать в переменной — например, с именем nextLevel:
<code class="brush:java">
int nextLevel = level + 1;
if(nextl_evel < tags.length)
{
parts = new Parse(body, tags, nextLevel, offset + endTag);
body = null;
}
</code>
Все команды функции должны быть сформулированы на одном уровне
абстракции, который расположен одним уровнем ниже операции, описываемой именем
функции. Возможно, это эвристическое правило сложнее всего правильно
интерпретировать и соблюдать. Идея достаточно тривиальна, но люди слишком
хорошо справляются со смешением разных уровней абстракции. Для примера
возьмем следующий код из FitNesse:
<code class="brush:java">
public String render() throws Exception
{
StringBuffer html = new StringBuffer("<hr");
if(size > 0)
html.append(" size=\"").append(size + l).append("\"");
html.append(">"):
return html .toStringO;
}
</code>
Разобраться в происходящем несложно. Функция конструирует тег HTML,
который рисует на странице горизонтальную линию. Толщина линии задается
переменной size.
А теперь взгляните еще раз. В этом методе смешиваются минимум два уровня
абстракции. Первый уровень — наличие толщины у горизонтальной линии. Второй
уровень — синтаксис тега HR. Код позаимствован из модуля HruleWidget проекта
FitNesse. Модуль распознает строку из четырех и более дефисов и преобразует ее
в соответствующий тег HR. Чем больше дефисов, тем больше толщина.
Я переработал этот фрагмент кода так, как показано ниже. Обратите внимание:
имя поля size изменено в соответствии с его истинным назначением (в нем
хранится количество дополнительных дефисов).
<code class="brush:java">
public String renderО throws Exception
{
HtmlTag hr = new HtmlTag("hr");
if (extraDashes > 0)
hг.addAttribute("size". hrSize(extraDashes));
return hr.html();
}
private String hrSize(int height)
{
int hrSize = height + 1;
return String. formatC'%d", hrSize);
}
</code>
Изменение разделяет два уровня абстракции. Функция render просто
конструирует тег HR, ничего не зная о синтаксисе HTML этого тега. Модуль Html Tag берет
на себя все хлопоты с синтаксисом.
Более того, при внесении этого изменения я обнаружил неприметную ошибку.
Исходный код не закрывал тег HR косой чертой, как того требует стандарт
XHTML (иначе говоря, он выдавал {{{<hr>}}} вместо {{{<hr/>}}}), хотя модуль Html Tag был
давно приведен в соответствие со стандартом XHTML.
Разделение уровней абстракции — одна из самых важных и одновременно самых
сложных в реализации функций рефакторинга. В качестве примера возьмем
следующий код — мою первую попытку разделения уровней абстракции в методе
HruleWidget.render.
<code class="brush:java">
public String render0 throws Exception
{
HtmlTag hr = new HtmlTagChr");
if (size > 0) {
hr.addAttribute("size", ""+(size+1));
}
return hr.htmK);
}
</code>
На этой стадии я стремился к тому, чтобы создать необходимое разделение,
и обеспечить прохождение тестов. Мне удалось легко добиться этой цели, но
в созданной функции по-прежнему смешивались разные уровни абстракции — на
этот раз конструирование тега HR и интерпретация/форматирование
переменной size. Таким образом, при разбиении функции по уровням абстракции иногда
обнаруживаются новые уровни, скрытые прежней структурой.
Если в программе имеется константа, определяющая значение по умолчанию
или параметр конфигурации, и эта константа известна на высоких уровнях
абстракции, — не прячьте ее в низкоуровневой функции. Передайте ее в аргументе
низкоуровневой функции, вызываемой из функции высокого уровня.
Рассмотрим пример из FitNesse.
<code class="brush:java">
public static void main(String[] args) throws Exception
{
Arguments arguments = parseCommandLine(args);
//...
}
public class Arguments
{
public static final String DEFAULT_PATH = ".";
public static final String DEFAULT_R00T = "FitNesseRoot";
public static final int DEFAULT_PORT = 80;
public static final int DEFAULT_VERSION_DAYS = 14;
//...
}
</code>
Аргументы командной строки разбираются в самой первой исполняемой строке
FitNesse. Значения аргументов по умолчанию задаются в начале класса Argument.
Читателю не приходится спускаться на нижние уровни системы за командами
следующего вида:
<code class="brush:java">
if (arguments.port == 0) // 80 по умолчанию
</code>
Конфигурационные константы находятся на очень высоком уровне. Если
потребуется, их можно легко изменить. Их значения передаются на более низкие
уровни иерархии другим компонентам приложения. Значения этих констант не
принадлежат нижним уровням приложения.
В общем случае модуль не должен обладать слишком полной информацией о тех
компонентах, с которыми он взаимодействует. Точнее, если А взаимодействует
с В, а В взаимодействует с С, то модули, использующие А, не должны знать о С
(то есть нежелательны конструкции вида
<code class="brush:java">
а.getB().getC().doSomething();
</code>
). Иногда это называется «законом Деметры». Прагматичные программисты используют
термин «умеренный код».
В любом случае все сводится к тому, что модули должны обладать информацией
только о тех модулях, с которыми они непосредственно взаимодействуют, а не
располагать навигационной картой всей системы.
Если в нескольких модулях используется та или иная форма команды
<code class="brush:java">
a.getВ().getC()
</code>
, то в дальнейшем вам будет трудно изменить архитектуру системы, вставив
между В и С промежуточный компонент Q. Придется найти каждое вхождение
<code class="brush:java">
a.getВ().getC()
</code>
и преобразовать его в
<code class="brush:java">
a.getВ().getQ().getC()
</code>
Так образуются жесткие, закостеневшие архитектуры. Слишком многие модули располагают
слишком подробной информацией о системе.
Весь необходимый сервис должен предоставляться компонентами, с которыми
напрямую взаимодействует модуль. Не заставляйте пользователя странствовать
по графу объектов системы в поисках нужного метода. Проблема должна
решаться простыми вызовами вида
<code class="brush:java">
myCol1aborator.doSomething()
</code>
Код должен работать правильно — вроде бы очевидное утверждение. Беда в том,
что мы редко понимаем, насколько сложным бывает правильное поведение.
Разработчики часто пишут функции, которые в их представлении работают, а затем
доверяются своей интуиции вместо того, чтобы тщательно проверить
работоспособность своего кода во всех граничных и особых ситуациях.
Усердие и терпение ничем не заменить. Каждая граничная ситуация, каждый
необычный и особый случай способны нарушить работу элегантного и
интуитивного алгоритма. Не полагайтесь на свою интуицию. Найдите каждое граничное
условие и напишите для него тест.
Авария на Чернобыльской станции произошла из-за того, что директор завода
отключил все механизмы безопасности, один за другим. Они усложняли
проведение эксперимента. Результат — эксперимент так и не состоялся, а мир столкнулся
с первой серьезной катастрофой в гражданской атомной энергетике.
Отключать средства безопасности рискованно. Ручное управление serialVersion-
UID бывает необходимо, но оно всегда сопряжено с риском. Иногда отключение
некоторых (или всех!) предупреждений компилятора позволяет успешно
построить программу, но при этом вы рискуете бесконечными отладочными
сеансами. Не отключайте сбойные тесты, обещая себе, что вы заставите их проходить
позднее, — это так же неразумно, как считать кредитную карту источником
бесплатных денег.
''Это одно из самых важных правил в книге'' и к нему следует относиться очень
серьезно. Практически каждый автор, пишущий о проектировании программного
обеспечения, упоминает это правило. Дэйв Томас (Dave Thomas) и Энди Хант
(Andy Hunt) назвали его принципом DRY («Don't Repeat Yourself», то есть «не
повторяйтесь») [PRAG]. Кент Бек сделал его одним из основных принципов
экстремального программирования в формулировке «Один, и только один раз». Рон
Джеффрис (Ron Jeffries) ставит это правило на второе место, после требования
о прохождении всех тестов.
Каждый раз, когда в программе встречается повторяющийся код, он указывает
на упущенную возможность для абстракции. Возможно, дубликат мог бы стать
функцией или даже отдельным классом. «Сворачивая» дублирование в
подобные абстракции, вы расширяете лексикон языка программирования. Другие
программисты могут воспользоваться созданными вами абстрактными
концепциями. Повышение уровня абстракции ускоряет программирование и снижает
вероятность ошибок.
Простейшая форма дублирования — куски одинакового кода. Программа
выглядит так, словно у программиста дрожат руки, и он снова и снова вставляет один
и тот же фрагмент. Такие дубликаты заменяются простыми методами.
Менее тривиальная форма дублирования — цепочки switch/case или i f/el se,
снова и снова встречающиеся в разных модулях и всегда проверяющие одинаковые
наборы условий. Вместо них надлежит применять полиморфизм.
Еще сложнее модули со сходными алгоритмами, но содержащие похожих строк
кода. Однако дублирование присутствует и в этом случае. Проблема решается
применением паттернов ШАБЛОННЫЙ МЕТОД или СТРАТЕГИЯ [GOF].
В сущности, большинство паттернов проектирования, появившихся за последние
15 лет, представляет собой хорошо известные способы борьбы с дублированием.
Нормальные формы Кодда устраняют дублирование в схемах баз данных. Само
объектно-ориентированное программирование может рассматриваться как
стратегия модульной организации кода и устранения дубликатов. Естественно, это
относится и к структурному программированию.
Надеюсь, я достаточно четко выразил свою мысль. Ищите и устраняйте
дубликаты повсюду, где это возможно.
В программировании важную роль играют абстракции, отделяющие
высокоуровневые общие концепции от низкоуровневых подробностей. Иногда эта задача
решается созданием абстрактных классов, содержащих высокоуровневые
концепции, и производных классов, в которых хранятся низкоуровневые концепции.
Действуя подобным образом, необходимо позаботиться о том, чтобы разделение
было полным. Все низкоуровневые концепции должны быть сосредоточены
в производных классах, а все высокоуровневые концепции объединяются в
базовом классе.
Например, константы, переменные и вспомогательные функции, относящиеся
только к конкретной реализации, исключаются из базового класса. Базовый класс
не должен ничего знать о них.
Правило также относится к исходным файлам, компонентам и модулям.
Качественное проектирование требует, чтобы концепции разделялись на разных
уровнях и размещались в разных контейнерах. Иногда такими контейнерами
являются базовые и производные классы; в других случаях это могут быть
исходные файлы, модули или компоненты. Но какое бы решение ни было выбрано
в конкретном случае, разделение должно быть полным. Высокоуровневые и
низкоуровневые концепции не должны смешиваться.
Рассмотрим следующий фрагмент:
<code class="brush:java">
public interface Stack {
Object pop() throws EmptyException;
void push(Object o) throws EullException;
double percentFull();
class EmptyException extends Exception {}
class Full Exception extends Exception {}
}
</code>
Функция percentFull находится на неверном уровне абстракции. Существует
много реализаций стека, в которых концепция заполнения выглядит разумно,
однако другие реализации могут не знать, до какой степени заполнен стек.
Следовательно, эта функция должна располагаться в производном интерфейсе —
например, BoundedStack.
Возможно, вы думаете, что для неограниченного стека реализация может просто
вернуть 0? Проблема в том, что абсолютно неограниченного стека не
существует. Вам не удастся предотвратить исключение OutOfMemoryException, проверив условие
<code class="brush:java">
stack.percentFull() < 50.0.
</code>
Если ваша реализация функции возвращает 0, то она попросту врет.
Суть в том, что ложь и фикции не способны компенсировать неверного
размещения абстракций. Разделение абстракций — одна из самых сложных задач,
решаемых разработчиками. Если выбор сделан неверно, не надейтесь, что вам
удастся найти простое обходное решение.
Самая распространенная причина для разбиения концепций на базовые и
производные классы состоит в том, чтобы концепции базового класса, относящиеся
к более высокому уровню, были независимы от низкоуровневых концепций
производных классов. Следовательно, когда в базовом классе встречаются
упоминания имен производных классов, значит, в проектировании что-то сделано
не так. В общем случае базовые классы не должны ничего знать о своих
производных классах.
Конечно, у этого правила имеются свои исключения. Иногда количество
производных классов жестко фиксировано, а в базовом классе присутствует код для
выбора между производными классами. Подобная ситуация часто встречается
в реализациях конечных автоматов. Однако в этом случае между базовым и
производными классами существует жесткая привязка, и они всегда размещаются
вместе в одном файле jar. В общем случае нам хотелось бы иметь возможность
размещения производных и базовых классов в разных файлах^/-.
Размещение производных и базовых классов в разных файлах jar, при котором
базовые файлы jar ничего не знают о содержимом производных файлов jar,
позволяет организовать развертывание систем в формате дискретных, независимых
компонентов. Если в такие компоненты будут внесены изменения, то они
развертываются заново без необходимости повторного развертывания базовых
компонентов. Такая архитектура значительно сокращает последствия от вносимых
изменений и упрощает сопровождение систем в условиях реальной эксплуатации.
Хорошо определенные модули обладают компактными интерфейсами,
позволяющими сделать много минимальными средствами. Для плохо определенных
модулей характерны широкие, глубокие интерфейсы, которые заставляют
пользователя выполнять много разных операций для решения простых задач. Хорошо
определенный интерфейс предоставляет относительно небольшое количество
функций, поэтому степень логической привязки при его использовании
относительно невелика. Плохо определенный интерфейс предоставляет множество
функций, которые необходимо вызывать, поэтому его использование сопряжено
с высокой степенью логической привязки.
Хорошие разработчики умеют ограничивать интерфейсы своих классов и
модулей. Чем меньше методов содержит класс, тем лучше. Чем меньше переменных
известно функции, тем лучше. Чем меньше переменных экземпляров содержит
класс, тем лучше.
Скрывайте свои данные. Скрывайте вспомогательные функции. Скрывайте
константы и временные переменные. Не создавайте классы с большим количеством
методов или переменных экземпляров. Не создавайте большого количества
защищенных переменных и функций в субклассах. Сосредоточьтесь на создании
очень компактных, концентрированных интерфейсов. Сокращайте логические
привязки за счет ограничения информации.
Мертвым кодом называется код, не выполняемый в ходе работы программы.
Он содержится в теле команды if, проверяющей невозможное условие. Он
содержится в секции catch для блока try, никогда не инициирующего исключения.
Он содержится в маленьких вспомогательных методах, которые никогда не
вызываются, или в никогда не встречающихся условиях switch/case.
Мертвый код плох тем, что спустя некоторое время он начинает «плохо пахнуть».
Чем древнее код, тем сильнее и резче запах. Дело в том, что мертвый код не
обновляется при изменении архитектуры. Он компилируется, но не соответствует
более новым конвенциям и правилам. Он был написан в то время, когда система
была другой. Обнаружив мертвый код, сделайте то, что положено делать в таких
случаях: достойно похороните его. Удалите его из системы.
<code class="brush:php">
$result = mysql_query("SHOW TABLE STATUS FROM db_name LIKE 'table_name'");
$row = mysql_fetch_array($result);
$nextId = $row['Auto_increment'];
mysql_free_result($result);
</code>
|Ctrl+T |Открытие новой вкладки|
|Ctrl+Shift+T |Повторное открытие последней закрытой вкладки. Chrome запоминает 10 последних закрытых вкладок.|
|Перетаскивание ссылки на вкладку |Открытие ссылки на указанной вкладке|
|Перетаскивание ссылки в место между вкладками |Открытие ссылки на новой вкладке в указанной позиции в области вкладок|
|Ctrl+1 - Ctrl+8 |Переключение на вкладку с указанным номером позиции. Нажимаемая цифра представляет позицию на панели вкладок.|
|Ctrl+9 |Переключение на последнюю вкладку|
|Ctrl+Tab |Переключение на следующую вкладку|
|Ctrl+Shift+Tab |Переключение на предыдущую вкладку|
|Ctrl+W или Ctrl+F4 |Закрытие текущей вкладки или всплывающего окна|
/***
|Name:|HideWhenPlugin|
|Description:|Allows conditional inclusion/exclusion in templates|
|Version:|3.1 ($Rev: 3919 $)|
|Date:|$Date: 2008-03-13 02:03:12 +1000 (Thu, 13 Mar 2008) $|
|Source:|http://mptw.tiddlyspot.com/#HideWhenPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
For use in ViewTemplate and EditTemplate. Example usage:
{{{<div macro="showWhenTagged Task">[[TaskToolbar]]</div>}}}
{{{<div macro="showWhen tiddler.modifier == 'BartSimpson'"><img src="bart.gif"/></div>}}}
***/
//{{{
window.hideWhenLastTest = false;
window.removeElementWhen = function(test,place) {
window.hideWhenLastTest = test;
if (test) {
removeChildren(place);
place.parentNode.removeChild(place);
}
};
merge(config.macros,{
hideWhen: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( eval(paramString), place);
}},
showWhen: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( !eval(paramString), place);
}},
hideWhenTagged: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( tiddler.tags.containsAll(params), place);
}},
showWhenTagged: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( !tiddler.tags.containsAll(params), place);
}},
hideWhenTaggedAny: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( tiddler.tags.containsAny(params), place);
}},
showWhenTaggedAny: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( !tiddler.tags.containsAny(params), place);
}},
hideWhenTaggedAll: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( tiddler.tags.containsAll(params), place);
}},
showWhenTaggedAll: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( !tiddler.tags.containsAll(params), place);
}},
hideWhenExists: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( store.tiddlerExists(params[0]) || store.isShadowTiddler(params[0]), place);
}},
showWhenExists: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( !(store.tiddlerExists(params[0]) || store.isShadowTiddler(params[0])), place);
}},
hideWhenTitleIs: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( tiddler.title == params[0], place);
}},
showWhenTitleIs: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( tiddler.title != params[0], place);
}},
'else': { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( !window.hideWhenLastTest, place);
}}
});
//}}}
http://www.splitbrain.org/blog/2008-12/24-setup_dokuwiki_on_free_hosting_in_less_than_15_minutes
http://stackoverflow.com/questions/611304/how-many-lines-of-code-should-a-function-procedure-method-have?lq=1
http://stackoverflow.com/questions/129599/best-rule-for-maximum-function-size
[[G30: Функции должны выполнять одну операцию]]
''Quotation from http://stackoverflow.com:''
It's not about lines of code. As Steve Mcconnell and Bob Martin say (two pretty good references on coding best practices), a method should do one thing and only one thing. However many lines of code it takes to do that one thing is how many lines it should have. If that "one thing" can be broken into smaller things, each of those should have a method.
Good clues your method is doing more than one thing:
* More than one level of indention in a method (indicates too many logic branches to only be doing one thing)
* "Paragraph Breaks" - whitespace between logical groups of code indicate the method is doing more than one thing
Just to name a few. Bob Martin also says to keep it around 10. Personally I usually try to shoot for 10. If it starts getting close to 20, that's a mental flag to pay closer attention to that method. But ultimately, LoC is a bad metric for pretty much anything. It is only a helpful indicator that can potentially point to the real issue.
<code class="">
ffmpeg -i music.m4a music.mp3
</code>
You need to use the \c escape sequence. So:
<code class="brush:">
/\ccopyright
</code>
<code class="brush:">
sudo find . -name '*.php' | xargs grep "some_function"
</code>
#http://vim.wikia.com/wiki/Maximize_or_set_initial_window_size
#use plugin for win32 - http://vim.sourceforge.net/scripts/script.php?script_id=1302
If you're editing it, you can reload it with:
<code class="brush:">
:so %
</code>
% stands for current file name (see :h current-file) and :so is short for :source, which reads the content of the specified file and treats it as Vim code.
In general, to re-load the currently active .vimrc, use the following (see Daily Vim):
<code class="brush:">
:so $MYVIMRC
</code>
[[Original|http://superuser.com/questions/132029/how-do-you-reload-your-vimrc-file-without-restarting-vim]]
* first way
<code class="brush:html">
<span style='cursor:pointer; text-decoration:underline; color:blue;' onclick="javascript: window.open()">Удалить объявление</span>;
</code>
* second
<code class="brush:html">
<a id="thislink" name="thislink" href="#thislink" onclick="showPopUp('dialog5');">Blended colors</a>
</code>
* third
<code class="brush:html">
<a name="thislink" href="#" onclick="showPopUp('dialog5');">Blended colors</a>
</code>
/***
|Name|InlineJavascriptPlugin|
|Source|http://www.TiddlyTools.com/#InlineJavascriptPlugin|
|Documentation|http://www.TiddlyTools.com/#InlineJavascriptPluginInfo|
|Version|1.9.6|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|Insert Javascript executable code directly into your tiddler content.|
''Call directly into TW core utility routines, define new functions, calculate values, add dynamically-generated TiddlyWiki-formatted output'' into tiddler content, or perform any other programmatic actions each time the tiddler is rendered.
!!!!!Documentation
>see [[InlineJavascriptPluginInfo]]
!!!!!Revisions
<<<
2010.12.15 1.9.6 allow (but ignore) type="..." syntax
|please see [[InlineJavascriptPluginInfo]] for additional revision details|
2005.11.08 1.0.0 initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.InlineJavascriptPlugin= {major: 1, minor: 9, revision: 6, date: new Date(2010,12,15)};
config.formatters.push( {
name: "inlineJavascript",
match: "\\<script",
lookahead: "\\<script(?: type=\\\"[^\\\"]*\\\")?(?: src=\\\"([^\\\"]*)\\\")?(?: label=\\\"([^\\\"]*)\\\")?(?: title=\\\"([^\\\"]*)\\\")?(?: key=\\\"([^\\\"]*)\\\")?( show)?\\>((?:.|\\n)*?)\\</script\\>",
handler: function(w) {
var lookaheadRegExp = new RegExp(this.lookahead,"mg");
lookaheadRegExp.lastIndex = w.matchStart;
var lookaheadMatch = lookaheadRegExp.exec(w.source)
if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
var src=lookaheadMatch[1];
var label=lookaheadMatch[2];
var tip=lookaheadMatch[3];
var key=lookaheadMatch[4];
var show=lookaheadMatch[5];
var code=lookaheadMatch[6];
if (src) { // external script library
var script = document.createElement("script"); script.src = src;
document.body.appendChild(script); document.body.removeChild(script);
}
if (code) { // inline code
if (show) // display source in tiddler
wikify("{{{\n"+lookaheadMatch[0]+"\n}}}\n",w.output);
if (label) { // create 'onclick' command link
var link=createTiddlyElement(w.output,"a",null,"tiddlyLinkExisting",wikifyPlainText(label));
var fixup=code.replace(/document.write\s*\(/gi,'place.bufferedHTML+=(');
link.code="function _out(place,tiddler){"+fixup+"\n};_out(this,this.tiddler);"
link.tiddler=w.tiddler;
link.onclick=function(){
this.bufferedHTML="";
try{ var r=eval(this.code);
if(this.bufferedHTML.length || (typeof(r)==="string")&&r.length)
var s=this.parentNode.insertBefore(document.createElement("span"),this.nextSibling);
if(this.bufferedHTML.length)
s.innerHTML=this.bufferedHTML;
if((typeof(r)==="string")&&r.length) {
wikify(r,s,null,this.tiddler);
return false;
} else return r!==undefined?r:false;
} catch(e){alert(e.description||e.toString());return false;}
};
link.setAttribute("title",tip||"");
var URIcode='javascript:void(eval(decodeURIComponent(%22(function(){try{';
URIcode+=encodeURIComponent(encodeURIComponent(code.replace(/\n/g,' ')));
URIcode+='}catch(e){alert(e.description||e.toString())}})()%22)))';
link.setAttribute("href",URIcode);
link.style.cursor="pointer";
if (key) link.accessKey=key.substr(0,1); // single character only
}
else { // run script immediately
var fixup=code.replace(/document.write\s*\(/gi,'place.innerHTML+=(');
var c="function _out(place,tiddler){"+fixup+"\n};_out(w.output,w.tiddler);";
try { var out=eval(c); }
catch(e) { out=e.description?e.description:e.toString(); }
if (out && out.length) wikify(out,w.output,w.highlightRegExp,w.tiddler);
}
}
w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
}
}
} )
//}}}
// // Backward-compatibility for TW2.1.x and earlier
//{{{
if (typeof(wikifyPlainText)=="undefined") window.wikifyPlainText=function(text,limit,tiddler) {
if(limit > 0) text = text.substr(0,limit);
var wikifier = new Wikifier(text,formatter,null,tiddler);
return wikifier.wikifyPlain();
}
//}}}
// // GLOBAL FUNCTION: $(...) -- 'shorthand' convenience syntax for document.getElementById()
//{{{
if (typeof($)=='undefined') { function $(id) { return document.getElementById(id.replace(/^#/,'')); } }
//}}}
<code class='brush:'>
sudo dpkg -i package.deb
</code>
/***
|Name:|InstantTimestampPlugin|
|Description:|A handy way to insert timestamps in your tiddler content|
|Version:|1.0.10 ($Rev: 3646 $)|
|Date:|$Date: 2008-02-27 02:34:38 +1000 (Wed, 27 Feb 2008) $|
|Source:|http://mptw.tiddlyspot.com/#InstantTimestampPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
!!Usage
If you enter {ts} in your tiddler content (without the spaces) it will be replaced with a timestamp when you save the tiddler. Full list of formats:
* {ts} or {t} -> timestamp
* {ds} or {d} -> datestamp
* !ts or !t at start of line -> !!timestamp
* !ds or !d at start of line -> !!datestamp
(I added the extra ! since that's how I like it. Remove it from translations below if required)
!!Notes
* Change the timeFormat and dateFormat below to suit your preference.
* See also http://mptw2.tiddlyspot.com/#AutoCorrectPlugin
* You could invent other translations and add them to the translations array below.
***/
//{{{
config.InstantTimestamp = {
// adjust to suit
timeFormat: 'DD/0MM/YY 0hh:0mm',
dateFormat: 'DD/0MM/YY',
translations: [
[/^!ts?$/img, "'!!{{ts{'+now.formatString(config.InstantTimestamp.timeFormat)+'}}}'"],
[/^!ds?$/img, "'!!{{ds{'+now.formatString(config.InstantTimestamp.dateFormat)+'}}}'"],
// thanks Adapted Cat
[/\{ts?\}(?!\}\})/ig,"'{{ts{'+now.formatString(config.InstantTimestamp.timeFormat)+'}}}'"],
[/\{ds?\}(?!\}\})/ig,"'{{ds{'+now.formatString(config.InstantTimestamp.dateFormat)+'}}}'"]
],
excludeTags: [
"noAutoCorrect",
"noTimestamp",
"html",
"CSS",
"css",
"systemConfig",
"systemConfigDisabled",
"zsystemConfig",
"Plugins",
"Plugin",
"plugins",
"plugin",
"javascript",
"code",
"systemTheme",
"systemPalette"
],
excludeTiddlers: [
"StyleSheet",
"StyleSheetLayout",
"StyleSheetColors",
"StyleSheetPrint"
// more?
]
};
TiddlyWiki.prototype.saveTiddler_mptw_instanttimestamp = TiddlyWiki.prototype.saveTiddler;
TiddlyWiki.prototype.saveTiddler = function(title,newTitle,newBody,modifier,modified,tags,fields,clearChangeCount,created) {
tags = tags ? tags : []; // just in case tags is null
tags = (typeof(tags) == "string") ? tags.readBracketedList() : tags;
var conf = config.InstantTimestamp;
if ( !tags.containsAny(conf.excludeTags) && !conf.excludeTiddlers.contains(newTitle) ) {
var now = new Date();
var trans = conf.translations;
for (var i=0;i<trans.length;i++) {
newBody = newBody.replace(trans[i][0], eval(trans[i][1]));
}
}
// TODO: use apply() instead of naming all args?
return this.saveTiddler_mptw_instanttimestamp(title,newTitle,newBody,modifier,modified,tags,fields,clearChangeCount,created);
}
// you can override these in StyleSheet
setStylesheet(".ts,.ds { font-style:italic; }","instantTimestampStyles");
//}}}
* [[Проверить Javascript код на ошибки|http://jslint.com/]]
* [[10 super useful tools for javascript developers|http://www.catswhocode.com/blog/10-super-useful-tools-for-javascript-developers]] и [[headjs|http://headjs.com]]
* [[Обработка форм на JavaScript|http://www.codeisart.ru/processing-forms-javascript/]]
* [[Javascript: Definition Guide|http://dl.dropbox.com/u/5332751/files/JavaScript.pdf]]
*http://joelonsoftware.com/
*http://russian.joelonsoftware.com/
*http://soundcloud.com/stack-exchange/sets/stack-exchange-podcasts/
Оказывается это он и его команда создали http://stackoverflow.com, вот такие дела
/***
|Name:|LessBackupsPlugin|
|Description:|Intelligently limit the number of backup files you create|
|Version:|3.0.1 ($Rev: 2320 $)|
|Date:|$Date: 2007-06-18 22:37:46 +1000 (Mon, 18 Jun 2007) $|
|Source:|http://mptw.tiddlyspot.com/#LessBackupsPlugin|
|Author:|Simon Baird|
|Email:|simon.baird@gmail.com|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
!!Description
You end up with just backup one per year, per month, per weekday, per hour, minute, and second. So total number won't exceed about 200 or so. Can be reduced by commenting out the seconds/minutes/hours line from modes array
!!Notes
Works in IE and Firefox only. Algorithm by Daniel Baird. IE specific code by by Saq Imtiaz.
***/
//{{{
var MINS = 60 * 1000;
var HOURS = 60 * MINS;
var DAYS = 24 * HOURS;
if (!config.lessBackups) {
config.lessBackups = {
// comment out the ones you don't want or set config.lessBackups.modes in your 'tweaks' plugin
modes: [
["YYYY", 365*DAYS], // one per year for ever
["MMM", 31*DAYS], // one per month
["ddd", 7*DAYS], // one per weekday
//["d0DD", 1*DAYS], // one per day of month
["h0hh", 24*HOURS], // one per hour
["m0mm", 1*HOURS], // one per minute
["s0ss", 1*MINS], // one per second
["latest",0] // always keep last version. (leave this).
]
};
}
window.getSpecialBackupPath = function(backupPath) {
var now = new Date();
var modes = config.lessBackups.modes;
for (var i=0;i<modes.length;i++) {
// the filename we will try
var specialBackupPath = backupPath.replace(/(\.)([0-9]+\.[0-9]+)(\.html)$/,
'$1'+now.formatString(modes[i][0]).toLowerCase()+'$3')
// open the file
try {
if (config.browser.isIE) {
var fsobject = new ActiveXObject("Scripting.FileSystemObject")
var fileExists = fsobject.FileExists(specialBackupPath);
if (fileExists) {
var fileObject = fsobject.GetFile(specialBackupPath);
var modDate = new Date(fileObject.DateLastModified).valueOf();
}
}
else {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
file.initWithPath(specialBackupPath);
var fileExists = file.exists();
if (fileExists) {
var modDate = file.lastModifiedTime;
}
}
}
catch(e) {
// give up
return backupPath;
}
// expiry is used to tell if it's an 'old' one. Eg, if the month is June and there is a
// June file on disk that's more than an month old then it must be stale so overwrite
// note that "latest" should be always written because the expiration period is zero (see above)
var expiry = new Date(modDate + modes[i][1]);
if (!fileExists || now > expiry)
return specialBackupPath;
}
}
// hijack the core function
window.getBackupPath_mptw_orig = window.getBackupPath;
window.getBackupPath = function(localPath) {
return getSpecialBackupPath(getBackupPath_mptw_orig(localPath));
}
//}}}
/***
|''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);
}
//}}}
https://github.com/downloads/drakulavich/russian-mc-cheatsheet/rmc.pdf
''Function keys''
|Клавиша |Активность |h
|F1 |Help|
|F2 |Opens user menu|
|F3 |View selected file content|
|F4 |Opens file in internal text editor|
|F5 |Copies selected file. Default is to another panel, but it asks first|
|F6 |Moving file. Default is to another panel, but it asks first|
|F7 |Make directory|
|F8 |Delete file or directory|
|F9 |Opens main menu at the top of the screen|
|F10 |Ends current action; editor, viewer, dialog window or ends mc program.|
|shift-F4 |Create file|
''Структура''
|Комбинация |Активность |h
|Tab, Ctrl + i |сменить текущую (активную) панель|
|Insert, Ctrl + t |отметить файл либо снять отметку|
|Alt + g Alt + r Alt + j |подсветка верхнего, среднего или нижнего файла из числа отображаемых на панели|
|Alt + t |переключить режим отображения|
|Ctrl + \ |показать «Справочник каталогов»|
|+ |выбрать (отметить) группу файлов по регулярному выражению|
|\ |снять отметку с группы файлов|
|Alt + o |если выделен каталог, установить его текущим в неактивной панели. Иначе, установить родительский каталог текущим.|
|Alt + i |текущий каталог активной панели станет текущим каталогом неактивной панели|
|Alt + y |к предыдущему каталогу из истории перемещения|
|Alt + u |к следующему каталогу из истории перемещения|
|Alt + H |отображает историю перемещения по каталогам|
|Alt + e |поменять кодировку панели|
|Alt + . |отобразить скрытые файлы|
|Alt + , |расположить панели вертикально/горизонтально|
|Ctrl + u |поменять панели местами|
''Разные комманды''
|Комбинация |Активность |h
|Ctrl + l |перерисовать экран|
|Ctrl + x c |поменять права (chmod) для отмеченных файлов|
|Ctrl + x o |поменять владельца (chown) для отмеченных файлов|
|Ctrl + x l |создать жёсткую ссылку|
|Ctrl + x s |создать абсолютную символическую ссылку|
|Ctrl + x v |создать относительную символическую ссылку|
|Ctrl + x i |переводит пассивную панель в режим «Информация»|
|Ctrl + x q |переводит пассивную панель в режим быстрого просмотра|
|Ctrl + x ! |меню → «Критерий панелизации»|
|Ctrl + x h |добавить имя каталога в «Справочник каталогов»|
|Alt + ! |меню → «Просмотр вывода команды»|
|Alt + ? |окно «Поиск файла»|
|Alt + c |окно «Быстрая смена каталога»|
|Ctrl + o |скрыть/показать панели|
|Ctrl + Space |подсчёт размера каталога|
|Ctrl + r |перечитать содержимое каталога|
|Ctrl + x j |показать фоновые задания|
|Ctrl + x d |сравнить каталоги|
|Ctrl + x, Ctrl + d |сравнить файлы|
|Shift + F6 |переименовать файл|
|Ctrl/Alt + s |режим быстрого поиска|
''Командная строка оболочки''
|Комбинация |Активность |h
|Ctrl/Alt + Enter |копирует подсвеченное имя файла в командную строку|
|Alt + Tab |пытается выполнить операцию Завершение ввода|
|Ctrl + x t, Ctrl + x Ctrl + t |копирует в командную строку имена помеченных файлов из активной/пассивной панели|
|Ctrl + x p, Ctrl + x Ctrl + p |копирует в командную строку имя текущего каталога из активной/пассивной панели|
|Ctrl + q |вставить символы, которые интерпретируются mc (пример: +)|
|Alt + p, Alt + n |перемещение по истории команд|
|Alt + h |выводит историю текущей строки ввода (историю команд)|
|Ctrl + V |вставка из буфера обмена|
MPTW is a distribution or edition of TiddlyWiki that includes a standard TiddlyWiki core packaged with some plugins designed to improve usability and provide a better way to organise your information. For more information see http://mptw.tiddlyspot.com/.
[[Building Mingw executables using Cygwin|http://www.delorie.com/howto/cygwin/mno-cygwin-howto.html]]
Чтобы, работая в cygwin через терминал, создавать на c++ программы под Windows, нужно:
#создать, например, каталог /win (внутри среды cygwin)
#установить туда MinGW (просто запустить в Windows gui-установщик, в качестве пути установки указать <путь к cygwin>/win/MinGW)
#добавить в cygwin-PATH путь к MinGW:
<code class="">
PATH=$PATH:/win/MinGW/bin/
</code>
''svn directory move example''
Suppose you have a directory named foo, and you want to rename it to bar. The svn move command to issue is:
<code class="brush:">
svn move foo bar
</code>
After moving the directory you'll then want to commit the change. You can either do this now, or some time later, but assuming you want to do it now, you can commit the move with this svn commit command:
<code class="brush:">
svn commit --message "Moved foo to bar because (explanation here)"
</code>
''svn move example #2''
To make our SVN directory move example a little harder, let's assume that you want to move foo up one level in the directory tree. Just issue these commands instead:
<code class="brush:">
svn move foo ../bar
cd ..
svn commit --message "Moved foo to bar because (explanation here)"
</code>
''Links''
http://stackoverflow.com/questions/3941291/a-sane-way-to-rename-a-directory-in-subversion-working-copy
Name: MptwBlack
Background: #000
Foreground: #fff
PrimaryPale: #333
PrimaryLight: #555
PrimaryMid: #888
PrimaryDark: #aaa
SecondaryPale: #111
SecondaryLight: #222
SecondaryMid: #555
SecondaryDark: #888
TertiaryPale: #222
TertiaryLight: #666
TertiaryMid: #888
TertiaryDark: #aaa
Error: #300
Name: MptwBlue
Background: #fff
Foreground: #000
PrimaryPale: #cdf
PrimaryLight: #57c
PrimaryMid: #114
PrimaryDark: #012
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
(function($){
merge(config.macros,{
mptwCollapse: {
handler: function(place,macroName,params) {
createTiddlyButton(place, params[0] == '+' ? '\u25AD' : '\u25AC', 'collapse/uncollapse', function(){
$(story.findContainingTiddler(place)).toggleClass('collapsed');
});
}
}
});
/* this doesn't work unless you have a modified ViewTempate */
config.shadowTiddlers["MptwCollapsePluginStyles"] = ""
+".collapsed .uncollapsedView { display:none; }"
+".collapsedView { display:none; }"
+".collapsed .collapsedView { display:block; }"
+".tiddler.collapsed { padding-bottom:1em; }"
+".tiddler.collapsed .title { font-size:100%; }"
;
store.addNotification("MptwCollapsePluginStyles",refreshStyles);
})(jQuery);
/***
|Name:|MptwConfigPlugin|
|Description:|Miscellaneous tweaks used by MPTW|
|Version:|1.0 ($Rev: 3646 $)|
|Date:|$Date: 2008-02-27 02:34:38 +1000 (Wed, 27 Feb 2008) $|
|Source:|http://mptw.tiddlyspot.com/#MptwConfigPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#MptwConfigPlugin|
!!Note: instead of editing this you should put overrides in MptwUserConfigPlugin
***/
//{{{
var originalReadOnly = readOnly;
var originalShowBackstage = showBackstage;
config.options.chkHttpReadOnly = false; // means web visitors can experiment with your site by clicking edit
readOnly = false; // needed because the above doesn't work any more post 2.1 (??)
showBackstage = true; // show backstage for same reason
config.options.chkInsertTabs = true; // tab inserts a tab when editing a tiddler
config.views.wikified.defaultText = ""; // don't need message when a tiddler doesn't exist
config.views.editor.defaultText = ""; // don't need message when creating a new tiddler
config.options.chkSaveBackups = true; // do save backups
config.options.txtBackupFolder = 'twbackup'; // put backups in a backups folder
config.options.chkAutoSave = (window.location.protocol == "file:"); // do autosave if we're in local file
config.mptwVersion = "2.5.3";
config.macros.mptwVersion={handler:function(place){wikify(config.mptwVersion,place);}};
if (config.options.txtTheme == '')
config.options.txtTheme = 'MptwTheme';
// add to default GettingStarted
config.shadowTiddlers.GettingStarted += "\n\nSee also [[MPTW]].";
// add select theme and palette controls in default OptionsPanel
config.shadowTiddlers.OptionsPanel = config.shadowTiddlers.OptionsPanel.replace(/(\n\-\-\-\-\nAlso see \[\[AdvancedOptions\]\])/, "{{select{<<selectTheme>>\n<<selectPalette>>}}}$1");
// these are used by ViewTemplate
config.mptwDateFormat = 'DD/MM/YY';
config.mptwJournalFormat = 'Journal DD/MM/YY';
//}}}
Name: MptwGreen
Background: #fff
Foreground: #000
PrimaryPale: #9b9
PrimaryLight: #385
PrimaryMid: #031
PrimaryDark: #020
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
Name: MptwRed
Background: #fff
Foreground: #000
PrimaryPale: #eaa
PrimaryLight: #c55
PrimaryMid: #711
PrimaryDark: #500
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
|Name|MptwRounded|
|Description|Mptw Theme with some rounded corners (Firefox only)|
|ViewTemplate|MptwTheme##ViewTemplate|
|EditTemplate|MptwTheme##EditTemplate|
|PageTemplate|MptwTheme##PageTemplate|
|StyleSheet|##StyleSheet|
!StyleSheet
/*{{{*/
[[MptwTheme##StyleSheet]]
.tiddler,
.sliderPanel,
.button,
.tiddlyLink,
.tabContents
{ -moz-border-radius: 1em; }
.tab {
-moz-border-radius-topleft: 0.5em;
-moz-border-radius-topright: 0.5em;
}
#topMenu {
-moz-border-radius-bottomleft: 2em;
-moz-border-radius-bottomright: 2em;
}
/*}}}*/
Name: MptwSmoke
Background: #fff
Foreground: #000
PrimaryPale: #aaa
PrimaryLight: #777
PrimaryMid: #111
PrimaryDark: #000
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
|Name|MptwStandard|
|Description|Mptw Theme with the default TiddlyWiki PageLayout and Styles|
|ViewTemplate|MptwTheme##ViewTemplate|
|EditTemplate|MptwTheme##EditTemplate|
Name: MptwTeal
Background: #fff
Foreground: #000
PrimaryPale: #B5D1DF
PrimaryLight: #618FA9
PrimaryMid: #1a3844
PrimaryDark: #000
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #f8f8f8
TertiaryLight: #bbb
TertiaryMid: #999
TertiaryDark: #888
Error: #f88
|Name|MptwTheme|
|Description|Mptw Theme including custom PageLayout|
|PageTemplate|##PageTemplate|
|ViewTemplate|##ViewTemplate|
|EditTemplate|##EditTemplate|
|StyleSheet|##StyleSheet|
http://mptw.tiddlyspot.com/#MptwTheme ($Rev: 1829 $)
!PageTemplate
<!--{{{-->
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<!-- horizontal MainMenu -->
<div id='topMenu' refresh='content' tiddler='MainMenu'></div>
<!-- original MainMenu menu -->
<!-- <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>
<!--}}}-->
!ViewTemplate
<!--{{{-->
<div class="uncollapsedView">
[[MptwTheme##ViewTemplateToolbar]]
<div class="tagglyTagged" macro="tags"></div>
<div class='titleContainer'>
<span class='title' macro='view title'></span>
<span macro="miniTag"></span>
</div>
<div class='subtitle'>
(updated <span macro='view modified date {{config.mptwDateFormat?config.mptwDateFormat:"MM/0DD/YY"}}'></span>
by <span macro='view modifier link'></span>)
<!--
(<span macro='message views.wikified.createdPrompt'></span>
<span macro='view created date {{config.mptwDateFormat?config.mptwDateFormat:"MM/0DD/YY"}}'></span>)
-->
</div>
<div macro="showWhen tiddler.tags.containsAny(['css','html','pre','systemConfig']) && !tiddler.text.match('{{'+'{')">
<div class='viewer'><pre macro='view text'></pre></div>
</div>
<div macro="else">
<div class='viewer' macro='view text wikified'></div>
</div>
<div class="tagglyTagging" macro="tagglyTagging"></div>
</div>
<div class="collapsedView">
<span class='toolbar'>
<span macro='toolbar closeTiddler'></span>
<span macro='mptwCollapse +'></span>
</span>
<span class='title' macro='view title'></span>
</div>
<!--}}}-->
!ViewTemplateToolbar
<!--{{{-->
<div class='toolbar'>
<span macro="showWhenTagged systemConfig">
<span macro="toggleTag systemConfigDisable . '[[disable|systemConfigDisable]]'"></span>
</span>
<span macro="showWhenTagged systemTheme"><span macro="applyTheme"></span></span>
<span macro="showWhenTagged systemPalette"><span macro="applyPalette"></span></span>
<span macro="showWhen tiddler.tags.contains('css') || tiddler.title == 'StyleSheet'"><span macro="refreshAll"></span></span>
<span style="padding:1em;"></span>
<span macro='toolbar closeTiddler closeOthers +editTiddler deleteTiddler > fields syncing permalink references jump'></span> <span macro='newHere label:"new here"'></span>
<span macro='newJournalHere {{config.mptwJournalFormat?config.mptwJournalFormat:"MM/0DD/YY"}}'></span>
<!--span macro='mptwCollapse -'></span-->
</div>
<!--}}}-->
!EditTemplate
<!--{{{-->
<div class="toolbar" macro="toolbar +saveTiddler saveCloseTiddler closeOthers -cancelTiddler cancelCloseTiddler deleteTiddler"></div>
<div class="title" macro="view title"></div>
<div class="editLabel">Title</div><div class="editor" macro="edit title"></div>
<div macro='annotations'></div>
<div class="editLabel">Content</div><div class="editor" macro="edit text"></div>
<div class="editLabel">Tags</div><div class="editor" macro="edit tags"></div>
<div class="editorFooter"><span macro="message views.editor.tagPrompt"></span><span macro="tagChooser"></span></div>
<!--}}}-->
!StyleSheet
/*{{{*/
/* a contrasting background so I can see where one tiddler ends and the other begins */
body {
background: [[ColorPalette::TertiaryLight]];
}
/* sexy colours and font for the header */
.headerForeground {
color: [[ColorPalette::PrimaryPale]];
}
.headerShadow, .headerShadow a {
color: [[ColorPalette::PrimaryMid]];
}
/* separate the top menu parts */
.headerForeground, .headerShadow {
padding: 1em 1em 0;
}
.headerForeground, .headerShadow {
font-family: 'Trebuchet MS', sans-serif;
font-weight:bold;
}
.headerForeground .siteSubtitle {
color: [[ColorPalette::PrimaryLight]];
}
.headerShadow .siteSubtitle {
color: [[ColorPalette::PrimaryMid]];
}
/* make shadow go and down right instead of up and left */
.headerShadow {
left: 1px;
top: 1px;
}
/* prefer monospace for editing */
.editor textarea, .editor input {
font-family: 'Consolas', monospace;
background-color:[[ColorPalette::TertiaryPale]];
}
/* sexy tiddler titles */
.title {
font-size: 250%;
color: [[ColorPalette::PrimaryLight]];
font-family: 'Trebuchet MS', sans-serif;
}
/* more subtle tiddler subtitle */
.subtitle {
padding:0px;
margin:0px;
padding-left:1em;
font-size: 90%;
color: [[ColorPalette::TertiaryMid]];
}
.subtitle .tiddlyLink {
color: [[ColorPalette::TertiaryMid]];
}
/* a little bit of extra whitespace */
.viewer {
padding-bottom:3px;
}
/* don't want any background color for headings */
h1,h2,h3,h4,h5,h6 {
background-color: transparent;
color: [[ColorPalette::Foreground]];
}
/* give tiddlers 3d style border and explicit background */
.tiddler {
background: [[ColorPalette::Background]];
border-right: 2px [[ColorPalette::TertiaryMid]] solid;
border-bottom: 2px [[ColorPalette::TertiaryMid]] solid;
margin-bottom: 1em;
padding:1em 2em 2em 1.5em;
}
/* make options slider look nicer */
#sidebarOptions .sliderPanel {
border:solid 1px [[ColorPalette::PrimaryLight]];
}
/* the borders look wrong with the body background */
#sidebar .button {
border-style: none;
}
/* this means you can put line breaks in SidebarOptions for readability */
#sidebarOptions br {
display:none;
}
/* undo the above in OptionsPanel */
#sidebarOptions .sliderPanel br {
display:inline;
}
/* horizontal main menu stuff */
#displayArea {
margin: 1em 15.7em 0em 1em; /* use the freed up space */
}
#topMenu br {
display: none;
}
#topMenu {
background: [[ColorPalette::PrimaryMid]];
color:[[ColorPalette::PrimaryPale]];
}
#topMenu {
padding:2px;
}
#topMenu .button, #topMenu .tiddlyLink, #topMenu a {
margin-left: 0.5em;
margin-right: 0.5em;
padding-left: 3px;
padding-right: 3px;
color: [[ColorPalette::PrimaryPale]];
font-size: 115%;
}
#topMenu .button:hover, #topMenu .tiddlyLink:hover {
background: [[ColorPalette::PrimaryDark]];
}
/* make 2.2 act like 2.1 with the invisible buttons */
.toolbar {
visibility:hidden;
}
.selected .toolbar {
visibility:visible;
}
/* experimental. this is a little borked in IE7 with the button
* borders but worth it I think for the extra screen realestate */
.toolbar { float:right; }
/* fix for TaggerPlugin. from sb56637. improved by FND */
.popup li .tagger a {
display:inline;
}
/* makes theme selector look a little better */
#sidebarOptions .sliderPanel .select .button {
padding:0.5em;
display:block;
}
#sidebarOptions .sliderPanel .select br {
display:none;
}
/* make it print a little cleaner */
@media print {
#topMenu {
display: none ! important;
}
/* not sure if we need all the importants */
.tiddler {
border-style: none ! important;
margin:0px ! important;
padding:0px ! important;
padding-bottom:2em ! important;
}
.tagglyTagging .button, .tagglyTagging .hidebutton {
display: none ! important;
}
.headerShadow {
visibility: hidden ! important;
}
.tagglyTagged .quickopentag, .tagged .quickopentag {
border-style: none ! important;
}
.quickopentag a.button, .miniTag {
display: none ! important;
}
}
/* get user styles specified in StyleSheet */
[[StyleSheet]]
/*}}}*/
|Name|MptwTrim|
|Description|Mptw Theme with a reduced header to increase useful space|
|ViewTemplate|MptwTheme##ViewTemplate|
|EditTemplate|MptwTheme##EditTemplate|
|StyleSheet|MptwTheme##StyleSheet|
|PageTemplate|##PageTemplate|
!PageTemplate
<!--{{{-->
<!-- horizontal MainMenu -->
<div id='topMenu' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<span refresh='content' tiddler='SiteTitle' style="padding-left:1em;font-weight:bold;"></span>:
<span refresh='content' tiddler='MainMenu'></span>
</div>
<div id='sidebar'>
<div id='sidebarOptions'>
<div refresh='content' tiddler='SideBarOptions'></div>
<div style="margin-left:0.1em;"
macro='slider chkTabSliderPanel SideBarTabs {{"tabs \u00bb"}} "Show Timeline, All, Tags, etc"'></div>
</div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
For upgrading. See [[ImportTiddlers]].
URL: http://mptw.tiddlyspot.com/upgrade.html
/***
|Description:|A place to put your config tweaks so they aren't overwritten when you upgrade MPTW|
See http://www.tiddlywiki.org/wiki/Configuration_Options for other options you can set. In some cases where there are clashes with other plugins it might help to rename this to zzMptwUserConfigPlugin so it gets executed last.
***/
//{{{
// example: set your preferred date format
//config.mptwDateFormat = 'MM/0DD/YY';
//config.mptwJournalFormat = 'Journal MM/0DD/YY';
// example: set the theme you want to start with
//config.options.txtTheme = 'MptwRoundTheme';
// example: switch off autosave, switch on backups and set a backup folder
//config.options.chkSaveBackups = true;
//config.options.chkAutoSave = false;
//config.options.txtBackupFolder = 'backups';
// uncomment to disable 'new means new' functionality for the new journal macro
//config.newMeansNewForJournalsToo = false;
//}}}
*[[Using MyISAM in production|http://www.mysqlperformanceblog.com/2006/06/17/using-myisam-in-production/]]
One of the most basic optimizations is to design your tables to take as little space on the disk as possible. This can result in huge improvements because disk reads are faster, and smaller tables normally require less main memory while their contents are being actively processed during query execution. Indexing also is a lesser resource burden if done on smaller columns.
MySQL supports many different storage engines (table types) and row formats. For each table, you can decide which storage and indexing method to use. Choosing the proper table format for your application may give you a big performance gain.
''Итак, ОПТИМИЗАЦИЯ БД MySQL это:''
1. __Проектировать таблицы так, чтобы они занимали как можно меньше места__
2. __Правильное индексирование столбцов (для каких столбцов нужны индексы и каких типов)__
3. __Выбор подходящего движка хранения и формата строк.__
''Шаг 1. Проектировать таблицы так, чтобы они занимали как можно меньше места.''
You can get better performance for a table and minimize storage space by using the techniques listed here:
- Use the most efficient (smallest) data types possible. MySQL has many specialized types that save disk space and memory. For example, use the smaller integer types if possible to get smaller tables. MEDIUMINT is often a better choice than INT because a MEDIUMINT column uses 25% less space.
- Declare columns to be NOT NULL if possible. It makes everything faster and you save one bit per column. If you really need NULL in your application, you should definitely use it. Just avoid having it on all columns by default.
- For MyISAM tables, if you do not have any variable-length columns (VARCHAR, TEXT, or BLOB columns), a fixed-size row format is used. This is faster but unfortunately may waste some space. See Section 13.1.3, “MyISAM Table Storage Formats”. You can hint that you want to have fixed length rows even if you have VARCHAR columns with the CREATE TABLE option ROW_FORMAT=FIXED.
- Starting with MySQL 5.0.3, InnoDB tables use a more compact storage format. In earlier versions of MySQL, InnoDB rows contain some redundant information, such as the number of columns and the length of each column, even for fixed-size columns. By default, tables are created in the compact format (ROW_FORMAT=COMPACT). If you wish to downgrade to older versions of MySQL, you can request the old format with ROW_FORMAT=REDUNDANT.
- The presence of the compact row format decreases row storage space by about 20% at the cost of increasing CPU use for some operations. If your workload is a typical one that is limited by cache hit rates and disk speed it is likely to be faster. If it is a rare case that is limited by CPU speed, it might be slower.
- The compact InnoDB format also changes how CHAR columns containing UTF-8 data are stored. With ROW_FORMAT=REDUNDANT, a UTF-8 CHAR(N) occupies 3 Ч N bytes, given that the maximum length of a UTF-8 encoded character is three bytes. Many languages can be written primarily using single-byte UTF-8 characters, so a fixed storage length often wastes space. With ROW_FORMAT=COMPACT format, InnoDB allocates a variable amount of storage in the range from N to 3 Ч N bytes for these columns by stripping trailing spaces if necessary. The minimum storage length is kept as N bytes to facilitate in-place updates in typical cases.
- The primary index of a table should be as short as possible. This makes identification of each row easy and efficient.
- Create only the indexes that you really need. Indexes are good for retrieval but bad when you need to store data quickly. If you access a table mostly by searching on a combination of columns, create an index on them. The first part of the index should be the column most used. If you always use many columns when selecting from the table, the first column in the index should be the one with the most duplicates to obtain better compression of the index.
- If it is very likely that a string column has a unique prefix on the first number of characters, it is better to index only this prefix, using MySQL's support for creating an index on the leftmost part of the column (see Section 12.1.8, “CREATE INDEX Syntax”). Shorter indexes are faster, not only because they require less disk space, but because they also give you more hits in the index cache, and thus fewer disk seeks. See Section 7.5.3, “Tuning Server Parameters”.
- In some circumstances, it can be beneficial to split into two a table that is scanned very often. This is especially true if it is a dynamic-format table and it is possible to use a smaller static format table that can be used to find the relevant rows when scanning the table.
''Шаг 2. Правильное индексирование столбцов (для каких столбцов нужны индексы и каких типов).''
''Шаг 3. Выбор подходящего движка хранения и формата строк.''
http://www.greenmice.info/ru/node/106 -- нужно ли переходить с MyISAM на InnoDb ?
Notes on Storage Engines: some key factors that are relevant to schema design.
''======================= The MyISAM Storage Engine ==============''
- __Table locks__
MyISAM tables have table-level locks. Be careful this doesn’t become a
bottleneck.
- __No automated data recovery__
If the MySQL server crashes or power goes down, you should check and possibly
repair your MyISAM tables before using them. If you have large tables, this
could take hours.
- __No transactions__
MyISAM tables don’t support transactions. In fact, MyISAM doesn’t even guarantee
that a single statement will complete; if there’s an error halfway through a
multirow UPDATE, for example, some of the rows will be updated and some
won’t.
- __Only indexes are cached in memory__
MyISAM caches only the index inside the MySQL process, in the key buffer. The
operating system caches the table’s data, so in MySQL 5.0 an expensive operating
system call is required to retrieve it.
- __Compact storage__
Rows are stored jam-packed one after another, so you get a small disk footprint
and fast full table scans for on-disk data.
''===================== The InnoDB Storage Engine ======================''
- __Transactional__
InnoDB supports transactions and four transaction isolation levels.
- __Foreign keys__
As of MySQL 5.0, InnoDB is the only stock storage engine that supports foreign
keys. Other storage engines will accept them in CREATE TABLE statements, but
won’t enforce them. Some third-party engines, such as solidDB for MySQL and
PBXT, support them at the storage engine level too; MySQL AB plans to add
support at the server level in the future.
- __Row-level locks__
Locks are set at the row level, with no escalation and nonblocking selects—standard
selects don’t set any locks at all, which gives very good concurrency.
- __Multiversioning__
InnoDB uses multiversion concurrency control, so by default your selects may
read stale data. In fact, its MVCC architecture adds a lot of complexity and possibly
unexpected behaviors. You should read the InnoDB manual thoroughly if
you use InnoDB.
- __Clustering by primary key__
All InnoDB tables are clustered by the primary key, which you can use to your
advantage in schema design.
All indexes contain the primary key columns
Indexes refer to the rows by the primary key, so if you don’t keep your primary
key short, the indexes will grow very large.
- __Optimized caching__
InnoDB caches both data and memory in the buffer pool. It also automatically
builds hash indexes to speed up row retrieval.
- __Unpacked indexes__
Indexes are not packed with prefix compression, so they can be much larger
than for MyISAM tables.
- __Slow data load__
As of MySQL 5.0, InnoDB does not specially optimize data load operations. It
builds indexes a row at a time, instead of building them by sorting. This may
result in significantly slower data loads.
- __Blocking AUTO_INCREMENT__
In versions earlier than MySQL 5.1, InnoDB uses a table-level lock to generate
each new AUTO_INCREMENT value.
- __No cached COUNT(*) value__
Unlike MyISAM or Memory tables, InnoDB tables don’t store the number of
rows in the table, which means COUNT(*) queries without a WHERE clause can’t be
optimized away and require full table or index scans. See“Optimizing COUNT()
Queries” on page 188 for more on this topic.
[[Download|http://www.vim.org/scripts/script.php?script_id=1658]]
Similar to netrw browser but looks more like a hierarchical explorer. It does not support remote file operations.
''повесим на F2 показать/скрыть NERDTree для директории данного(редактируемого) файла''
<code class="">
:map <F2> :NERDTreeToggle %:p<CR>
</code>
|Hotkey |Action |h
|r |If a dir is selected, recursively refresh that dir|
|R |Recursively refresh the tree root|
|m a |add node|
|m d |delete current node|
use [[Path tools|http://plugins.netbeans.org/PluginPortal/faces/PluginDetailPage.jsp?pluginid=676]] that provides:
*Copy Paths,
*Explore,
*Shell
*External Edit
actions.
''Beats all the VIM Plugins…''
… because you can use the one and only original Vim. Use
>cmd /C start path to vim\gvim.exe -g """--servername project-name --"""remote-silent "{path}"
to start. That way all files will be opened by the same vim server instance. On Mac OS and Linux you won't need the cmd stuff as vim will spawn itself into the background.
http://netbeans.org/kb/trails/php.html
/***
|Name:|NewHerePlugin|
|Description:|Creates the new here and new journal macros|
|Version:|3.0 ($Rev: 3861 $)|
|Date:|$Date: 2008-03-08 10:53:09 +1000 (Sat, 08 Mar 2008) $|
|Source:|http://mptw.tiddlyspot.com/#NewHerePlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License|http://mptw.tiddlyspot.com/#TheBSDLicense|
***/
//{{{
merge(config.macros, {
newHere: {
handler: function(place,macroName,params,wikifier,paramString,tiddler) {
wikify("<<newTiddler "+paramString+" tag:[["+tiddler.title+"]]>>",place,null,tiddler);
}
},
newJournalHere: {
handler: function(place,macroName,params,wikifier,paramString,tiddler) {
wikify("<<newJournal "+paramString+" tag:[["+tiddler.title+"]]>>",place,null,tiddler);
}
}
});
//}}}
/***
|Name:|NewMeansNewPlugin|
|Description:|If 'New Tiddler' already exists then create 'New Tiddler (1)' and so on|
|Version:|1.1.1 ($Rev: 2263 $)|
|Date:|$Date: 2007-06-13 04:22:32 +1000 (Wed, 13 Jun 2007) $|
|Source:|http://mptw.tiddlyspot.com/empty.html#NewMeansNewPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License|http://mptw.tiddlyspot.com/#TheBSDLicense|
!!Note: I think this should be in the core
***/
//{{{
// change this or set config.newMeansNewForJournalsToo it in MptwUuserConfigPlugin
if (config.newMeansNewForJournalsToo == undefined) config.newMeansNewForJournalsToo = true;
String.prototype.getNextFreeName = function() {
numberRegExp = / \(([0-9]+)\)$/;
var match = numberRegExp.exec(this);
if (match) {
var num = parseInt(match[1]) + 1;
return this.replace(numberRegExp," ("+num+")");
}
else {
return this + " (1)";
}
}
config.macros.newTiddler.checkForUnsaved = function(newName) {
var r = false;
story.forEachTiddler(function(title,element) {
if (title == newName)
r = true;
});
return r;
}
config.macros.newTiddler.getName = function(newName) {
while (store.getTiddler(newName) || config.macros.newTiddler.checkForUnsaved(newName))
newName = newName.getNextFreeName();
return newName;
}
config.macros.newTiddler.onClickNewTiddler = function()
{
var title = this.getAttribute("newTitle");
if(this.getAttribute("isJournal") == "true") {
title = new Date().formatString(title.trim());
}
// ---- these three lines should be the only difference between this and the core onClickNewTiddler
if (config.newMeansNewForJournalsToo || this.getAttribute("isJournal") != "true")
title = config.macros.newTiddler.getName(title);
var params = this.getAttribute("params");
var tags = params ? params.split("|") : [];
var focus = this.getAttribute("newFocus");
var template = this.getAttribute("newTemplate");
var customFields = this.getAttribute("customFields");
if(!customFields && !store.isShadowTiddler(title))
customFields = String.encodeHashMap(config.defaultCustomFields);
story.displayTiddler(null,title,template,false,null,null);
var tiddlerElem = story.getTiddler(title);
if(customFields)
story.addCustomFields(tiddlerElem,customFields);
var text = this.getAttribute("newText");
if(typeof text == "string")
story.getTiddlerField(title,"text").value = text.format([title]);
for(var t=0;t<tags.length;t++)
story.setTiddlerTag(title,tags[t],+1);
story.focusTiddler(title,focus);
return false;
};
//}}}
Shift-Enter
открыть виндовое окно текущей директории
In my case, the problem was caused by deleting the connection with orphaned document changes.
The solution for OpenSuse Linux:
Locate ~/.mysql/workbench/sql_workspaces/your connection name.autosave directory
Delete it.
As simple as that.
*http://zmievski.org/talks/
http://stackoverflow.com/questions/393603/php-uml-generator
http://habrahabr.ru/blogs/php/69744/ -- DooPHP фрэймворк
PHP фрэймворки
With page content
<code class="brush:">
time curl http://www.drom.ru/ > /dev/null
</code>
<code class="brush:">
real 0m2.266s
user 0m0.008s
sys 0m0.000s
</code>
Without page content (time of headers receiving):
<code class="brush:">
time curl -I http://www.drom.ru/ > /dev/null
</code>
<code class="brush:">
real 0m0.318s
user 0m0.000s
sys 0m0.008s
</code>
<!--{{{-->
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>
<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>
<!--}}}-->
/***
|''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"
});
*/
//}}}
*http://v673.com/personalities/paul-graham/ на русском
/***
|Name:|PrettyDatesPlugin|
|Description:|Provides a new date format ('pppp') that displays times such as '2 days ago'|
|Version:|1.0 ($Rev: 3646 $)|
|Date:|$Date: 2008-02-27 02:34:38 +1000 (Wed, 27 Feb 2008) $|
|Source:|http://mptw.tiddlyspot.com/#PrettyDatesPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
!!Notes
* If you want to you can rename this plugin. :) Some suggestions: LastUpdatedPlugin, RelativeDatesPlugin, SmartDatesPlugin, SexyDatesPlugin.
* Inspired by http://ejohn.org/files/pretty.js
***/
//{{{
Date.prototype.prettyDate = function() {
var diff = (((new Date()).getTime() - this.getTime()) / 1000);
var day_diff = Math.floor(diff / 86400);
if (isNaN(day_diff)) return "";
else if (diff < 0) return "in the future";
else if (diff < 60) return "just now";
else if (diff < 120) return "1 minute ago";
else if (diff < 3600) return Math.floor(diff/60) + " minutes ago";
else if (diff < 7200) return "1 hour ago";
else if (diff < 86400) return Math.floor(diff/3600) + " hours ago";
else if (day_diff == 1) return "Yesterday";
else if (day_diff < 7) return day_diff + " days ago";
else if (day_diff < 14) return "a week ago";
else if (day_diff < 31) return Math.ceil(day_diff/7) + " weeks ago";
else if (day_diff < 62) return "a month ago";
else if (day_diff < 365) return "about " + Math.ceil(day_diff/31) + " months ago";
else if (day_diff < 730) return "a year ago";
else return Math.ceil(day_diff/365) + " years ago";
}
Date.prototype.formatString_orig_mptw = Date.prototype.formatString;
Date.prototype.formatString = function(template) {
return this.formatString_orig_mptw(template).replace(/pppp/,this.prettyDate());
}
// for MPTW. otherwise edit your ViewTemplate as required.
// config.mptwDateFormat = 'pppp (DD/MM/YY)';
config.mptwDateFormat = 'pppp';
//}}}
*[[Joel on software - переключение между задачами|http://russian.joelonsoftware.com/Articles/HumanTaskSwitchesConsider.html]]
http://eriwen.com/productivity/aliases-and-functions/
http://eriwen.com/bash/effective-shorthand/
<code class="brush:php">
$query_time = getmicrotime(); //засекаем время на основной запрос
if (!$GLOBAL_SITE_DATA['MYSQL']['SLAVE_SETUP']['sales']) {
$query = our_mysql_query($query_text);
}
else {
$query = our_mysql_slave_read($query_text);
}
$query_time = getmicrotime() - $query_time;
echo "Query working time: $query_time";
</code>
''Links''
http://www.vim.org/scripts/script.php?script_id=69
''Operations''
* Create new project \C or \c. Cursor must be on the top blank line.
* Edit project in .vimprojects file
* Refresh project's dir \r
* About filter wildcard chars you can read [[here|http://technet.microsoft.com/en-us/library/cc482985.aspx]]
/***
|Name:|QuickOpenTagPlugin|
|Description:|Changes tag links to make it easier to open tags as tiddlers|
|Version:|3.0.1 ($Rev: 3861 $)|
|Date:|$Date: 2008-03-08 10:53:09 +1000 (Sat, 08 Mar 2008) $|
|Source:|http://mptw.tiddlyspot.com/#QuickOpenTagPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
***/
//{{{
config.quickOpenTag = {
dropdownChar: (document.all ? "\u25bc" : "\u25be"), // the little one doesn't work in IE?
createTagButton: function(place,tag,excludeTiddler) {
// little hack so we can do this: <<tag PrettyTagName|RealTagName>>
var splitTag = tag.split("|");
var pretty = tag;
if (splitTag.length == 2) {
tag = splitTag[1];
pretty = splitTag[0];
}
var sp = createTiddlyElement(place,"span",null,"quickopentag");
createTiddlyText(createTiddlyLink(sp,tag,false),pretty);
var theTag = createTiddlyButton(sp,config.quickOpenTag.dropdownChar,
config.views.wikified.tag.tooltip.format([tag]),onClickTag);
theTag.setAttribute("tag",tag);
if (excludeTiddler)
theTag.setAttribute("tiddler",excludeTiddler);
return(theTag);
},
miniTagHandler: function(place,macroName,params,wikifier,paramString,tiddler) {
var tagged = store.getTaggedTiddlers(tiddler.title);
if (tagged.length > 0) {
var theTag = createTiddlyButton(place,config.quickOpenTag.dropdownChar,
config.views.wikified.tag.tooltip.format([tiddler.title]),onClickTag);
theTag.setAttribute("tag",tiddler.title);
theTag.className = "miniTag";
}
},
allTagsHandler: function(place,macroName,params) {
var tags = store.getTags(params[0]);
var filter = params[1]; // new feature
var ul = createTiddlyElement(place,"ul");
if(tags.length == 0)
createTiddlyElement(ul,"li",null,"listTitle",this.noTags);
for(var t=0; t<tags.length; t++) {
var title = tags[t][0];
if (!filter || (title.match(new RegExp('^'+filter)))) {
var info = getTiddlyLinkInfo(title);
var theListItem =createTiddlyElement(ul,"li");
var theLink = createTiddlyLink(theListItem,tags[t][0],true);
var theCount = " (" + tags[t][1] + ")";
theLink.appendChild(document.createTextNode(theCount));
var theDropDownBtn = createTiddlyButton(theListItem," " +
config.quickOpenTag.dropdownChar,this.tooltip.format([tags[t][0]]),onClickTag);
theDropDownBtn.setAttribute("tag",tags[t][0]);
}
}
},
// todo fix these up a bit
styles: [
"/*{{{*/",
"/* created by QuickOpenTagPlugin */",
".tagglyTagged .quickopentag, .tagged .quickopentag ",
" { margin-right:1.2em; border:1px solid #eee; padding:2px; padding-right:0px; padding-left:1px; }",
".quickopentag .tiddlyLink { padding:2px; padding-left:3px; }",
".quickopentag a.button { padding:1px; padding-left:2px; padding-right:2px;}",
"/* extra specificity to make it work right */",
"#displayArea .viewer .quickopentag a.button, ",
"#displayArea .viewer .quickopentag a.tiddyLink, ",
"#mainMenu .quickopentag a.tiddyLink, ",
"#mainMenu .quickopentag a.tiddyLink ",
" { border:0px solid black; }",
"#displayArea .viewer .quickopentag a.button, ",
"#mainMenu .quickopentag a.button ",
" { margin-left:0px; padding-left:2px; }",
"#displayArea .viewer .quickopentag a.tiddlyLink, ",
"#mainMenu .quickopentag a.tiddlyLink ",
" { margin-right:0px; padding-right:0px; padding-left:0px; margin-left:0px; }",
"a.miniTag {font-size:150%;} ",
"#mainMenu .quickopentag a.button ",
" /* looks better in right justified main menus */",
" { margin-left:0px; padding-left:2px; margin-right:0px; padding-right:0px; }",
"#topMenu .quickopentag { padding:0px; margin:0px; border:0px; }",
"#topMenu .quickopentag .tiddlyLink { padding-right:1px; margin-right:0px; }",
"#topMenu .quickopentag .button { padding-left:1px; margin-left:0px; border:0px; }",
"/*}}}*/",
""].join("\n"),
init: function() {
// we fully replace these builtins. can't hijack them easily
window.createTagButton = this.createTagButton;
config.macros.allTags.handler = this.allTagsHandler;
config.macros.miniTag = { handler: this.miniTagHandler };
config.shadowTiddlers["QuickOpenTagStyles"] = this.styles;
store.addNotification("QuickOpenTagStyles",refreshStyles);
}
}
config.quickOpenTag.init();
//}}}
High Level Steps to Record and Play inside Vim
* Start recording by pressing q, followed by a lower case character to name the macro
* Perform any typical editing, actions inside Vim editor, which will be recorded
* Stop recording by pressing q
* Play the recorded macro by pressing @ followed by the macro name
* To repeat macros multiple times, press : NN @ macro name. NN is a number
* [[Line Length, Volume and Density|http://paul-m-jones.com/archives/276]]
|Regexp |Description |Example|h
|^ |Start of string, or start of line in multi-line pattern|
|\A |Start of string|
|$ |End of string, or end of line in multi-line pattern|
|\Z |End of string|
|\b |Word boundary|
|\B |Not word boundary|
|\< |Start of word|
|\> |End of word|
''Links:''
http://www.regular-expressions.info/
/***
|Name:|RenameTagsPlugin|
|Description:|Allows you to easily rename or delete tags across multiple tiddlers|
|Version:|3.0 ($Rev: 5501 $)|
|Date:|$Date: 2008-06-10 23:11:55 +1000 (Tue, 10 Jun 2008) $|
|Source:|http://mptw.tiddlyspot.com/#RenameTagsPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License|http://mptw.tiddlyspot.com/#TheBSDLicense|
Rename a tag and you will be prompted to rename it in all its tagged tiddlers.
***/
//{{{
config.renameTags = {
prompts: {
rename: "Rename the tag '%0' to '%1' in %2 tidder%3?",
remove: "Remove the tag '%0' from %1 tidder%2?"
},
removeTag: function(tag,tiddlers) {
store.suspendNotifications();
for (var i=0;i<tiddlers.length;i++) {
store.setTiddlerTag(tiddlers[i].title,false,tag);
}
store.resumeNotifications();
store.notifyAll();
},
renameTag: function(oldTag,newTag,tiddlers) {
store.suspendNotifications();
for (var i=0;i<tiddlers.length;i++) {
store.setTiddlerTag(tiddlers[i].title,false,oldTag); // remove old
store.setTiddlerTag(tiddlers[i].title,true,newTag); // add new
}
store.resumeNotifications();
store.notifyAll();
},
storeMethods: {
saveTiddler_orig_renameTags: TiddlyWiki.prototype.saveTiddler,
saveTiddler: function(title,newTitle,newBody,modifier,modified,tags,fields,clearChangeCount,created,creator) {
if (title != newTitle) {
var tagged = this.getTaggedTiddlers(title);
if (tagged.length > 0) {
// then we are renaming a tag
if (confirm(config.renameTags.prompts.rename.format([title,newTitle,tagged.length,tagged.length>1?"s":""])))
config.renameTags.renameTag(title,newTitle,tagged);
if (!this.tiddlerExists(title) && newBody == "")
// dont create unwanted tiddler
return null;
}
}
return this.saveTiddler_orig_renameTags(title,newTitle,newBody,modifier,modified,tags,fields,clearChangeCount,created,creator);
},
removeTiddler_orig_renameTags: TiddlyWiki.prototype.removeTiddler,
removeTiddler: function(title) {
var tagged = this.getTaggedTiddlers(title);
if (tagged.length > 0)
if (confirm(config.renameTags.prompts.remove.format([title,tagged.length,tagged.length>1?"s":""])))
config.renameTags.removeTag(title,tagged);
return this.removeTiddler_orig_renameTags(title);
}
},
init: function() {
merge(TiddlyWiki.prototype,this.storeMethods);
}
}
config.renameTags.init();
//}}}
<html>
<img src="http://static.thegeekstuff.com/wp-content/uploads/2009/04/vim-find-and-replace-300x210.jpg" align="right" hspace="10" vspace="8">
</html>
Hello there! I am Lindrid and this is my personal notepad, but maybe you will find here something interesting for YOU. So, good luck and have fun!
Images uploaded on OpenDrive:
<html>
<a href="http://www.opendrive.com">
<img border="0" title="OpenDrive - Online storage, backup and file management" src="http://www.opendrive.com/images/OpenDrive_logo_70x20.png">
</a>
</html>
Условие задачи: в таблице могут находится 9 чисел из диапазона от 1 до 10, в рандомном порядке. Каждое число встречается один раз. Необходимо написать запрос, который вернёт число из диапазона [1,10] отсутствующее в таблице.
Решение:
<code class='brush: SQL'>
SELECT value FROM
(SELECT 1 AS Value from dual UNION
SELECT 2 AS Value from dual UNION
SELECT 3 AS Value from dual UNION
SELECT 4 AS Value from dual UNION
SELECT 5 AS Value from dual UNION
SELECT 6 AS Value from dual UNION
SELECT 7 AS Value from dual UNION
SELECT 8 AS Value from dual UNION
SELECT 9 AS Value from dual UNION
SELECT 10 AS Value from dual) ValueTable
where value not in (select * from bla)
</code>
/***
|Name:|SaveCloseTiddlerPlugin|
|Description:|Provides two extra toolbar commands, saveCloseTiddler and cancelCloseTiddler|
|Version:|3.0 ($Rev: 5502 $)|
|Date:|$Date: 2008-06-10 23:31:39 +1000 (Tue, 10 Jun 2008) $|
|Source:|http://mptw.tiddlyspot.com/#SaveCloseTiddlerPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
To use these you must add them to the tool bar in your EditTemplate
***/
//{{{
merge(config.commands,{
saveCloseTiddler: {
text: 'done/close',
tooltip: 'Save changes to this tiddler and close it',
handler: function(ev,src,title) {
var closeTitle = title;
var newTitle = story.saveTiddler(title,ev.shiftKey);
if (newTitle)
closeTitle = newTitle;
return config.commands.closeTiddler.handler(ev,src,closeTitle);
}
},
cancelCloseTiddler: {
text: 'cancel/close',
tooltip: 'Undo changes to this tiddler and close it',
handler: function(ev,src,title) {
// the same as closeTiddler now actually
return config.commands.closeTiddler.handler(ev,src,title);
}
}
});
//}}}
/***
|Name:|SelectThemePlugin|
|Description:|Lets you easily switch theme and palette|
|Version:|1.0.1 ($Rev: 3646 $)|
|Date:|$Date: 2008-02-27 02:34:38 +1000 (Wed, 27 Feb 2008) $|
|Source:|http://mptw.tiddlyspot.com/#SelectThemePlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
!Notes
* Borrows largely from ThemeSwitcherPlugin by Martin Budden http://www.martinswiki.com/#ThemeSwitcherPlugin
* Theme is cookie based. But set a default by setting config.options.txtTheme in MptwConfigPlugin (for example)
* Palette is not cookie based. It actually overwrites your ColorPalette tiddler when you select a palette, so beware.
!Usage
* {{{<<selectTheme>>}}} makes a dropdown selector
* {{{<<selectPalette>>}}} makes a dropdown selector
* {{{<<applyTheme>>}}} applies the current tiddler as a theme
* {{{<<applyPalette>>}}} applies the current tiddler as a palette
* {{{<<applyTheme TiddlerName>>}}} applies TiddlerName as a theme
* {{{<<applyPalette TiddlerName>>}}} applies TiddlerName as a palette
***/
//{{{
config.macros.selectTheme = {
label: {
selectTheme:"select theme",
selectPalette:"select palette"
},
prompt: {
selectTheme:"Select the current theme",
selectPalette:"Select the current palette"
},
tags: {
selectTheme:'systemTheme',
selectPalette:'systemPalette'
}
};
config.macros.selectTheme.handler = function(place,macroName)
{
var btn = createTiddlyButton(place,this.label[macroName],this.prompt[macroName],this.onClick);
// want to handle palettes and themes with same code. use mode attribute to distinguish
btn.setAttribute('mode',macroName);
};
config.macros.selectTheme.onClick = function(ev)
{
var e = ev ? ev : window.event;
var popup = Popup.create(this);
var mode = this.getAttribute('mode');
var tiddlers = store.getTaggedTiddlers(config.macros.selectTheme.tags[mode]);
// for default
if (mode == "selectPalette") {
var btn = createTiddlyButton(createTiddlyElement(popup,'li'),"(default)","default color palette",config.macros.selectTheme.onClickTheme);
btn.setAttribute('theme',"(default)");
btn.setAttribute('mode',mode);
}
for(var i=0; i<tiddlers.length; i++) {
var t = tiddlers[i].title;
var name = store.getTiddlerSlice(t,'Name');
var desc = store.getTiddlerSlice(t,'Description');
var btn = createTiddlyButton(createTiddlyElement(popup,'li'), name?name:t, desc?desc:config.macros.selectTheme.label['mode'], config.macros.selectTheme.onClickTheme);
btn.setAttribute('theme',t);
btn.setAttribute('mode',mode);
}
Popup.show();
return stopEvent(e);
};
config.macros.selectTheme.onClickTheme = function(ev)
{
var mode = this.getAttribute('mode');
var theme = this.getAttribute('theme');
if (mode == 'selectTheme')
story.switchTheme(theme);
else // selectPalette
config.macros.selectTheme.updatePalette(theme);
return false;
};
config.macros.selectTheme.updatePalette = function(title)
{
if (title != "") {
store.deleteTiddler("ColorPalette");
if (title != "(default)")
store.saveTiddler("ColorPalette","ColorPalette",store.getTiddlerText(title),
config.options.txtUserName,undefined,"");
refreshAll();
if(config.options.chkAutoSave)
saveChanges(true);
}
};
config.macros.applyTheme = {
label: "apply",
prompt: "apply this theme or palette" // i'm lazy
};
config.macros.applyTheme.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
var useTiddler = params[0] ? params[0] : tiddler.title;
var btn = createTiddlyButton(place,this.label,this.prompt,config.macros.selectTheme.onClickTheme);
btn.setAttribute('theme',useTiddler);
btn.setAttribute('mode',macroName=="applyTheme"?"selectTheme":"selectPalette"); // a bit untidy here
}
config.macros.selectPalette = config.macros.selectTheme;
config.macros.applyPalette = config.macros.applyTheme;
config.macros.refreshAll = { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
createTiddlyButton(place,"refresh","refresh layout and styles",function() { refreshAll(); });
}};
//}}}
<code class="brush:">
:lcd %:p:h
</code>
/***
|Requires|ShCore.js|
***/
//{{{
/**
* SyntaxHighlighter
* http://alexgorbatchev.com/SyntaxHighlighter
*
* SyntaxHighlighter is donationware. If you are using it, please donate.
* http://alexgorbatchev.com/SyntaxHighlighter/donate.html
*
* @version
* 3.0.83 (July 02 2010)
*
* @copyright
* Copyright (C) 2004-2010 Alex Gorbatchev.
*
* @license
* Dual licensed under the MIT and GPL licenses.
*/
;(function()
{
// CommonJS
typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null;
function Brush()
{
function getKeywordsCSS(str)
{
return '\\b([a-z_]|)' + str.replace(/ /g, '(?=:)\\b|\\b([a-z_\\*]|\\*|)') + '(?=:)\\b';
};
function getValuesCSS(str)
{
return '\\b' + str.replace(/ /g, '(?!-)(?!:)\\b|\\b()') + '\:\\b';
};
var keywords = 'ascent azimuth background-attachment background-color background-image background-position ' +
'background-repeat background baseline bbox border-collapse border-color border-spacing border-style border-top ' +
'border-right border-bottom border-left border-top-color border-right-color border-bottom-color border-left-color ' +
'border-top-style border-right-style border-bottom-style border-left-style border-top-width border-right-width ' +
'border-bottom-width border-left-width border-width border bottom cap-height caption-side centerline clear clip color ' +
'content counter-increment counter-reset cue-after cue-before cue cursor definition-src descent direction display ' +
'elevation empty-cells float font-size-adjust font-family font-size font-stretch font-style font-variant font-weight font ' +
'height left letter-spacing line-height list-style-image list-style-position list-style-type list-style margin-top ' +
'margin-right margin-bottom margin-left margin marker-offset marks mathline max-height max-width min-height min-width orphans ' +
'outline-color outline-style outline-width outline overflow padding-top padding-right padding-bottom padding-left padding page ' +
'page-break-after page-break-before page-break-inside pause pause-after pause-before pitch pitch-range play-during position ' +
'quotes right richness size slope src speak-header speak-numeral speak-punctuation speak speech-rate stemh stemv stress ' +
'table-layout text-align top text-decoration text-indent text-shadow text-transform unicode-bidi unicode-range units-per-em ' +
'vertical-align visibility voice-family volume white-space widows width widths word-spacing x-height z-index';
var values = 'above absolute all always aqua armenian attr aural auto avoid baseline behind below bidi-override black blink block blue bold bolder '+
'both bottom braille capitalize caption center center-left center-right circle close-quote code collapse compact condensed '+
'continuous counter counters crop cross crosshair cursive dashed decimal decimal-leading-zero default digits disc dotted double '+
'embed embossed e-resize expanded extra-condensed extra-expanded fantasy far-left far-right fast faster fixed format fuchsia '+
'gray green groove handheld hebrew help hidden hide high higher icon inline-table inline inset inside invert italic '+
'justify landscape large larger left-side left leftwards level lighter lime line-through list-item local loud lower-alpha '+
'lowercase lower-greek lower-latin lower-roman lower low ltr marker maroon medium message-box middle mix move narrower '+
'navy ne-resize no-close-quote none no-open-quote no-repeat normal nowrap n-resize nw-resize oblique olive once open-quote outset '+
'outside overline pointer portrait pre print projection purple red relative repeat repeat-x repeat-y rgb ridge right right-side '+
'rightwards rtl run-in screen scroll semi-condensed semi-expanded separate se-resize show silent silver slower slow '+
'small small-caps small-caption smaller soft solid speech spell-out square s-resize static status-bar sub super sw-resize '+
'table-caption table-cell table-column table-column-group table-footer-group table-header-group table-row table-row-group teal '+
'text-bottom text-top thick thin top transparent tty tv ultra-condensed ultra-expanded underline upper-alpha uppercase upper-latin '+
'upper-roman url visible wait white wider w-resize x-fast x-high x-large x-loud x-low x-slow x-small x-soft xx-large xx-small yellow';
var fonts = '[mM]onospace [tT]ahoma [vV]erdana [aA]rial [hH]elvetica [sS]ans-serif [sS]erif [cC]ourier mono sans serif';
this.regexList = [
{ regex: SyntaxHighlighter.regexLib.multiLineCComments, css: 'comments' }, // multiline comments
{ regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' }, // double quoted strings
{ regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, // single quoted strings
{ regex: /\#[a-fA-F0-9]{3,6}/g, css: 'value' }, // html colors
{ regex: /(-?\d+)(\.\d+)?(px|em|pt|\:|\%|)/g, css: 'value' }, // sizes
{ regex: /!important/g, css: 'color3' }, // !important
{ regex: new RegExp(getKeywordsCSS(keywords), 'gm'), css: 'keyword' }, // keywords
{ regex: new RegExp(getValuesCSS(values), 'g'), css: 'value' }, // values
{ regex: new RegExp(this.getKeywords(fonts), 'g'), css: 'color1' } // fonts
];
this.forHtmlScript({
left: /(<|<)\s*style.*?(>|>)/gi,
right: /(<|<)\/\s*style\s*(>|>)/gi
});
};
Brush.prototype = new SyntaxHighlighter.Highlighter();
Brush.aliases = ['css'];
SyntaxHighlighter.brushes.CSS = Brush;
// CommonJS
typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
})();
//}}}
/***
***/
/*{{{*/
/**
* SyntaxHighlighter
* http://alexgorbatchev.com/SyntaxHighlighter
*
* SyntaxHighlighter is donationware. If you are using it, please donate.
* http://alexgorbatchev.com/SyntaxHighlighter/donate.html
*
* @version
* 3.0.83 (July 02 2010)
*
* @copyright
* Copyright (C) 2004-2010 Alex Gorbatchev.
*
* @license
* Dual licensed under the MIT and GPL licenses.
*/
;(function()
{
// CommonJS
typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null;
function Brush()
{
var keywords = 'break case catch continue ' +
'default delete do else false ' +
'for function if in instanceof ' +
'new null return super switch ' +
'this throw true try typeof var while with'
;
var r = SyntaxHighlighter.regexLib;
this.regexList = [
{ regex: r.multiLineDoubleQuotedString, css: 'string' }, // double quoted strings
{ regex: r.multiLineSingleQuotedString, css: 'string' }, // single quoted strings
{ regex: r.singleLineCComments, css: 'comments' }, // one line comments
{ regex: r.multiLineCComments, css: 'comments' }, // multiline comments
{ regex: /\s*#.*/gm, css: 'preprocessor' }, // preprocessor tags like #region and #endregion
{ regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' } // keywords
];
this.forHtmlScript(r.scriptScriptTags);
};
Brush.prototype = new SyntaxHighlighter.Highlighter();
Brush.aliases = ['js', 'jscript', 'javascript'];
SyntaxHighlighter.brushes.JScript = Brush;
// CommonJS
typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
})();
/*}}}*/
/**
* SyntaxHighlighter
* http://alexgorbatchev.com/SyntaxHighlighter
*
* SyntaxHighlighter is donationware. If you are using it, please donate.
* http://alexgorbatchev.com/SyntaxHighlighter/donate.html
*
* @version
* 3.0.83 (July 02 2010)
*
* @copyright
* Copyright (C) 2004-2010 Alex Gorbatchev.
*
* @license
* Dual licensed under the MIT and GPL licenses.
*/
;(function()
{
// CommonJS
typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null;
function Brush()
{
var keywords = 'abstract assert boolean break byte case catch char class const ' +
'continue default do double else enum extends ' +
'false final finally float for goto if implements import ' +
'instanceof int interface long native new null ' +
'package private protected public return ' +
'short static strictfp super switch synchronized this throw throws true ' +
'transient try void volatile while';
this.regexList = [
{ regex: SyntaxHighlighter.regexLib.singleLineCComments, css: 'comments' }, // one line comments
{ regex: /\/\*([^\*][\s\S]*)?\*\//gm, css: 'comments' }, // multiline comments
{ regex: /\/\*(?!\*\/)\*[\s\S]*?\*\//gm, css: 'preprocessor' }, // documentation comments
{ regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' }, // strings
{ regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, // strings
{ regex: /\b([\d]+(\.[\d]+)?|0x[a-f0-9]+)\b/gi, css: 'value' }, // numbers
{ regex: /(?!\@interface\b)\@[\$\w]+\b/g, css: 'color1' }, // annotation @anno
{ regex: /\@interface\b/g, css: 'color2' }, // @interface keyword
{ regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' } // java keyword
];
this.forHtmlScript({
left : /(<|<)%[@!=]?/g,
right : /%(>|>)/g
});
};
Brush.prototype = new SyntaxHighlighter.Highlighter();
Brush.aliases = ['java'];
SyntaxHighlighter.brushes.Java = Brush;
// CommonJS
typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
})();
//{{{
;(function()
{
// CommonJS
typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null;
function Brush()
{
var funcs = 'abs acos acosh addcslashes addslashes ' +
'array_change_key_case array_chunk array_combine array_count_values array_diff '+
'array_diff_assoc array_diff_key array_diff_uassoc array_diff_ukey array_fill '+
'array_filter array_flip array_intersect array_intersect_assoc array_intersect_key '+
'array_intersect_uassoc array_intersect_ukey array_key_exists array_keys array_map '+
'array_merge array_merge_recursive array_multisort array_pad array_pop array_product '+
'array_push array_rand array_reduce array_reverse array_search array_shift '+
'array_slice array_splice array_sum array_udiff array_udiff_assoc '+
'array_udiff_uassoc array_uintersect array_uintersect_assoc '+
'array_uintersect_uassoc array_unique array_unshift array_values array_walk '+
'array_walk_recursive atan atan2 atanh base64_decode base64_encode base_convert '+
'basename bcadd bccomp bcdiv bcmod bcmul bindec bindtextdomain bzclose bzcompress '+
'bzdecompress bzerrno bzerror bzerrstr bzflush bzopen bzread bzwrite ceil chdir '+
'checkdate checkdnsrr chgrp chmod chop chown chr chroot chunk_split class_exists '+
'closedir closelog copy cos cosh count count_chars date decbin dechex decoct '+
'deg2rad delete ebcdic2ascii echo empty end ereg ereg_replace eregi eregi_replace error_log '+
'error_reporting escapeshellarg escapeshellcmd eval exec exit exp explode extension_loaded '+
'feof fflush fgetc fgetcsv fgets fgetss file_exists file_get_contents file_put_contents '+
'fileatime filectime filegroup fileinode filemtime fileowner fileperms filesize filetype '+
'floatval flock floor flush fmod fnmatch fopen fpassthru fprintf fputcsv fputs fread fscanf '+
'fseek fsockopen fstat ftell ftok getallheaders getcwd getdate getenv gethostbyaddr gethostbyname '+
'gethostbynamel getimagesize getlastmod getmxrr getmygid getmyinode getmypid getmyuid getopt '+
'getprotobyname getprotobynumber getrandmax getrusage getservbyname getservbyport gettext '+
'gettimeofday gettype glob gmdate gmmktime ini_alter ini_get ini_get_all ini_restore ini_set '+
'interface_exists intval ip2long is_a is_array is_bool is_callable is_dir is_double '+
'is_executable is_file is_finite is_float is_infinite is_int is_integer is_link is_long '+
'is_nan is_null is_numeric is_object is_readable is_real is_resource is_scalar is_soap_fault '+
'is_string is_subclass_of is_uploaded_file is_writable is_writeable mkdir mktime nl2br '+
'parse_ini_file parse_str parse_url passthru pathinfo print readlink realpath rewind rewinddir rmdir '+
'round str_ireplace str_pad str_repeat str_replace str_rot13 str_shuffle str_split '+
'str_word_count strcasecmp strchr strcmp strcoll strcspn strftime strip_tags stripcslashes '+
'stripos stripslashes stristr strlen strnatcasecmp strnatcmp strncasecmp strncmp strpbrk '+
'strpos strptime strrchr strrev strripos strrpos strspn strstr strtok strtolower strtotime '+
'strtoupper strtr strval substr substr_compare';
var keywords = 'abstract and array as break case catch cfunction class clone const continue declare default die do ' +
'else elseif enddeclare endfor endforeach endif endswitch endwhile extends final for foreach ' +
'function include include_once global goto if implements interface instanceof namespace new ' +
'old_function or private protected public return require require_once static switch ' +
'throw try use var while xor ';
var constants = '__FILE__ __LINE__ __METHOD__ __FUNCTION__ __CLASS__';
this.regexList = [
{ regex: SyntaxHighlighter.regexLib.singleLineCComments, css: 'comments' }, // one line comments
{ regex: SyntaxHighlighter.regexLib.multiLineCComments, css: 'comments' }, // multiline comments
{ regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' }, // double quoted strings
{ regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, // single quoted strings
{ regex: /\$\w+/g, css: 'variable' }, // variables
{ regex: new RegExp(this.getKeywords(funcs), 'gmi'), css: 'functions' }, // common functions
{ regex: new RegExp(this.getKeywords(constants), 'gmi'), css: 'constants' }, // constants
{ regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' } // keyword
];
this.forHtmlScript(SyntaxHighlighter.regexLib.phpScriptTags);
};
Brush.prototype = new SyntaxHighlighter.Highlighter();
Brush.aliases = ['php'];
SyntaxHighlighter.brushes.Php = Brush;
// CommonJS
typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
})();
//}}}
//{{{
/**
* SyntaxHighlighter
* http://alexgorbatchev.com/SyntaxHighlighter
*
* SyntaxHighlighter is donationware. If you are using it, please donate.
* http://alexgorbatchev.com/SyntaxHighlighter/donate.html
*
* @version
* 3.0.83 (July 02 2010)
*
* @copyright
* Copyright (C) 2004-2010 Alex Gorbatchev.
*
* @license
* Dual licensed under the MIT and GPL licenses.
*/
;(function()
{
// CommonJS
typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null;
function Brush()
{
};
Brush.prototype = new SyntaxHighlighter.Highlighter();
Brush.aliases = ['text', 'plain'];
SyntaxHighlighter.brushes.Plain = Brush;
// CommonJS
typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
})();
//}}}
//{{{
/**
* SyntaxHighlighter
* http://alexgorbatchev.com/SyntaxHighlighter
*
* SyntaxHighlighter is donationware. If you are using it, please donate.
* http://alexgorbatchev.com/SyntaxHighlighter/donate.html
*
* @version
* 3.0.83 (July 02 2010)
*
* @copyright
* Copyright (C) 2004-2010 Alex Gorbatchev.
*
* @license
* Dual licensed under the MIT and GPL licenses.
*/
;(function()
{
// CommonJS
typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null;
function Brush()
{
// Contributed by Gheorghe Milas and Ahmad Sherif
var keywords = 'and assert break class continue def del elif else ' +
'except exec finally for from global if import in is ' +
'lambda not or pass print raise return try yield while';
var funcs = '__import__ abs all any apply basestring bin bool buffer callable ' +
'chr classmethod cmp coerce compile complex delattr dict dir ' +
'divmod enumerate eval execfile file filter float format frozenset ' +
'getattr globals hasattr hash help hex id input int intern ' +
'isinstance issubclass iter len list locals long map max min next ' +
'object oct open ord pow print property range raw_input reduce ' +
'reload repr reversed round set setattr slice sorted staticmethod ' +
'str sum super tuple type type unichr unicode vars xrange zip';
var special = 'None True False self cls class_';
this.regexList = [
{ regex: SyntaxHighlighter.regexLib.singleLinePerlComments, css: 'comments' },
{ regex: /^\s*@\w+/gm, css: 'decorator' },
{ regex: /(['\"]{3})([^\1])*?\1/gm, css: 'comments' },
{ regex: /"(?!")(?:\.|\\\"|[^\""\n])*"/gm, css: 'string' },
{ regex: /'(?!')(?:\.|(\\\')|[^\''\n])*'/gm, css: 'string' },
{ regex: /\+|\-|\*|\/|\%|=|==/gm, css: 'keyword' },
{ regex: /\b\d+\.?\w*/g, css: 'value' },
{ regex: new RegExp(this.getKeywords(funcs), 'gmi'), css: 'functions' },
{ regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' },
{ regex: new RegExp(this.getKeywords(special), 'gm'), css: 'color1' }
];
this.forHtmlScript(SyntaxHighlighter.regexLib.aspScriptTags);
};
Brush.prototype = new SyntaxHighlighter.Highlighter();
Brush.aliases = ['py', 'python'];
SyntaxHighlighter.brushes.Python = Brush;
// CommonJS
typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
})();
//}}}
//{{{
/**
* SyntaxHighlighter
* http://alexgorbatchev.com/SyntaxHighlighter
*
* SyntaxHighlighter is donationware. If you are using it, please donate.
* http://alexgorbatchev.com/SyntaxHighlighter/donate.html
*
* @version
* 3.0.83 (July 02 2010)
*
* @copyright
* Copyright (C) 2004-2010 Alex Gorbatchev.
*
* @license
* Dual licensed under the MIT and GPL licenses.
*/
;(function()
{
// CommonJS
typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null;
function Brush()
{
function process(match, regexInfo)
{
var constructor = SyntaxHighlighter.Match,
code = match[0],
tag = new XRegExp('(<|<)[\\s\\/\\?]*(?<name>[:\\w-\\.]+)', 'xg').exec(code),
result = []
;
if (match.attributes != null)
{
var attributes,
regex = new XRegExp('(?<name> [\\w:\\-\\.]+)' +
'\\s*=\\s*' +
'(?<value> ".*?"|\'.*?\'|\\w+)',
'xg');
while ((attributes = regex.exec(code)) != null)
{
result.push(new constructor(attributes.name, match.index + attributes.index, 'color1'));
result.push(new constructor(attributes.value, match.index + attributes.index + attributes[0].indexOf(attributes.value), 'string'));
}
}
if (tag != null)
result.push(
new constructor(tag.name, match.index + tag[0].indexOf(tag.name), 'keyword')
);
return result;
}
this.regexList = [
{ regex: new XRegExp('(\\<|<)\\!\\[[\\w\\s]*?\\[(.|\\s)*?\\]\\](\\>|>)', 'gm'), css: 'color2' }, // <![ ... [ ... ]]>
{ regex: SyntaxHighlighter.regexLib.xmlComments, css: 'comments' }, // <!-- ... -->
{ regex: new XRegExp('(<|<)[\\s\\/\\?]*(\\w+)(?<attributes>.*?)[\\s\\/\\?]*(>|>)', 'sg'), func: process }
];
};
Brush.prototype = new SyntaxHighlighter.Highlighter();
Brush.aliases = ['xml', 'xhtml', 'xslt', 'html'];
SyntaxHighlighter.brushes.Xml = Brush;
// CommonJS
typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
})();
//}}}
/*{{{*/
/**
* SyntaxHighlighter
* http://alexgorbatchev.com/SyntaxHighlighter
*
* SyntaxHighlighter is donationware. If you are using it, please donate.
* http://alexgorbatchev.com/SyntaxHighlighter/donate.html
*
* @version
* 3.0.83 (July 02 2010)
*
* @copyright
* Copyright (C) 2004-2010 Alex Gorbatchev.
*
* @license
* Dual licensed under the MIT and GPL licenses.
*/
.syntaxhighlighter a,
.syntaxhighlighter div,
.syntaxhighlighter code,
.syntaxhighlighter table,
.syntaxhighlighter table td,
.syntaxhighlighter table tr,
.syntaxhighlighter table tbody,
.syntaxhighlighter table thead,
.syntaxhighlighter table caption,
.syntaxhighlighter textarea {
-moz-border-radius: 0 0 0 0 !important;
-webkit-border-radius: 0 0 0 0 !important;
background: none !important;
border: 0 !important;
bottom: auto !important;
float: none !important;
height: auto !important;
left: auto !important;
margin: 0 !important;
outline: 0 !important;
overflow: visible !important;
padding: 0 !important;
position: static !important;
right: auto !important;
text-align: left !important;
top: auto !important;
vertical-align: baseline !important;
width: auto !important;
box-sizing: content-box !important;
font-family: "Courier New" !important;
font-weight: normal !important;
font-style: normal !important;
font-size: 1.01em !important;
min-height: inherit !important;
min-height: auto !important;
}
.syntaxhighlighter {
width: 100% !important;
margin: 1em 0 1em 0 !important;
position: relative !important;
overflow: auto !important;
font-size: .9em !important;
}
.syntaxhighlighter.source {
overflow: hidden !important;
}
.syntaxhighlighter .bold {
font-weight: bold !important;
}
.syntaxhighlighter .italic {
font-style: italic !important;
}
.syntaxhighlighter .line {
white-space: pre !important;
}
.syntaxhighlighter table {
width: 100% !important;
}
.syntaxhighlighter table caption {
text-align: left !important;
padding: .5em 0 0.5em 1em !important;
}
.syntaxhighlighter table td.code {
width: 100% !important;
}
.syntaxhighlighter table td.code .container {
position: relative !important;
}
.syntaxhighlighter table td.code .container textarea {
box-sizing: border-box !important;
position: absolute !important;
left: 0 !important;
top: 0 !important;
width: 100% !important;
height: 100% !important;
border: none !important;
background: white !important;
padding-left: 1em !important;
overflow: hidden !important;
white-space: pre !important;
}
.syntaxhighlighter table td.gutter .line {
text-align: left !important;
padding: 0 0.5em 0 1em !important;
line-height: 1.49629 !important;
}
.syntaxhighlighter table td.code .line {
padding: 0 0.5em !important;
}
.syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line {
padding-left: 0em !important;
}
.syntaxhighlighter.show {
display: block !important;
}
.syntaxhighlighter.collapsed table {
display: none !important;
}
.syntaxhighlighter.collapsed .toolbar {
padding: 0.1em 0.8em 0em 0.8em !important;
font-size: 1em !important;
position: static !important;
width: auto !important;
height: auto !important;
}
.syntaxhighlighter.collapsed .toolbar span {
display: inline !important;
margin-right: 1.05em !important;
}
.syntaxhighlighter.collapsed .toolbar span a {
padding: 0 !important;
display: none !important;
}
.syntaxhighlighter.collapsed .toolbar span a.expandSource {
display: inline !important;
}
.syntaxhighlighter .toolbar {
position: absolute !important;
right: 1px !important;
top: 1px !important;
width: 11px !important;
height: 11px !important;
font-size: 10px !important;
z-index: 10 !important;
}
.syntaxhighlighter .toolbar span.title {
display: inline !important;
}
.syntaxhighlighter .toolbar a {
display: block !important;
text-align: center !important;
text-decoration: none !important;
padding-top: 1px !important;
}
.syntaxhighlighter .toolbar a.expandSource {
display: none !important;
}
.syntaxhighlighter.ie {
font-size: .9em !important;
padding: 1px 0 1px 0 !important;
}
.syntaxhighlighter.ie .toolbar {
line-height: 8px !important;
}
.syntaxhighlighter.ie .toolbar a {
padding-top: 0px !important;
}
.syntaxhighlighter.printing .line.alt1 .content,
.syntaxhighlighter.printing .line.alt2 .content,
.syntaxhighlighter.printing .line.highlighted .number,
.syntaxhighlighter.printing .line.highlighted.alt1 .content,
.syntaxhighlighter.printing .line.highlighted.alt2 .content {
background: none !important;
}
.syntaxhighlighter.printing .line .number {
color: #bbbbbb !important;
}
.syntaxhighlighter.printing .line .content {
color: black !important;
}
.syntaxhighlighter.printing .toolbar {
display: none !important;
}
.syntaxhighlighter.printing a {
text-decoration: none !important;
}
.syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a {
color: black !important;
}
.syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a {
color: #008200 !important;
}
.syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a {
color: blue !important;
}
.syntaxhighlighter.printing .keyword {
color: #006699 !important;
font-weight: bold !important;
}
.syntaxhighlighter.printing .preprocessor {
color: gray !important;
}
.syntaxhighlighter.printing .variable {
color: #aa7700 !important;
}
.syntaxhighlighter.printing .value {
color: #009900 !important;
}
.syntaxhighlighter.printing .functions {
color: #ff1493 !important;
}
.syntaxhighlighter.printing .constants {
color: #0066cc !important;
}
.syntaxhighlighter.printing .script {
font-weight: bold !important;
}
.syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a {
color: gray !important;
}
.syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a {
color: #ff1493 !important;
}
.syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a {
color: red !important;
}
.syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a {
color: black !important;
}
/*}}}*/
/**
* SyntaxHighlighter
* http://alexgorbatchev.com/SyntaxHighlighter
*
* SyntaxHighlighter is donationware. If you are using it, please donate.
* http://alexgorbatchev.com/SyntaxHighlighter/donate.html
*
* @version
* 3.0.83 (July 02 2010)
*
* @copyright
* Copyright (C) 2004-2010 Alex Gorbatchev.
*
* @license
* Dual licensed under the MIT and GPL licenses.
*/
eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('K M;I(M)1S 2U("2a\'t 4k M 4K 2g 3l 4G 4H");(6(){6 r(f,e){I(!M.1R(f))1S 3m("3s 15 4R");K a=f.1w;f=M(f.1m,t(f)+(e||""));I(a)f.1w={1m:a.1m,19:a.19?a.19.1a(0):N};H f}6 t(f){H(f.1J?"g":"")+(f.4s?"i":"")+(f.4p?"m":"")+(f.4v?"x":"")+(f.3n?"y":"")}6 B(f,e,a,b){K c=u.L,d,h,g;v=R;5K{O(;c--;){g=u[c];I(a&g.3r&&(!g.2p||g.2p.W(b))){g.2q.12=e;I((h=g.2q.X(f))&&h.P===e){d={3k:g.2b.W(b,h,a),1C:h};1N}}}}5v(i){1S i}5q{v=11}H d}6 p(f,e,a){I(3b.Z.1i)H f.1i(e,a);O(a=a||0;a<f.L;a++)I(f[a]===e)H a;H-1}M=6(f,e){K a=[],b=M.1B,c=0,d,h;I(M.1R(f)){I(e!==1d)1S 3m("2a\'t 5r 5I 5F 5B 5C 15 5E 5p");H r(f)}I(v)1S 2U("2a\'t W 3l M 59 5m 5g 5x 5i");e=e||"";O(d={2N:11,19:[],2K:6(g){H e.1i(g)>-1},3d:6(g){e+=g}};c<f.L;)I(h=B(f,c,b,d)){a.U(h.3k);c+=h.1C[0].L||1}Y I(h=n.X.W(z[b],f.1a(c))){a.U(h[0]);c+=h[0].L}Y{h=f.3a(c);I(h==="[")b=M.2I;Y I(h==="]")b=M.1B;a.U(h);c++}a=15(a.1K(""),n.Q.W(e,w,""));a.1w={1m:f,19:d.2N?d.19:N};H a};M.3v="1.5.0";M.2I=1;M.1B=2;K C=/\\$(?:(\\d\\d?|[$&`\'])|{([$\\w]+)})/g,w=/[^5h]+|([\\s\\S])(?=[\\s\\S]*\\1)/g,A=/^(?:[?*+]|{\\d+(?:,\\d*)?})\\??/,v=11,u=[],n={X:15.Z.X,1A:15.Z.1A,1C:1r.Z.1C,Q:1r.Z.Q,1e:1r.Z.1e},x=n.X.W(/()??/,"")[1]===1d,D=6(){K f=/^/g;n.1A.W(f,"");H!f.12}(),y=6(){K f=/x/g;n.Q.W("x",f,"");H!f.12}(),E=15.Z.3n!==1d,z={};z[M.2I]=/^(?:\\\\(?:[0-3][0-7]{0,2}|[4-7][0-7]?|x[\\29-26-f]{2}|u[\\29-26-f]{4}|c[A-3o-z]|[\\s\\S]))/;z[M.1B]=/^(?:\\\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9]\\d*|x[\\29-26-f]{2}|u[\\29-26-f]{4}|c[A-3o-z]|[\\s\\S])|\\(\\?[:=!]|[?*+]\\?|{\\d+(?:,\\d*)?}\\??)/;M.1h=6(f,e,a,b){u.U({2q:r(f,"g"+(E?"y":"")),2b:e,3r:a||M.1B,2p:b||N})};M.2n=6(f,e){K a=f+"/"+(e||"");H M.2n[a]||(M.2n[a]=M(f,e))};M.3c=6(f){H r(f,"g")};M.5l=6(f){H f.Q(/[-[\\]{}()*+?.,\\\\^$|#\\s]/g,"\\\\$&")};M.5e=6(f,e,a,b){e=r(e,"g"+(b&&E?"y":""));e.12=a=a||0;f=e.X(f);H b?f&&f.P===a?f:N:f};M.3q=6(){M.1h=6(){1S 2U("2a\'t 55 1h 54 3q")}};M.1R=6(f){H 53.Z.1q.W(f)==="[2m 15]"};M.3p=6(f,e,a,b){O(K c=r(e,"g"),d=-1,h;h=c.X(f);){a.W(b,h,++d,f,c);c.12===h.P&&c.12++}I(e.1J)e.12=0};M.57=6(f,e){H 6 a(b,c){K d=e[c].1I?e[c]:{1I:e[c]},h=r(d.1I,"g"),g=[],i;O(i=0;i<b.L;i++)M.3p(b[i],h,6(k){g.U(d.3j?k[d.3j]||"":k[0])});H c===e.L-1||!g.L?g:a(g,c+1)}([f],0)};15.Z.1p=6(f,e){H J.X(e[0])};15.Z.W=6(f,e){H J.X(e)};15.Z.X=6(f){K e=n.X.1p(J,14),a;I(e){I(!x&&e.L>1&&p(e,"")>-1){a=15(J.1m,n.Q.W(t(J),"g",""));n.Q.W(f.1a(e.P),a,6(){O(K c=1;c<14.L-2;c++)I(14[c]===1d)e[c]=1d})}I(J.1w&&J.1w.19)O(K b=1;b<e.L;b++)I(a=J.1w.19[b-1])e[a]=e[b];!D&&J.1J&&!e[0].L&&J.12>e.P&&J.12--}H e};I(!D)15.Z.1A=6(f){(f=n.X.W(J,f))&&J.1J&&!f[0].L&&J.12>f.P&&J.12--;H!!f};1r.Z.1C=6(f){M.1R(f)||(f=15(f));I(f.1J){K e=n.1C.1p(J,14);f.12=0;H e}H f.X(J)};1r.Z.Q=6(f,e){K a=M.1R(f),b,c;I(a&&1j e.58()==="3f"&&e.1i("${")===-1&&y)H n.Q.1p(J,14);I(a){I(f.1w)b=f.1w.19}Y f+="";I(1j e==="6")c=n.Q.W(J,f,6(){I(b){14[0]=1f 1r(14[0]);O(K d=0;d<b.L;d++)I(b[d])14[0][b[d]]=14[d+1]}I(a&&f.1J)f.12=14[14.L-2]+14[0].L;H e.1p(N,14)});Y{c=J+"";c=n.Q.W(c,f,6(){K d=14;H n.Q.W(e,C,6(h,g,i){I(g)5b(g){24"$":H"$";24"&":H d[0];24"`":H d[d.L-1].1a(0,d[d.L-2]);24"\'":H d[d.L-1].1a(d[d.L-2]+d[0].L);5a:i="";g=+g;I(!g)H h;O(;g>d.L-3;){i=1r.Z.1a.W(g,-1)+i;g=1Q.3i(g/10)}H(g?d[g]||"":"$")+i}Y{g=+i;I(g<=d.L-3)H d[g];g=b?p(b,i):-1;H g>-1?d[g+1]:h}})})}I(a&&f.1J)f.12=0;H c};1r.Z.1e=6(f,e){I(!M.1R(f))H n.1e.1p(J,14);K a=J+"",b=[],c=0,d,h;I(e===1d||+e<0)e=5D;Y{e=1Q.3i(+e);I(!e)H[]}O(f=M.3c(f);d=f.X(a);){I(f.12>c){b.U(a.1a(c,d.P));d.L>1&&d.P<a.L&&3b.Z.U.1p(b,d.1a(1));h=d[0].L;c=f.12;I(b.L>=e)1N}f.12===d.P&&f.12++}I(c===a.L){I(!n.1A.W(f,"")||h)b.U("")}Y b.U(a.1a(c));H b.L>e?b.1a(0,e):b};M.1h(/\\(\\?#[^)]*\\)/,6(f){H n.1A.W(A,f.2S.1a(f.P+f[0].L))?"":"(?:)"});M.1h(/\\((?!\\?)/,6(){J.19.U(N);H"("});M.1h(/\\(\\?<([$\\w]+)>/,6(f){J.19.U(f[1]);J.2N=R;H"("});M.1h(/\\\\k<([\\w$]+)>/,6(f){K e=p(J.19,f[1]);H e>-1?"\\\\"+(e+1)+(3R(f.2S.3a(f.P+f[0].L))?"":"(?:)"):f[0]});M.1h(/\\[\\^?]/,6(f){H f[0]==="[]"?"\\\\b\\\\B":"[\\\\s\\\\S]"});M.1h(/^\\(\\?([5A]+)\\)/,6(f){J.3d(f[1]);H""});M.1h(/(?:\\s+|#.*)+/,6(f){H n.1A.W(A,f.2S.1a(f.P+f[0].L))?"":"(?:)"},M.1B,6(){H J.2K("x")});M.1h(/\\./,6(){H"[\\\\s\\\\S]"},M.1B,6(){H J.2K("s")})})();1j 2e!="1d"&&(2e.M=M);K 1v=6(){6 r(a,b){a.1l.1i(b)!=-1||(a.1l+=" "+b)}6 t(a){H a.1i("3e")==0?a:"3e"+a}6 B(a){H e.1Y.2A[t(a)]}6 p(a,b,c){I(a==N)H N;K d=c!=R?a.3G:[a.2G],h={"#":"1c",".":"1l"}[b.1o(0,1)]||"3h",g,i;g=h!="3h"?b.1o(1):b.5u();I((a[h]||"").1i(g)!=-1)H a;O(a=0;d&&a<d.L&&i==N;a++)i=p(d[a],b,c);H i}6 C(a,b){K c={},d;O(d 2g a)c[d]=a[d];O(d 2g b)c[d]=b[d];H c}6 w(a,b,c,d){6 h(g){g=g||1P.5y;I(!g.1F){g.1F=g.52;g.3N=6(){J.5w=11}}c.W(d||1P,g)}a.3g?a.3g("4U"+b,h):a.4y(b,h,11)}6 A(a,b){K c=e.1Y.2j,d=N;I(c==N){c={};O(K h 2g e.1U){K g=e.1U[h];d=g.4x;I(d!=N){g.1V=h.4w();O(g=0;g<d.L;g++)c[d[g]]=h}}e.1Y.2j=c}d=e.1U[c[a]];d==N&&b!=11&&1P.1X(e.13.1x.1X+(e.13.1x.3E+a));H d}6 v(a,b){O(K c=a.1e("\\n"),d=0;d<c.L;d++)c[d]=b(c[d],d);H c.1K("\\n")}6 u(a,b){I(a==N||a.L==0||a=="\\n")H a;a=a.Q(/</g,"&1y;");a=a.Q(/ {2,}/g,6(c){O(K d="",h=0;h<c.L-1;h++)d+=e.13.1W;H d+" "});I(b!=N)a=v(a,6(c){I(c.L==0)H"";K d="";c=c.Q(/^(&2s;| )+/,6(h){d=h;H""});I(c.L==0)H d;H d+\'<17 1g="\'+b+\'">\'+c+"</17>"});H a}6 n(a,b){a.1e("\\n");O(K c="",d=0;d<50;d++)c+=" ";H a=v(a,6(h){I(h.1i("\\t")==-1)H h;O(K g=0;(g=h.1i("\\t"))!=-1;)h=h.1o(0,g)+c.1o(0,b-g%b)+h.1o(g+1,h.L);H h})}6 x(a){H a.Q(/^\\s+|\\s+$/g,"")}6 D(a,b){I(a.P<b.P)H-1;Y I(a.P>b.P)H 1;Y I(a.L<b.L)H-1;Y I(a.L>b.L)H 1;H 0}6 y(a,b){6 c(k){H k[0]}O(K d=N,h=[],g=b.2D?b.2D:c;(d=b.1I.X(a))!=N;){K i=g(d,b);I(1j i=="3f")i=[1f e.2L(i,d.P,b.23)];h=h.1O(i)}H h}6 E(a){K b=/(.*)((&1G;|&1y;).*)/;H a.Q(e.3A.3M,6(c){K d="",h=N;I(h=b.X(c)){c=h[1];d=h[2]}H\'<a 2h="\'+c+\'">\'+c+"</a>"+d})}6 z(){O(K a=1E.36("1k"),b=[],c=0;c<a.L;c++)a[c].3s=="20"&&b.U(a[c]);H b}6 f(a){a=a.1F;K b=p(a,".20",R);a=p(a,".3O",R);K c=1E.4i("3t");I(!(!a||!b||p(a,"3t"))){B(b.1c);r(b,"1m");O(K d=a.3G,h=[],g=0;g<d.L;g++)h.U(d[g].4z||d[g].4A);h=h.1K("\\r");c.39(1E.4D(h));a.39(c);c.2C();c.4C();w(c,"4u",6(){c.2G.4E(c);b.1l=b.1l.Q("1m","")})}}I(1j 3F!="1d"&&1j M=="1d")M=3F("M").M;K e={2v:{"1g-27":"","2i-1s":1,"2z-1s-2t":11,1M:N,1t:N,"42-45":R,"43-22":4,1u:R,16:R,"3V-17":R,2l:11,"41-40":R,2k:11,"1z-1k":11},13:{1W:"&2s;",2M:R,46:11,44:11,34:"4n",1x:{21:"4o 1m",2P:"?",1X:"1v\\n\\n",3E:"4r\'t 4t 1D O: ",4g:"4m 4B\'t 51 O 1z-1k 4F: ",37:\'<!4T 1z 4S "-//4V//3H 4W 1.0 4Z//4Y" "1Z://2y.3L.3K/4X/3I/3H/3I-4P.4J"><1z 4I="1Z://2y.3L.3K/4L/5L"><3J><4N 1Z-4M="5G-5M" 6K="2O/1z; 6J=6I-8" /><1t>6L 1v</1t></3J><3B 1L="25-6M:6Q,6P,6O,6N-6F;6y-2f:#6x;2f:#6w;25-22:6v;2O-3D:3C;"><T 1L="2O-3D:3C;3w-32:1.6z;"><T 1L="25-22:6A-6E;">1v</T><T 1L="25-22:.6C;3w-6B:6R;"><T>3v 3.0.76 (72 73 3x)</T><T><a 2h="1Z://3u.2w/1v" 1F="38" 1L="2f:#3y">1Z://3u.2w/1v</a></T><T>70 17 6U 71.</T><T>6T 6X-3x 6Y 6D.</T></T><T>6t 61 60 J 1k, 5Z <a 2h="6u://2y.62.2w/63-66/65?64=5X-5W&5P=5O" 1L="2f:#3y">5R</a> 5V <2R/>5U 5T 5S!</T></T></3B></1z>\'}},1Y:{2j:N,2A:{}},1U:{},3A:{6n:/\\/\\*[\\s\\S]*?\\*\\//2c,6m:/\\/\\/.*$/2c,6l:/#.*$/2c,6k:/"([^\\\\"\\n]|\\\\.)*"/g,6o:/\'([^\\\\\'\\n]|\\\\.)*\'/g,6p:1f M(\'"([^\\\\\\\\"]|\\\\\\\\.)*"\',"3z"),6s:1f M("\'([^\\\\\\\\\']|\\\\\\\\.)*\'","3z"),6q:/(&1y;|<)!--[\\s\\S]*?--(&1G;|>)/2c,3M:/\\w+:\\/\\/[\\w-.\\/?%&=:@;]*/g,6a:{18:/(&1y;|<)\\?=?/g,1b:/\\?(&1G;|>)/g},69:{18:/(&1y;|<)%=?/g,1b:/%(&1G;|>)/g},6d:{18:/(&1y;|<)\\s*1k.*?(&1G;|>)/2T,1b:/(&1y;|<)\\/\\s*1k\\s*(&1G;|>)/2T}},16:{1H:6(a){6 b(i,k){H e.16.2o(i,k,e.13.1x[k])}O(K c=\'<T 1g="16">\',d=e.16.2x,h=d.2X,g=0;g<h.L;g++)c+=(d[h[g]].1H||b)(a,h[g]);c+="</T>";H c},2o:6(a,b,c){H\'<2W><a 2h="#" 1g="6e 6h\'+b+" "+b+\'">\'+c+"</a></2W>"},2b:6(a){K b=a.1F,c=b.1l||"";b=B(p(b,".20",R).1c);K d=6(h){H(h=15(h+"6f(\\\\w+)").X(c))?h[1]:N}("6g");b&&d&&e.16.2x[d].2B(b);a.3N()},2x:{2X:["21","2P"],21:{1H:6(a){I(a.V("2l")!=R)H"";K b=a.V("1t");H e.16.2o(a,"21",b?b:e.13.1x.21)},2B:6(a){a=1E.6j(t(a.1c));a.1l=a.1l.Q("47","")}},2P:{2B:6(){K a="68=0";a+=", 18="+(31.30-33)/2+", 32="+(31.2Z-2Y)/2+", 30=33, 2Z=2Y";a=a.Q(/^,/,"");a=1P.6Z("","38",a);a.2C();K b=a.1E;b.6W(e.13.1x.37);b.6V();a.2C()}}}},35:6(a,b){K c;I(b)c=[b];Y{c=1E.36(e.13.34);O(K d=[],h=0;h<c.L;h++)d.U(c[h]);c=d}c=c;d=[];I(e.13.2M)c=c.1O(z());I(c.L===0)H d;O(h=0;h<c.L;h++){O(K g=c[h],i=a,k=c[h].1l,j=3W 0,l={},m=1f M("^\\\\[(?<2V>(.*?))\\\\]$"),s=1f M("(?<27>[\\\\w-]+)\\\\s*:\\\\s*(?<1T>[\\\\w-%#]+|\\\\[.*?\\\\]|\\".*?\\"|\'.*?\')\\\\s*;?","g");(j=s.X(k))!=N;){K o=j.1T.Q(/^[\'"]|[\'"]$/g,"");I(o!=N&&m.1A(o)){o=m.X(o);o=o.2V.L>0?o.2V.1e(/\\s*,\\s*/):[]}l[j.27]=o}g={1F:g,1n:C(i,l)};g.1n.1D!=N&&d.U(g)}H d},1M:6(a,b){K c=J.35(a,b),d=N,h=e.13;I(c.L!==0)O(K g=0;g<c.L;g++){b=c[g];K i=b.1F,k=b.1n,j=k.1D,l;I(j!=N){I(k["1z-1k"]=="R"||e.2v["1z-1k"]==R){d=1f e.4l(j);j="4O"}Y I(d=A(j))d=1f d;Y 6H;l=i.3X;I(h.2M){l=l;K m=x(l),s=11;I(m.1i("<![6G[")==0){m=m.4h(9);s=R}K o=m.L;I(m.1i("]]\\>")==o-3){m=m.4h(0,o-3);s=R}l=s?m:l}I((i.1t||"")!="")k.1t=i.1t;k.1D=j;d.2Q(k);b=d.2F(l);I((i.1c||"")!="")b.1c=i.1c;i.2G.74(b,i)}}},2E:6(a){w(1P,"4k",6(){e.1M(a)})}};e.2E=e.2E;e.1M=e.1M;e.2L=6(a,b,c){J.1T=a;J.P=b;J.L=a.L;J.23=c;J.1V=N};e.2L.Z.1q=6(){H J.1T};e.4l=6(a){6 b(j,l){O(K m=0;m<j.L;m++)j[m].P+=l}K c=A(a),d,h=1f e.1U.5Y,g=J,i="2F 1H 2Q".1e(" ");I(c!=N){d=1f c;O(K k=0;k<i.L;k++)(6(){K j=i[k];g[j]=6(){H h[j].1p(h,14)}})();d.28==N?1P.1X(e.13.1x.1X+(e.13.1x.4g+a)):h.2J.U({1I:d.28.17,2D:6(j){O(K l=j.17,m=[],s=d.2J,o=j.P+j.18.L,F=d.28,q,G=0;G<s.L;G++){q=y(l,s[G]);b(q,o);m=m.1O(q)}I(F.18!=N&&j.18!=N){q=y(j.18,F.18);b(q,j.P);m=m.1O(q)}I(F.1b!=N&&j.1b!=N){q=y(j.1b,F.1b);b(q,j.P+j[0].5Q(j.1b));m=m.1O(q)}O(j=0;j<m.L;j++)m[j].1V=c.1V;H m}})}};e.4j=6(){};e.4j.Z={V:6(a,b){K c=J.1n[a];c=c==N?b:c;K d={"R":R,"11":11}[c];H d==N?c:d},3Y:6(a){H 1E.4i(a)},4c:6(a,b){K c=[];I(a!=N)O(K d=0;d<a.L;d++)I(1j a[d]=="2m")c=c.1O(y(b,a[d]));H J.4e(c.6b(D))},4e:6(a){O(K b=0;b<a.L;b++)I(a[b]!==N)O(K c=a[b],d=c.P+c.L,h=b+1;h<a.L&&a[b]!==N;h++){K g=a[h];I(g!==N)I(g.P>d)1N;Y I(g.P==c.P&&g.L>c.L)a[b]=N;Y I(g.P>=c.P&&g.P<d)a[h]=N}H a},4d:6(a){K b=[],c=2u(J.V("2i-1s"));v(a,6(d,h){b.U(h+c)});H b},3U:6(a){K b=J.V("1M",[]);I(1j b!="2m"&&b.U==N)b=[b];a:{a=a.1q();K c=3W 0;O(c=c=1Q.6c(c||0,0);c<b.L;c++)I(b[c]==a){b=c;1N a}b=-1}H b!=-1},2r:6(a,b,c){a=["1s","6i"+b,"P"+a,"6r"+(b%2==0?1:2).1q()];J.3U(b)&&a.U("67");b==0&&a.U("1N");H\'<T 1g="\'+a.1K(" ")+\'">\'+c+"</T>"},3Q:6(a,b){K c="",d=a.1e("\\n").L,h=2u(J.V("2i-1s")),g=J.V("2z-1s-2t");I(g==R)g=(h+d-1).1q().L;Y I(3R(g)==R)g=0;O(K i=0;i<d;i++){K k=b?b[i]:h+i,j;I(k==0)j=e.13.1W;Y{j=g;O(K l=k.1q();l.L<j;)l="0"+l;j=l}a=j;c+=J.2r(i,k,a)}H c},49:6(a,b){a=x(a);K c=a.1e("\\n");J.V("2z-1s-2t");K d=2u(J.V("2i-1s"));a="";O(K h=J.V("1D"),g=0;g<c.L;g++){K i=c[g],k=/^(&2s;|\\s)+/.X(i),j=N,l=b?b[g]:d+g;I(k!=N){j=k[0].1q();i=i.1o(j.L);j=j.Q(" ",e.13.1W)}i=x(i);I(i.L==0)i=e.13.1W;a+=J.2r(g,l,(j!=N?\'<17 1g="\'+h+\' 5N">\'+j+"</17>":"")+i)}H a},4f:6(a){H a?"<4a>"+a+"</4a>":""},4b:6(a,b){6 c(l){H(l=l?l.1V||g:g)?l+" ":""}O(K d=0,h="",g=J.V("1D",""),i=0;i<b.L;i++){K k=b[i],j;I(!(k===N||k.L===0)){j=c(k);h+=u(a.1o(d,k.P-d),j+"48")+u(k.1T,j+k.23);d=k.P+k.L+(k.75||0)}}h+=u(a.1o(d),c()+"48");H h},1H:6(a){K b="",c=["20"],d;I(J.V("2k")==R)J.1n.16=J.1n.1u=11;1l="20";J.V("2l")==R&&c.U("47");I((1u=J.V("1u"))==11)c.U("6S");c.U(J.V("1g-27"));c.U(J.V("1D"));a=a.Q(/^[ ]*[\\n]+|[\\n]*[ ]*$/g,"").Q(/\\r/g," ");b=J.V("43-22");I(J.V("42-45")==R)a=n(a,b);Y{O(K h="",g=0;g<b;g++)h+=" ";a=a.Q(/\\t/g,h)}a=a;a:{b=a=a;h=/<2R\\s*\\/?>|&1y;2R\\s*\\/?&1G;/2T;I(e.13.46==R)b=b.Q(h,"\\n");I(e.13.44==R)b=b.Q(h,"");b=b.1e("\\n");h=/^\\s*/;g=4Q;O(K i=0;i<b.L&&g>0;i++){K k=b[i];I(x(k).L!=0){k=h.X(k);I(k==N){a=a;1N a}g=1Q.4q(k[0].L,g)}}I(g>0)O(i=0;i<b.L;i++)b[i]=b[i].1o(g);a=b.1K("\\n")}I(1u)d=J.4d(a);b=J.4c(J.2J,a);b=J.4b(a,b);b=J.49(b,d);I(J.V("41-40"))b=E(b);1j 2H!="1d"&&2H.3S&&2H.3S.1C(/5s/)&&c.U("5t");H b=\'<T 1c="\'+t(J.1c)+\'" 1g="\'+c.1K(" ")+\'">\'+(J.V("16")?e.16.1H(J):"")+\'<3Z 5z="0" 5H="0" 5J="0">\'+J.4f(J.V("1t"))+"<3T><3P>"+(1u?\'<2d 1g="1u">\'+J.3Q(a)+"</2d>":"")+\'<2d 1g="17"><T 1g="3O">\'+b+"</T></2d></3P></3T></3Z></T>"},2F:6(a){I(a===N)a="";J.17=a;K b=J.3Y("T");b.3X=J.1H(a);J.V("16")&&w(p(b,".16"),"5c",e.16.2b);J.V("3V-17")&&w(p(b,".17"),"56",f);H b},2Q:6(a){J.1c=""+1Q.5d(1Q.5n()*5k).1q();e.1Y.2A[t(J.1c)]=J;J.1n=C(e.2v,a||{});I(J.V("2k")==R)J.1n.16=J.1n.1u=11},5j:6(a){a=a.Q(/^\\s+|\\s+$/g,"").Q(/\\s+/g,"|");H"\\\\b(?:"+a+")\\\\b"},5f:6(a){J.28={18:{1I:a.18,23:"1k"},1b:{1I:a.1b,23:"1k"},17:1f M("(?<18>"+a.18.1m+")(?<17>.*?)(?<1b>"+a.1b.1m+")","5o")}}};H e}();1j 2e!="1d"&&(2e.1v=1v);',62,441,'||||||function|||||||||||||||||||||||||||||||||||||return|if|this|var|length|XRegExp|null|for|index|replace|true||div|push|getParam|call|exec|else|prototype||false|lastIndex|config|arguments|RegExp|toolbar|code|left|captureNames|slice|right|id|undefined|split|new|class|addToken|indexOf|typeof|script|className|source|params|substr|apply|toString|String|line|title|gutter|SyntaxHighlighter|_xregexp|strings|lt|html|test|OUTSIDE_CLASS|match|brush|document|target|gt|getHtml|regex|global|join|style|highlight|break|concat|window|Math|isRegExp|throw|value|brushes|brushName|space|alert|vars|http|syntaxhighlighter|expandSource|size|css|case|font|Fa|name|htmlScript|dA|can|handler|gm|td|exports|color|in|href|first|discoveredBrushes|light|collapse|object|cache|getButtonHtml|trigger|pattern|getLineHtml|nbsp|numbers|parseInt|defaults|com|items|www|pad|highlighters|execute|focus|func|all|getDiv|parentNode|navigator|INSIDE_CLASS|regexList|hasFlag|Match|useScriptTags|hasNamedCapture|text|help|init|br|input|gi|Error|values|span|list|250|height|width|screen|top|500|tagName|findElements|getElementsByTagName|aboutDialog|_blank|appendChild|charAt|Array|copyAsGlobal|setFlag|highlighter_|string|attachEvent|nodeName|floor|backref|output|the|TypeError|sticky|Za|iterate|freezeTokens|scope|type|textarea|alexgorbatchev|version|margin|2010|005896|gs|regexLib|body|center|align|noBrush|require|childNodes|DTD|xhtml1|head|org|w3|url|preventDefault|container|tr|getLineNumbersHtml|isNaN|userAgent|tbody|isLineHighlighted|quick|void|innerHTML|create|table|links|auto|smart|tab|stripBrs|tabs|bloggerMode|collapsed|plain|getCodeLinesHtml|caption|getMatchesHtml|findMatches|figureOutLineNumbers|removeNestedMatches|getTitleHtml|brushNotHtmlScript|substring|createElement|Highlighter|load|HtmlScript|Brush|pre|expand|multiline|min|Can|ignoreCase|find|blur|extended|toLowerCase|aliases|addEventListener|innerText|textContent|wasn|select|createTextNode|removeChild|option|same|frame|xmlns|dtd|twice|1999|equiv|meta|htmlscript|transitional|1E3|expected|PUBLIC|DOCTYPE|on|W3C|XHTML|TR|EN|Transitional||configured|srcElement|Object|after|run|dblclick|matchChain|valueOf|constructor|default|switch|click|round|execAt|forHtmlScript|token|gimy|functions|getKeywords|1E6|escape|within|random|sgi|another|finally|supply|MSIE|ie|toUpperCase|catch|returnValue|definition|event|border|imsx|constructing|one|Infinity|from|when|Content|cellpadding|flags|cellspacing|try|xhtml|Type|spaces|2930402|hosted_button_id|lastIndexOf|donate|active|development|keep|to|xclick|_s|Xml|please|like|you|paypal|cgi|cmd|webscr|bin|highlighted|scrollbars|aspScriptTags|phpScriptTags|sort|max|scriptScriptTags|toolbar_item|_|command|command_|number|getElementById|doubleQuotedString|singleLinePerlComments|singleLineCComments|multiLineCComments|singleQuotedString|multiLineDoubleQuotedString|xmlComments|alt|multiLineSingleQuotedString|If|https|1em|000|fff|background|5em|xx|bottom|75em|Gorbatchev|large|serif|CDATA|continue|utf|charset|content|About|family|sans|Helvetica|Arial|Geneva|3em|nogutter|Copyright|syntax|close|write|2004|Alex|open|JavaScript|highlighter|July|02|replaceChild|offset|83'.split('|'),0,{}))
/*{{{*/
/**
* SyntaxHighlighter
* http://alexgorbatchev.com/SyntaxHighlighter
*
* SyntaxHighlighter is donationware. If you are using it, please donate.
* http://alexgorbatchev.com/SyntaxHighlighter/donate.html
*
* @version
* 3.0.83 (July 02 2010)
*
* @copyright
* Copyright (C) 2004-2010 Alex Gorbatchev.
*
* @license
* Dual licensed under the MIT and GPL licenses.
*/
.syntaxhighlighter {
background-color: white !important;
}
.syntaxhighlighter .line.alt1 {
background-color: white !important;
}
.syntaxhighlighter .line.alt2 {
background-color: white !important;
}
.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 {
background-color: #e0e0e0 !important;
}
.syntaxhighlighter .line.highlighted.number {
color: black !important;
}
.syntaxhighlighter table caption {
color: black !important;
}
.syntaxhighlighter .gutter {
color: #afafaf !important;
}
.syntaxhighlighter .gutter .line {
border-right: 3px solid #6ce26c !important;
}
.syntaxhighlighter .gutter .line.highlighted {
background-color: #6ce26c !important;
color: white !important;
}
.syntaxhighlighter.printing .line .content {
border: none !important;
}
.syntaxhighlighter.collapsed {
overflow: visible !important;
}
.syntaxhighlighter.collapsed .toolbar {
color: blue !important;
background: white !important;
border: 1px solid #6ce26c !important;
}
.syntaxhighlighter.collapsed .toolbar a {
color: blue !important;
}
.syntaxhighlighter.collapsed .toolbar a:hover {
color: red !important;
}
.syntaxhighlighter .toolbar {
color: white !important;
background: #6ce26c !important;
border: none !important;
}
.syntaxhighlighter .toolbar a {
color: white !important;
}
.syntaxhighlighter .toolbar a:hover {
color: black !important;
}
.syntaxhighlighter .plain, .syntaxhighlighter .plain a {
color: black !important;
}
.syntaxhighlighter .comments, .syntaxhighlighter .comments a {
color: #008200 !important;
}
.syntaxhighlighter .string, .syntaxhighlighter .string a {
color: blue !important;
}
.syntaxhighlighter .keyword {
color: #006699 !important;
}
.syntaxhighlighter .preprocessor {
color: gray !important;
}
.syntaxhighlighter .variable {
color: #aa7700 !important;
}
.syntaxhighlighter .value {
color: #009900 !important;
}
.syntaxhighlighter .functions {
color: #ff1493 !important;
}
.syntaxhighlighter .constants {
color: #0066cc !important;
}
.syntaxhighlighter .script {
font-weight: bold !important;
color: #006699 !important;
background-color: none !important;
}
.syntaxhighlighter .color1, .syntaxhighlighter .color1 a {
color: gray !important;
}
.syntaxhighlighter .color2, .syntaxhighlighter .color2 a {
color: #ff1493 !important;
}
.syntaxhighlighter .color3, .syntaxhighlighter .color3 a {
color: red !important;
}
.syntaxhighlighter .keyword {
font-weight: bold !important;
}
/*}}}*/
/***
<<highlightSyntax>>
***/
show index from t1 in db1
<<search>><<closeAll>>
<script>
if (config.options.txtUserName=="Lindrid") return "<<permaview>><<newTiddler>><<newJournal \"DD MMM YYYY\" \"journal\">><<saveChanges>>";
</script>
<<tiddler TspotSidebar>><<slider chkSliderOptionsPanel OptionsPanel "options »" "Change TiddlyWiki advanced options">>
<script>
if (config.options.txtUserName=="Lindrid") return "<<tabs txtMainTab \"Timeline\" \"Timeline\" TabTimeline \"All\" \"All tiddlers\" TabAll \"Tags\" \"All tags\" TabTags \"More\" \"More lists\" TabMore>>";
</script>
/***
|Name|SinglePageModePlugin|
|Source|http://www.TiddlyTools.com/#SinglePageModePlugin|
|Documentation|http://www.TiddlyTools.com/#SinglePageModePluginInfo|
|Version|2.9.7|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|Show tiddlers one at a time with automatic permalink, or always open tiddlers at top/bottom of page.|
This plugin allows you to configure TiddlyWiki to navigate more like a traditional multipage web site with only one tiddler displayed at a time.
!!!!!Documentation
>see [[SinglePageModePluginInfo]]
!!!!!Configuration
<<<
<<option chkSinglePageMode>> Display one tiddler at a time
><<option chkSinglePagePermalink>> Automatically permalink current tiddler
><<option chkSinglePageKeepFoldedTiddlers>> Don't close tiddlers that are folded
><<option chkSinglePageKeepEditedTiddlers>> Don't close tiddlers that are being edited
<<option chkTopOfPageMode>> Open tiddlers at the top of the page
<<option chkBottomOfPageMode>> Open tiddlers at the bottom of the page
<<option chkSinglePageAutoScroll>> Automatically scroll tiddler into view (if needed)
Notes:
* The "display one tiddler at a time" option can also be //temporarily// set/reset by including a 'paramifier' in the document URL: {{{#SPM:true}}} or {{{#SPM:false}}}.
* If more than one display mode is selected, 'one at a time' display takes precedence over both 'top' and 'bottom' settings, and if 'one at a time' setting is not used, 'top of page' takes precedence over 'bottom of page'.
* When using Apple's Safari browser, automatically setting the permalink causes an error and is disabled.
<<<
!!!!!Revisions
<<<
2010.11.30 2.9.7 use story.getTiddler()
2008.10.17 2.9.6 changed chkSinglePageAutoScroll default to false
| Please see [[SinglePageModePluginInfo]] for previous revision details |
2005.08.15 1.0.0 Initial Release. Support for BACK/FORWARD buttons adapted from code developed by Clint Checketts.
<<<
!!!!!Code
***/
//{{{
version.extensions.SinglePageModePlugin= {major: 2, minor: 9, revision: 7, date: new Date(2010,11,30)};
//}}}
//{{{
config.paramifiers.SPM = { onstart: function(v) {
config.options.chkSinglePageMode=eval(v);
if (config.options.chkSinglePageMode && config.options.chkSinglePagePermalink && !config.browser.isSafari) {
config.lastURL = window.location.hash;
if (!config.SPMTimer) config.SPMTimer=window.setInterval(function() {checkLastURL();},1000);
}
} };
//}}}
//{{{
if (config.options.chkSinglePageMode==undefined)
config.options.chkSinglePageMode=false;
if (config.options.chkSinglePagePermalink==undefined)
config.options.chkSinglePagePermalink=true;
if (config.options.chkSinglePageKeepFoldedTiddlers==undefined)
config.options.chkSinglePageKeepFoldedTiddlers=false;
if (config.options.chkSinglePageKeepEditedTiddlers==undefined)
config.options.chkSinglePageKeepEditedTiddlers=false;
if (config.options.chkTopOfPageMode==undefined)
config.options.chkTopOfPageMode=false;
if (config.options.chkBottomOfPageMode==undefined)
config.options.chkBottomOfPageMode=false;
if (config.options.chkSinglePageAutoScroll==undefined)
config.options.chkSinglePageAutoScroll=false;
//}}}
//{{{
config.SPMTimer = 0;
config.lastURL = window.location.hash;
function checkLastURL()
{
if (!config.options.chkSinglePageMode)
{ window.clearInterval(config.SPMTimer); config.SPMTimer=0; return; }
if (config.lastURL == window.location.hash) return; // no change in hash
var tids=decodeURIComponent(window.location.hash.substr(1)).readBracketedList();
if (tids.length==1) // permalink (single tiddler in URL)
story.displayTiddler(null,tids[0]);
else { // restore permaview or default view
config.lastURL = window.location.hash;
if (!tids.length) tids=store.getTiddlerText("DefaultTiddlers").readBracketedList();
story.closeAllTiddlers();
story.displayTiddlers(null,tids);
}
}
if (Story.prototype.SPM_coreDisplayTiddler==undefined)
Story.prototype.SPM_coreDisplayTiddler=Story.prototype.displayTiddler;
Story.prototype.displayTiddler = function(srcElement,tiddler,template,animate,slowly)
{
var title=(tiddler instanceof Tiddler)?tiddler.title:tiddler;
var tiddlerElem=story.getTiddler(title); // ==null unless tiddler is already displayed
var opt=config.options;
var single=opt.chkSinglePageMode && !startingUp;
var top=opt.chkTopOfPageMode && !startingUp;
var bottom=opt.chkBottomOfPageMode && !startingUp;
if (single) {
story.forEachTiddler(function(tid,elem) {
// skip current tiddler and, optionally, tiddlers that are folded.
if ( tid==title
|| (opt.chkSinglePageKeepFoldedTiddlers && elem.getAttribute("folded")=="true"))
return;
// if a tiddler is being edited, ask before closing
if (elem.getAttribute("dirty")=="true") {
if (opt.chkSinglePageKeepEditedTiddlers) return;
// if tiddler to be displayed is already shown, then leave active tiddler editor as is
// (occurs when switching between view and edit modes)
if (tiddlerElem) return;
// otherwise, ask for permission
var msg="'"+tid+"' is currently being edited.\n\n";
msg+="Press OK to save and close this tiddler\nor press Cancel to leave it opened";
if (!confirm(msg)) return; else story.saveTiddler(tid);
}
story.closeTiddler(tid);
});
}
else if (top)
arguments[0]=null;
else if (bottom)
arguments[0]="bottom";
if (single && opt.chkSinglePagePermalink && !config.browser.isSafari) {
window.location.hash = encodeURIComponent(String.encodeTiddlyLink(title));
config.lastURL = window.location.hash;
document.title = wikifyPlain("SiteTitle") + " - " + title;
if (!config.SPMTimer) config.SPMTimer=window.setInterval(function() {checkLastURL();},1000);
}
if (tiddlerElem && tiddlerElem.getAttribute("dirty")=="true") { // editing... move tiddler without re-rendering
var isTopTiddler=(tiddlerElem.previousSibling==null);
if (!isTopTiddler && (single || top))
tiddlerElem.parentNode.insertBefore(tiddlerElem,tiddlerElem.parentNode.firstChild);
else if (bottom)
tiddlerElem.parentNode.insertBefore(tiddlerElem,null);
else this.SPM_coreDisplayTiddler.apply(this,arguments); // let CORE render tiddler
} else
this.SPM_coreDisplayTiddler.apply(this,arguments); // let CORE render tiddler
var tiddlerElem=story.getTiddler(title);
if (tiddlerElem&&opt.chkSinglePageAutoScroll) {
// scroll to top of page or top of tiddler
var isTopTiddler=(tiddlerElem.previousSibling==null);
var yPos=isTopTiddler?0:ensureVisible(tiddlerElem);
// if animating, defer scroll until after animation completes
var delay=opt.chkAnimate?config.animDuration+10:0;
setTimeout("window.scrollTo(0,"+yPos+")",delay);
}
}
if (Story.prototype.SPM_coreDisplayTiddlers==undefined)
Story.prototype.SPM_coreDisplayTiddlers=Story.prototype.displayTiddlers;
Story.prototype.displayTiddlers = function() {
// suspend single/top/bottom modes when showing multiple tiddlers
var opt=config.options;
var saveSPM=opt.chkSinglePageMode; opt.chkSinglePageMode=false;
var saveTPM=opt.chkTopOfPageMode; opt.chkTopOfPageMode=false;
var saveBPM=opt.chkBottomOfPageMode; opt.chkBottomOfPageMode=false;
this.SPM_coreDisplayTiddlers.apply(this,arguments);
opt.chkBottomOfPageMode=saveBPM;
opt.chkTopOfPageMode=saveTPM;
opt.chkSinglePageMode=saveSPM;
}
//}}}
Lindrid - [[TiddlyWiki Reference|http://tiddlywiki.com/#Reference]]
[[Notes on programming|Root]]
http://trish.in/articles/tverdye-obektno-orientirovannye-principy
/***
|''Name:''|SortableGridPlugin|
|''Description:''|Provide live sorting of tables by column|
|''Date:''|Sep. 29, 2007|
|''Source:''|[[SortableGridPlugin|http://rumkin.com/tools/tiddlywiki/#SortableGridPlugin]]|
|''Author:''|Stuart Langridge, Demian Johnson, Bob Denny|
|''License:''|See Below|
|''Version:''|1.1.3|
|''~CoreVersion:''|2.0.11, 2.1.x and newer|
|''Browser:''|Firefox 1.5/2.0; Internet Explorer 6.0/7.0; Safari|
!!Description
@@Only minor changes by Tyler to make it work with TiddlyWiki 2.2.x and newer@@
This plugin provides live sorting of tables by clicking on a column header. To sort in reverse, click the same column header a second time. An arrow in the sort column shows the direction of sorting.
It works by trying to automatically detect the type of data in a column, then sorting by the rules for that data type. Note that the data in the first row (before sorting for the first time) is used for type detection, so if other data types exist in the column below the first row, the results will be unpredictable. If it //can// recognize the string as prticular type it //will// sort that column by that type. Moral: keep all of your data in a column the same type. The following data types are checked in the order shown (in other words the table shows the precedence of type detection):
|!Type |!Description|
|Date|Various formats for dates, specifically any string format that can be converted to a date/time by Javascript's Date.Parse() method.|
|Currency|Any string beginning with $, £, or € followed by a numeric string (except no leading sign). Note that it does not do currency conversion, the raw currency values are sorted numerically. {{{/^[$|£|€]{1}\d*\.{0,1}\d+$/}}}|
|Numeric|Data must consist purely of digits, optional leading plus or minus sign, a single period. Javascript cannot handle the Continental virgule (comma decimal point). {{{/^[\+|\-]{0,1}\d*\.{0,1}\d+$/}}}|
|File Size|Numeric string (except no leading sign) with b, Kb, Mb, or Gb at the end. Sorts according to the actual value represented by the notation. {{{/^\d*\.{0,1}\d+[K|M|G]{0,1}b$}}}|
|Text|Anything that does not match the formats listed below. Text is sorted without regard to character case.|
!!Installation
Follow the usual procedure for installing a plugin: Edit this tiddler, copy, paste into a new tiddler in your TW, and tag it systemConfig. Close, Save, and Shift-Reload your TW's page. The table below (in Example) should have hot column headers and be sortable.
!!Usage
To make a table sortable, append an {{{h}}} to the end of the first row. If the table is thus marked as sortable, the formatter will add a CSS class {{{sortable}}} to the generated {{{<table>}}} element. Thus you can use CSS to alter the appearance of the sortable table and/or its elements.
!!Example
|Name |Salary |Extension |Performance |File Size |Start date |h
|Bloggs, Fred |$12000.00 |1353 |+1.2 |74.2Kb |Aug 19, 2003 21:34:00 |
|Bloggs, Fred |$12000.00 |1353 |1.2 |3350b |09/18/2003 |
|Bloggs, Fred |$12000 |1353 |1.200 |55.2Kb |August 18, 2003 |
|Bloggs, Fred |$12000.00 |1353 |1.2 |2100b |07/18/2003 |
|Bloggs, Fred |$12000.00 |1353 |01.20 |6.156Mb |08/17/2003 05:43 |
|Turvey, Kevin |$191200.00 |2342 |-33 |1b |02/05/1979 |
|Mbogo, Arnold |$32010.12 |2755 |-21.673 |1.2Gb |09/08/1998 |
|Shakespeare, Bill |£122000.00|3211 |6 |33.22Gb |12/11/1961 |
|Shakespeare, Hamlet |£9000 |9005 |-8 |3Gb |01/01/2002 |
|Fitz, Marvin |€3300.30 |5554 |+5 |4Kb |05/22/1995 |
!!Revision History
<<<
''2003.11.?? [?.?.?]'' Stuart Langridge (http://www.kryogenix.org/code/browser/sorttable/) - Core code for DHTML sortable tables. Copyright and license for his code has been carried forward and applies to subsequent additions.
''2006.02.14 [1.0.0]'' Demian Johnson - Initial release, adaptation of Langridge code to TiddlyWiki.
''2006.09.29 [1.1.0]'' Bob Denny - Add standard-format plugin documentation, reformat and tabify code for readability, refactor references to plugin, add new "file size" detection and sorting, add sterling and euro to currency detection, allow any real numbers including optional sign and either period or comma for decimal point for numeric sorting, make RegExp matching strict for currency and numeric, clean up lint warnings, correct spelling of Hamlet's name.
''2006.10.19 [1.1.1]'' Bob Denny - Allow use with TW 2.1.1 and 2.1.2, hijack is identical with 2.1.0.
''2006.11.04 [1.1.2]'' Bob Denny - Oh hell, accept 2.1.x, bit again by 2.1.3 which was OK.
<<<
!!Code
***/
//{{{
//
// Begin SORTABLE.JS
// This Code is:
// Code downloaded from the Browser Experiments section of kryogenix.org is
// licenced under the so-called MIT licence. The license is below.
// ----------------------------------------
// Copyright (c) 1997-date Stuart Langridge
// ----------------------------------------
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// Modified under the same aforementioned terms by Demian Johnston, 2006
// Further modified under the same aforementioned terms by Bob Denny, 2006:
// 1. Add flexible date/time
// 2. Use 'this' instead of full dotted names
// 3. Re-indent and tabify after being munged by TW/IE bu
// 4. Add "file size" sensing and sorting. Validate with Javascript Lint
// Modified under the same aforementioned terms by Tyler Akins, 2007
// Works work with TiddlyWiki 2.2.x
//
version.extensions.PersistentForm = {
major: 1, minor: 1, revision: 3,
date: new Date(2007, 9, 29),
type: 'extension',
source: "http://rumkin.com/tools/tiddlywiki/#SortableGridPlugin"
};
//}}}
//{{{
config.macros.sortableGridPlugin = { SORT_COLUMN_INDEX: 0 };
config.macros.sortableGridPlugin.ts_makeSortable = function(table)
{
var firstRow;
if (table.rows && table.rows.length > 0) {
firstRow = table.rows[0];
}
if (!firstRow) return;
// We have a first row: assume it's the header, and make its contents clickable links
for (var i=0;i<firstRow.cells.length;i++) {
var cell = firstRow.cells[i];
var txt = config.macros.sortableGridPlugin.ts_getInnerText(cell);
cell.innerHTML = '<a href="#" class="sortheader" onclick="config.macros.sortableGridPlugin.ts_resortTable(this);return false;">' +
txt + '<span class="sortarrow"> </span></a>';
}
};
//}}}
//{{{
config.macros.sortableGridPlugin.ts_getInnerText = function(el)
{
if (typeof el == "string") return el;
if (typeof el == "undefined") { return el; }
if (el.innerText) return el.innerText; //Not needed but it is faster
var str = "";
var cs = el.childNodes;
var l = cs.length;
for (var i = 0; i < l; i++) {
switch (cs[i].nodeType)
{
case 1: //ELEMENT_NODE
str += config.macros.sortableGridPlugin.ts_getInnerText(cs[i]);
break;
case 3: //TEXT_NODE
str += cs[i].nodeValue;
break;
}
}
return str;
};
config.macros.sortableGridPlugin.getParent = function(el, pTagName)
{
if (el === null)
return null;
else if (el.nodeType == 1 && el.tagName.toLowerCase() == pTagName.toLowerCase()) // Gecko bug, supposed to be uppercase
return el;
else
return config.macros.sortableGridPlugin.getParent(el.parentNode, pTagName);
};
//}}}
//{{{
config.macros.sortableGridPlugin.ts_resortTable = function(lnk)
{
var M = config.macros.sortableGridPlugin;
// get the span
var span;
for (var ci = 0; ci < lnk.childNodes.length; ci++) {
if (lnk.childNodes[ci].tagName && lnk.childNodes[ci].tagName.toLowerCase() == 'span')
span = lnk.childNodes[ci];
}
var td = lnk.parentNode;
var column = td.cellIndex;
var table = M.getParent(td,'TABLE');
// Work out a type for the column
if (table.rows.length <= 1) return;
var itm = M.ts_getInnerText(table.rows[1].cells[column]);
var sortfn = M.ts_sort_caseinsensitive;
if(!isNaN(Date.parse(itm)))
sortfn = M.ts_sort_date;
else if(itm.match(/^[$|£|€]{1}\d*\.{0,1}\d+$/))
sortfn = M.ts_sort_currency;
else if(itm.match(/^[\+|\-]{0,1}\d*\.{0,1}\d+$/))
sortfn = M.ts_sort_numeric;
else if(itm.match(/^\d*\.{0,1}\d+[K|M|G]{0,1}b$/))
sortfn = M.ts_sort_fileSize;
M.SORT_COLUMN_INDEX = column;
var firstRow = new Array();
var newRows = new Array();
for (var i = 0; i < table.rows[0].length; i++) { firstRow[i] = table.rows[0][i]; }
for (var j = 1; j < table.rows.length; j++) { newRows[j-1] = table.rows[j]; }
newRows.sort(sortfn);
var ARROW;
if (span.getAttribute("sortdir") == 'down') {
ARROW = ' ↑';
newRows.reverse();
span.setAttribute('sortdir','up');
} else {
ARROW = ' ↓';
span.setAttribute('sortdir','down');
}
// We appendChild rows that already exist to the tbody, so it moves them
// rather than creating new ones. Don't do sortbottom rows
for ( i=0;i<newRows.length;i++) {
if (!newRows[i].className || (newRows[i].className && (newRows[i].className.indexOf('sortbottom') == -1)))
table.tBodies[0].appendChild(newRows[i]);
}
// do sortbottom rows only
for ( i=0;i<newRows.length;i++) {
if (newRows[i].className && (newRows[i].className.indexOf('sortbottom') != -1))
table.tBodies[0].appendChild(newRows[i]);
}
// Delete any other arrows there may be showing
var allspans = document.getElementsByTagName("span");
for ( ci=0;ci<allspans.length;ci++) {
if (allspans[ci].className == 'sortarrow') {
if (M.getParent(allspans[ci],"table") == M.getParent(lnk,"table")) { // in the same table as us?
allspans[ci].innerHTML = ' ';
}
}
}
span.innerHTML = ARROW;
};
//}}}
//{{{
config.macros.sortableGridPlugin.ts_sort_fileSize = function(a, b)
{
var M = config.macros.sortableGridPlugin;
var convert = function(str)
{
var val;
var i;
if((i = str.indexOf("Kb")) != -1)
val = 1024.0 * str.substr(0, i);
else if((i = str.indexOf("Mb")) != -1)
val = 1048576.0 * str.substr(0, i);
else if((i = str.indexOf("Gb")) != -1)
val = 1073741824.0 * str.substr(0, i);
else
val = 1.0 * str.substr(0, str.length - 1);
return val;
};
var aa = M.ts_getInnerText(a.cells[M.SORT_COLUMN_INDEX]);
var bb = M.ts_getInnerText(b.cells[M.SORT_COLUMN_INDEX]);
var v1 = convert(aa);
var v2 = convert(bb);
if(v1 == v2) return 0;
if(v1 < v2) return -1;
return 1;
};
config.macros.sortableGridPlugin.ts_sort_date = function(a, b)
{
var M = config.macros.sortableGridPlugin;
// Handles dates per the rules of Date.parse()
var aa = M.ts_getInnerText(a.cells[M.SORT_COLUMN_INDEX]);
var bb = M.ts_getInnerText(b.cells[M.SORT_COLUMN_INDEX]);
var dt1 = Date.parse(aa);
var dt2 = Date.parse(bb);
if (dt1 == dt2) return 0;
if (dt1 < dt2) return -1;
return 1;
};
config.macros.sortableGridPlugin.ts_sort_currency = function(a, b)
{
var M = config.macros.sortableGridPlugin;
var aa = M.ts_getInnerText(a.cells[M.SORT_COLUMN_INDEX]).replace(/[^0-9.]/g,'');
var bb = M.ts_getInnerText(b.cells[M.SORT_COLUMN_INDEX]).replace(/[^0-9.]/g,'');
return parseFloat(aa) - parseFloat(bb);
};
config.macros.sortableGridPlugin.ts_sort_numeric = function(a, b)
{
var M = config.macros.sortableGridPlugin;
var aa = parseFloat(M.ts_getInnerText(a.cells[M.SORT_COLUMN_INDEX]));
if (isNaN(aa)) aa = 0;
var bb = parseFloat(M.ts_getInnerText(b.cells[M.SORT_COLUMN_INDEX]));
if (isNaN(bb)) bb = 0;
return aa-bb;
};
config.macros.sortableGridPlugin.ts_sort_caseinsensitive = function(a, b)
{
var M = config.macros.sortableGridPlugin;
var aa = M.ts_getInnerText(a.cells[M.SORT_COLUMN_INDEX]).toLowerCase();
var bb = M.ts_getInnerText(b.cells[M.SORT_COLUMN_INDEX]).toLowerCase();
if (aa == bb) return 0;
if (aa < bb) return -1;
return 1;
};
//}}}
//{{{
// end Code downloaded from the Browser Experiments section of kryogenix.org
// end Copyright (c) 1997-date Stuart Langridge//
// END SORTABLE.JS//
//}}}
//{{{
//
//
// CORE HIJACK WARNINGS:
// (1) Depends on the table formatter being first in the config.formatters array
// (2) Version-specifics - test on your version before adding to the logic here!
//
if(version.major == 2 && version.minor === 0 && version.revision == 11)
{
config.formatters[0].handler = function(w)
{
var table = createTiddlyElement(w.output,"table");
w.nextMatch = w.matchStart;
var lookaheadRegExp = new RegExp(this.lookahead,"mg");
var currRowType = null, nextRowType;
var rowContainer, rowElement;
var prevColumns = [];
var rowCount = 0;
var want_sortable=0;
do {
lookaheadRegExp.lastIndex = w.nextMatch;
var lookaheadMatch = lookaheadRegExp.exec(w.source);
var matched = lookaheadMatch && lookaheadMatch.index == w.nextMatch;
if(matched)
{
nextRowType = lookaheadMatch[2];
if(nextRowType != currRowType)
rowContainer = createTiddlyElement(table,this.rowTypes[nextRowType]);
currRowType = nextRowType;
if(currRowType == "c")
{
if(rowCount === 0)
rowContainer.setAttribute("align","top");
else
rowContainer.setAttribute("align","bottom");
w.nextMatch = w.nextMatch + 1;
w.subWikify(rowContainer,this.rowTerminator);
table.insertBefore(rowContainer,table.firstChild);
}
else
{
var rowClass = (rowCount & 1) ? "oddRow" : "evenRow";
rowElement = createTiddlyElement(rowContainer,"tr",null,rowClass);
this.rowHandler(w,rowElement,prevColumns);
}
if(currRowType == "h") {
want_sortable=1;
}
rowCount++;
}
} while(matched);
if (want_sortable) {
table.setAttribute("class","sortable");
config.macros.sortableGridPlugin.ts_makeSortable(table);
}
};
}
else if(version.major == 2 && (version.minor > 0))
{
config.formatters[0].handler = function(w)
{
var table = createTiddlyElement(w.output,"table");
var prevColumns = [];
var currRowType = null;
var rowContainer;
var rowCount = 0;
var want_sortable = 0;
w.nextMatch = w.matchStart;
this.lookaheadRegExp.lastIndex = w.nextMatch;
var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
while(lookaheadMatch && lookaheadMatch.index == w.nextMatch)
{
var nextRowType = lookaheadMatch[2];
if(nextRowType == "k")
{
table.className = lookaheadMatch[1];
w.nextMatch += lookaheadMatch[0].length+1;
}
else
{
if(nextRowType != currRowType)
{
rowContainer = createTiddlyElement(table,this.rowTypes[nextRowType]);
currRowType = nextRowType;
}
if(currRowType == "c")
{
// Caption
w.nextMatch++;
if(rowContainer != table.firstChild)
table.insertBefore(rowContainer,table.firstChild);
rowContainer.setAttribute("align",rowCount === 0?"top":"bottom");
w.subWikifyTerm(rowContainer,this.rowTermRegExp);
}
else
{
this.rowHandler(w,createTiddlyElement(rowContainer,"tr",null,(rowCount&1)?"oddRow":"evenRow"),prevColumns);
if(currRowType == "h") want_sortable = 1;
rowCount++;
}
}
this.lookaheadRegExp.lastIndex = w.nextMatch;
lookaheadMatch = this.lookaheadRegExp.exec(w.source);
}
if (want_sortable) {
table.setAttribute("class","sortable");
config.macros.sortableGridPlugin.ts_makeSortable(table);
}
};
}
else
alert("SortableGridPlugin works only with TiddlyWiki 2.0.11, 2.1.x or newer");
//}}}
''Code page tables supported by Windows'':
*More reliable - http://msdn.microsoft.com/en-us/goglobal/bb964653.aspx
*More convenient - http://www.fileformat.info/info/charset/codepage.htm
''Web-tools''
*[[UTF-8 Tool|http://www.ltg.ed.ac.uk/~richard/utf-8.cgi]]
''Links''
http://www.intuit.ru/department/se/proghum/6/1.html
http://rsdn.ru/Forum/Info/FAQ.winapi.ManySidedUnicode.aspx -- многоликий Unicode
http://ru.wikipedia.org/wiki/UTF-8
http://en.wikipedia.org/wiki/UTF-8
[[ShCore.css]]
[[ShThemeDefault.css]]
we used to do something like this but we send over data. using
javascript...
* onClick of a button (Not a submit button).
1. create a new window/popup
2. send the new window the input data from the <from> on your page.
* onLoad of your new window.
1. submit the <form> that was sent over by the other page.
2. close the window.
/***
|''Name''|SyntaxHighlighterPlugin3|
|''Description''|Enables syntax highlighting|
|''Author''|PMario|
|''Version''|0.2.0|
|''Status''|''beta''|
|''Source''|http://syntaxhighlighter.tiddlyspace.com/#SyntaxHighlighterPlugin3|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''CoreVersion''|2.5.0|
|''Requires''|ShCore.js|
|''Keywords''|syntax highlighting color code|
!Documentation
*see: [[SyntaxHighlighterPlugin3Info]]
!Description
Enables syntax highlighting for <pre> and <code> blocks. Adds a new formatter for {{{<code class='brush:???'>}}}
!Usage
!!!!StyleSheet
<<<
*add this to your StyleSheet
{{{
[[ShCore.css]]
[[ShThemeDefault.css]]
}}}
<<<
!!!!Macro
<<<
*The macro is only needed if you have inline html blocks. see: [[SyntaxHighlighterPlugin3Info]]
<<<
!!!!ViewTemplate
<<<
*Same as macro, but will be executed automatically for every tiddler. see: [[SyntaxHighlighterPlugin3Info]]
<<<
!!!!Parameters
<<<
{{{<<highlightSyntax [tagName]>> }}}
*will render all blocks, with any defined tag name. eg: tagName = code.
*[tagName] is optional. Default is "pre".
<<<
!!!!Configuration options
<<<
Guess syntax: <<option chkGuessSyntax>> .. If activated, ~TiddlyWiky <pre> blocks will be rendered according to there block braces. see [[SyntaxHighlighterPlugin3Info]]
Expert mode: <<option chkExpertSyntax>> .. If activated, additional values below will be used. see [[SyntaxHighlighterPlugin3Info]]
{{{ {{{ }}} txtShText: <<option txtShText>> eg: 'brush:text tab-size:4 + options'
{{{ /*{{{* / }}} txtShCss: <<option txtShCss>> eg: 'brush:css + options'
{{{ //{{{ }}} txtShPlugin: <<option txtShPlugin>> 'brush:js + options'
{{{ <!--{{{-->> }}} txtShXml: <<option txtShXml>> 'brush:xml + options'
Additional options can be found at: [[SyntaxHighlighter homepage|http://alexgorbatchev.com/SyntaxHighlighter/manual/configuration/]]
<<<
!!!!Revision History
<<<
*V 0.2.0 2010-08-22
**New formatter for {{{<code class='brush:???'>}}} is available now
**expert mode uses config options now
<<<
!!!!ToDo
<<<
*
<<<
!!!Code
***/
//{{{
version.extensions.SyntaxHighlighterPlugin3 = {major: 0, minor: 2, revision: 0, date: new Date(2010,8,22)};
(function($) {
if(!window.SyntaxHighlighter) {
throw "Missing dependency: SyntaxHighlighter";
}
config.macros.highlightSyntax = {
getElementsByClass: function (searchClass,node,tag) {
var classElements = [];
if ( node == null ) node = document;
if ( tag == null ) tag = '*';
var els = node.getElementsByTagName(tag);
var elsLen = els.length;
var pattern = new RegExp("(^|\\s)"+searchClass+"(:|\\s|$)");
for (i = 0, j = 0; i < elsLen; i++) {
if ( pattern.test(els[i].className) ) {
classElements[j] = els[i];
j++;
}
}
return classElements;
},
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
// the configured tagName can be temporarily overwritten by the macro.
var tagName = params[0] || SyntaxHighlighter.config.tagName;
var arr = this.getElementsByClass('brush', story.findContainingTiddler(place), tagName);
for (i=0; i<arr.length; i++) {
SyntaxHighlighter.highlight(null, arr[i]);
}
} // handler
};
})(jQuery);
//}}}
/***
!!!!!New formatter for {{{<code class='brush:??'>}}}
***/
//{{{
config.formatters.push({
name: "highlightSyntax",
match: "^<code[\\s]+[^>]+>\\n",
element: "pre",
handler: function(w)
{
this.lookaheadRegExp = /<code[\s]+class.*=.*["'](.*)["'].*>\n((?:^[^\n]*\n)+?)(^<\/code>$\n?)/img;
this.lookaheadRegExp.lastIndex = w.matchStart;
var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
var options = lookaheadMatch[1];
var text = lookaheadMatch[2];
if(config.browser.isIE)
text = text.replace(/\n/g,"\r");
var element = createTiddlyElement(w.output,this.element,null,options,text);
SyntaxHighlighter.highlight(null, element);
w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
}
}
});
//}}}
/***
!!!!!Add class attribute to pre, if defined
***/
//{{{
(function(formatters) { //# set up alias
var helper = {};
helper.enclosedTextHelper = function(w){
var attr;
var co = config.options;
var expert = (co.chkExpertSyntax != undefined)? co.chkExpertSyntax : false;
var guess = (co.chkGuessSyntax != undefined)? co.chkGuessSyntax : true;
this.lookaheadRegExp.lastIndex = w.matchStart;
var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
var text = lookaheadMatch[1];
if(config.browser.isIE)
text = text.replace(/\n/g,"\r");
switch(w.matchText) {
case "{{{\n": // text
attr = (expert) ? (co.txtShText) ? (co.txtShText) : 'brush:text' : 'brush:text' ;
break;
case "/*{{{*/\n": // CSS
attr = (expert) ? (co.txtShCss) ? (co.txtShCss) : 'brush:css' : 'brush:css';
break;
case "//{{{\n": // plugin
attr = (expert) ? (co.txtShPlugin) ? (co.txtShPlugin) : 'brush:js' : 'brush:js';
break;
case "<!--{{{-->\n": //template
attr = (expert) ? (co.txtShXml) ? (co.txtShXml) : 'brush:xml' : 'brush:xml';
break;
}
var element = createTiddlyElement(w.output,this.element,null,attr,text);
if (guess || expert) SyntaxHighlighter.highlight(null, element);
w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
}
};
// merge the new helper function into formatterHelpers.
merge(config.formatterHelpers, helper);
})(config.formatters); //# end of alias
//}}}
|''Name''|SyntaxHighlighterPlugin3Info|
|''Description''|Documentation for [[SyntaxHighlighterPlugin3]]|
|''Author''|PMario|
|''Version''|0.2.0|
|''Source''|http://syntaxhighlighter.tiddlyspace.com/#SyntaxHighlighterPlugin3|
|''Documentation''|http://syntaxhighlighter.tiddlyspace.com/#SyntaxHighlighterPlugin3Info|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]], libraries used: see the according files: [[ShCore.js]] |
|''Keywords''|syntax highlighting color code|
!Usage
!!!!StyleSheet
<<<
*add this to your StyleSheet
{{{
[[ShCore.css]]
[[ShThemeDefault.css]]
}}}
<<<
!!!!Macro
<<<
*The macro is only needed if you have inline html blocks, like shown below.
<!--{{{-->
<html>
<pre class='brush:pascal tab-size:3'>
// your code
<pre>
</html>
<<highlightSyntax>> .. will render the <pre> blocks shown above.
<!--}}}-->
<<<
!!!!ViewTemplate
<<<
*Same as macro, but will be executed automatically for every tiddler.
<!--{{{-->
<div class='tagging' macro='tagging'></div>
<div macro='highlightSyntax'></div> <!-- insert this line -->
<div class='tagClear'></div>
<!--}}}-->
<<<
!!!!Parameters
<<<
{{{<<highlightSyntax [tagName]>>}}}
*will render all blocks, with any defined tag name. eg: tagName = code.
*[tagName] is optional. Default is "pre".
<<<
!!Examples
!!!!Code sample
<<<
<!--{{{-->
<code class="brush:js highlight:[1,3]">
// comment
var a = b = 0;
a = 17;
</code>
<!--}}}-->
will render like
<code class="brush:js highlight:[1,3]">
// comment
var a = b = 0;
a = 17;
</code>
<<<
!!!!Text
<<<
{{{
{{{
this will be rendered as text!
}}}
}}}
<<<
!!!!CSS
<<<
{{{
/*{{{*/
.cssClass {
display: block; !important;
}
/*}}}*/
}}}
will render like:
/*{{{*/
.cssClass {
display: block; !important;
}
/*}}}*/
<<<
!!!!XML
<<<
{{{
<!--{{{-->
<html>
<div id='myId' class='dp50'>some text </div>
</html>
<!--}}}-->
}}}
will render like:
<!--{{{-->
<html>
<div id='myId' class='dp50'>some text </div>
</html>
<!--}}}-->
<<<
!!!!Plugin
<<<
{{{
//{{{
(function($) {
config.macros.highlightSyntax = {
var a = b = 0;
// your code here!
}
})(jQuery);
//}}}
}}}
will render like:
//{{{
(function($) {
config.macros.highlightSyntax = {
var a = b = 0;
// your code here!
}
})(jQuery);
//}}}
<<<
!!Configuration Options
<<<
Guess syntax: <<option chkGuessSyntax>> .. If activated, ~TiddlyWiky <pre> blocks will be rendered according to there block braces, like described obove.
Expert mode: <<option chkExpertSyntax>> .. If activated, additional values below will be used
{{{ {{{ }}} txtShText: <<option txtShText>> eg: 'brush:text tab-size:4 + options'
{{{ /*{{{*/ }}} txtShCss: <<option txtShCss>> eg: 'brush:css + options'
{{{ //{{{ }}} txtShPlugin: <<option txtShPlugin>> 'brush:js + options'
{{{ <!--{{{-->> }}} txtShXml: <<option txtShXml>> 'brush:xml + options'
If you want to change the default values, add the following to a [[zzConfig]] tiddler and tag it "systemConfig"
//{{{
config.options.chkGuessSyntax = true;
config.options.chkExpertSyntax = false;
config.options.txtShPlugin = 'brush:js tab-size:4';
//}}}
All possible options can be found at: [[SyntaxHighlighter homepage|http://alexgorbatchev.com/SyntaxHighlighter/manual/configuration/]]
<<<
!!!Revision History
*V 0.2.0 2010-08-22
**New formatter for {{{<code class='brush:???'>}}} is available now
**expert mode uses config options now
*V 0.1.0 2010-08-17
**initial release
!!!Needed: list tagged syntax
<<list filter [tag[syntax]]>>
<<tabs txtMoreTab "Tags" "All Tags" TabAllTags "Miss" "Missing tiddlers" TabMoreMissing "Orph" "Orphaned tiddlers" TabMoreOrphans "Shad" "Shadowed tiddlers" TabMoreShadowed>>
<<allTags excludeLists [a-z]>>
SHOW TABLE STATUS FROM $db LIKE '$table' [WHERE expr]
<code class="brush:">
describe <table>;
</code>
/***
|Name|TaggedTemplateTweak|
|Source|http://www.TiddlyTools.com/#TaggedTemplateTweak|
|Documentation|http://www.TiddlyTools.com/#TaggedTemplateTweakInfo|
|Version|1.6.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|use alternative ViewTemplate/EditTemplate for specific tiddlers|
This plugin extends the core function, story.chooseTemplateForTiddler(), so that any given tiddler can be viewed and/or edited using alternatives to the standard tiddler templates.
!!!!!Documentation
>see [[TaggedTemplateTweakInfo]]
!!!!!Revisions
<<<
2009.09.02 [1.6.1] apply field-based template (if any) *before* tag-based template
| please see [[TaggedTemplateTweakInfo]] for previous revision details |
2007.06.11 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.TaggedTemplateTweak= {major: 1, minor: 6, revision: 1, date: new Date(2009,9,2)};
if (!config.options.txtTemplateTweakFieldname)
config.options.txtTemplateTweakFieldname='template';
Story.prototype.taggedTemplate_chooseTemplateForTiddler = Story.prototype.chooseTemplateForTiddler
Story.prototype.chooseTemplateForTiddler = function(title,template)
{
// get core template and split into theme and template name
var coreTemplate=this.taggedTemplate_chooseTemplateForTiddler.apply(this,arguments);
var theme=""; var template=coreTemplate;
var parts=template.split(config.textPrimitives.sectionSeparator);
if (parts[1]) { theme=parts[0]; template=parts[1]; }
else theme=config.options.txtTheme||""; // if theme is not specified
theme+=config.textPrimitives.sectionSeparator;
// look for template using title as prefix
if (!store.getTaggedTiddlers(title).length) { // if tiddler is not a tag
if (store.getTiddlerText(theme+title+template))
{ return theme+title+template; } // theme##TitleTemplate
if (store.getTiddlerText(title+template))
{ return title+template; } // TitleTemplate
}
// look for templates using custom field value as prefix
var v=store.getValue(title,config.options.txtTemplateTweakFieldname);
if (store.getTiddlerText(theme+v+template))
{ return theme+v+template; } // theme##valueTemplate
if (store.getTiddlerText(v+template))
{ return v+template; } // valueTemplate
// look for template using tags as prefix
var tiddler=store.getTiddler(title);
if (!tiddler) return coreTemplate; // tiddler doesn't exist... use core result
for (i=0; i<tiddler.tags.length; i++) {
var t=tiddler.tags[i]+template; // add tag prefix to template
var c=t.substr(0,1).toUpperCase()+t.substr(1); // capitalized for WikiWord title
if (store.getTiddlerText(theme+t)) { return theme+t; } // theme##tagTemplate
if (store.getTiddlerText(theme+c)) { return theme+c; } // theme##TagTemplate
if (store.getTiddlerText(t)) { return t; } // tagTemplate
if (store.getTiddlerText(c)) { return c; } // TagTemplate
}
// no match... use core result
return coreTemplate;
}
//}}}
/***
|Name:|TagglyTaggingPlugin|
|Description:|tagglyTagging macro is a replacement for the builtin tagging macro in your ViewTemplate|
|Version:|3.3.1 ($Rev: 9828 $)|
|Date:|$Date: 2009-06-03 21:38:41 +1000 (Wed, 03 Jun 2009) $|
|Source:|http://mptw.tiddlyspot.com/#TagglyTaggingPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
!Notes
See http://mptw.tiddlyspot.com/#TagglyTagging
***/
//{{{
merge(String.prototype,{
parseTagExpr: function(debug) {
if (this.trim() == "")
return "(true)";
var anyLogicOp = /(!|&&|\|\||\(|\))/g;
var singleLogicOp = /^(!|&&|\|\||\(|\))$/;
var spaced = this.
// because square brackets in templates are no good
// this means you can use [(With Spaces)] instead of [[With Spaces]]
replace(/\[\(/g," [[").
replace(/\)\]/g,"]] ").
// space things out so we can use readBracketedList. tricky eh?
replace(anyLogicOp," $1 ");
var expr = "";
var tokens = spaced.readBracketedList(false); // false means don't uniq the list. nice one JR!
for (var i=0;i<tokens.length;i++)
if (tokens[i].match(singleLogicOp))
expr += tokens[i];
else
expr += "tiddler.tags.contains('%0')".format([tokens[i].replace(/'/,"\\'")]); // fix single quote bug. still have round bracket bug i think
if (debug)
alert(expr);
return '('+expr+')';
}
});
merge(TiddlyWiki.prototype,{
getTiddlersByTagExpr: function(tagExpr,sortField) {
var result = [];
var expr = tagExpr.parseTagExpr();
store.forEachTiddler(function(title,tiddler) {
if (eval(expr))
result.push(tiddler);
});
if(!sortField)
sortField = "title";
result.sort(function(a,b) {return a[sortField] < b[sortField] ? -1 : (a[sortField] == b[sortField] ? 0 : +1);});
return result;
}
});
config.taggly = {
// for translations
lingo: {
labels: {
asc: "\u2191", // down arrow
desc: "\u2193", // up arrow
title: "title",
modified: "modified",
created: "created",
show: "+",
hide: "-",
normal: "normal",
group: "group",
commas: "commas",
sitemap: "sitemap",
numCols: "cols\u00b1", // plus minus sign
label: "Tagged as '%0':",
exprLabel: "Matching tag expression '%0':",
excerpts: "excerpts",
descr: "descr",
slices: "slices",
contents: "contents",
sliders: "sliders",
noexcerpts: "title only",
noneFound: "(none)"
},
tooltips: {
title: "Click to sort by title",
modified: "Click to sort by modified date",
created: "Click to sort by created date",
show: "Click to show tagging list",
hide: "Click to hide tagging list",
normal: "Click to show a normal ungrouped list",
group: "Click to show list grouped by tag",
sitemap: "Click to show a sitemap style list",
commas: "Click to show a comma separated list",
numCols: "Click to change number of columns",
excerpts: "Click to show excerpts",
descr: "Click to show the description slice",
slices: "Click to show all slices",
contents: "Click to show entire tiddler contents",
sliders: "Click to show tiddler contents in sliders",
noexcerpts: "Click to show entire title only"
},
tooDeepMessage: "* //sitemap too deep...//"
},
config: {
showTaggingCounts: true,
listOpts: {
// the first one will be the default
sortBy: ["title","modified","created"],
sortOrder: ["asc","desc"],
hideState: ["show","hide"],
listMode: ["normal","group","sitemap","commas"],
numCols: ["1","2","3","4","5","6"],
excerpts: ["noexcerpts","excerpts","descr","slices","contents","sliders"]
},
valuePrefix: "taggly.",
excludeTags: ["excludeLists","excludeTagging"],
excerptSize: 50,
excerptMarker: "/%"+"%/",
siteMapDepthLimit: 25
},
getTagglyOpt: function(title,opt) {
var val = store.getValue(title,this.config.valuePrefix+opt);
return val ? val : this.config.listOpts[opt][0];
},
setTagglyOpt: function(title,opt,value) {
// create it silently if it doesn't exist
if (!store.tiddlerExists(title)) {
store.saveTiddler(title,title,config.views.editor.defaultText.format([title]),config.options.txtUserName,new Date(),"");
// <<tagglyTagging expr:"...">> creates a tiddler to store its display settings
// Make those tiddlers less noticeable by tagging as excludeSearch and excludeLists
// Because we don't want to hide real tags, check that they aren't actually tags before doing so
// Also tag them as tagglyExpression for manageability
// (contributed by RA)
if (!store.getTaggedTiddlers(title).length) {
store.setTiddlerTag(title,true,"excludeSearch");
store.setTiddlerTag(title,true,"excludeLists");
store.setTiddlerTag(title,true,"tagglyExpression");
}
}
// if value is default then remove it to save space
return store.setValue(title, this.config.valuePrefix+opt, value == this.config.listOpts[opt][0] ? null : value);
},
getNextValue: function(title,opt) {
var current = this.getTagglyOpt(title,opt);
var pos = this.config.listOpts[opt].indexOf(current);
// supposed to automagically don't let cols cycle up past the number of items
// currently broken in some situations, eg when using an expression
// lets fix it later when we rewrite for jquery
// the columns thing should be jquery table manipulation probably
var limit = (opt == "numCols" ? store.getTaggedTiddlers(title).length : this.config.listOpts[opt].length);
var newPos = (pos + 1) % limit;
return this.config.listOpts[opt][newPos];
},
toggleTagglyOpt: function(title,opt) {
var newVal = this.getNextValue(title,opt);
this.setTagglyOpt(title,opt,newVal);
},
createListControl: function(place,title,type) {
var lingo = config.taggly.lingo;
var label;
var tooltip;
var onclick;
if ((type == "title" || type == "modified" || type == "created")) {
// "special" controls. a little tricky. derived from sortOrder and sortBy
label = lingo.labels[type];
tooltip = lingo.tooltips[type];
if (this.getTagglyOpt(title,"sortBy") == type) {
label += lingo.labels[this.getTagglyOpt(title,"sortOrder")];
onclick = function() {
config.taggly.toggleTagglyOpt(title,"sortOrder");
return false;
}
}
else {
onclick = function() {
config.taggly.setTagglyOpt(title,"sortBy",type);
config.taggly.setTagglyOpt(title,"sortOrder",config.taggly.config.listOpts.sortOrder[0]);
return false;
}
}
}
else {
// "regular" controls, nice and simple
label = lingo.labels[type == "numCols" ? type : this.getNextValue(title,type)];
tooltip = lingo.tooltips[type == "numCols" ? type : this.getNextValue(title,type)];
onclick = function() {
config.taggly.toggleTagglyOpt(title,type);
return false;
}
}
// hide button because commas don't have columns
if (!(this.getTagglyOpt(title,"listMode") == "commas" && type == "numCols"))
createTiddlyButton(place,label,tooltip,onclick,type == "hideState" ? "hidebutton" : "button");
},
makeColumns: function(orig,numCols) {
var listSize = orig.length;
var colSize = listSize/numCols;
var remainder = listSize % numCols;
var upperColsize = colSize;
var lowerColsize = colSize;
if (colSize != Math.floor(colSize)) {
// it's not an exact fit so..
upperColsize = Math.floor(colSize) + 1;
lowerColsize = Math.floor(colSize);
}
var output = [];
var c = 0;
for (var j=0;j<numCols;j++) {
var singleCol = [];
var thisSize = j < remainder ? upperColsize : lowerColsize;
for (var i=0;i<thisSize;i++)
singleCol.push(orig[c++]);
output.push(singleCol);
}
return output;
},
drawTable: function(place,columns,theClass) {
var newTable = createTiddlyElement(place,"table",null,theClass);
var newTbody = createTiddlyElement(newTable,"tbody");
var newTr = createTiddlyElement(newTbody,"tr");
for (var j=0;j<columns.length;j++) {
var colOutput = "";
for (var i=0;i<columns[j].length;i++)
colOutput += columns[j][i];
var newTd = createTiddlyElement(newTr,"td",null,"tagglyTagging"); // todo should not need this class
wikify(colOutput,newTd);
}
return newTable;
},
createTagglyList: function(place,title,isTagExpr) {
switch(this.getTagglyOpt(title,"listMode")) {
case "group": return this.createTagglyListGrouped(place,title,isTagExpr); break;
case "normal": return this.createTagglyListNormal(place,title,false,isTagExpr); break;
case "commas": return this.createTagglyListNormal(place,title,true,isTagExpr); break;
case "sitemap":return this.createTagglyListSiteMap(place,title,isTagExpr); break;
}
},
getTaggingCount: function(title,isTagExpr) {
// thanks to Doug Edmunds
if (this.config.showTaggingCounts) {
var tagCount = config.taggly.getTiddlers(title,'title',isTagExpr).length;
if (tagCount > 0)
return " ("+tagCount+")";
}
return "";
},
getTiddlers: function(titleOrExpr,sortBy,isTagExpr) {
return isTagExpr ? store.getTiddlersByTagExpr(titleOrExpr,sortBy) : store.getTaggedTiddlers(titleOrExpr,sortBy);
},
getExcerpt: function(inTiddlerTitle,title,indent) {
if (!indent)
indent = 1;
var displayMode = this.getTagglyOpt(inTiddlerTitle,"excerpts");
var t = store.getTiddler(title);
if (t && displayMode == "excerpts") {
var text = t.text.replace(/\n/," ");
var marker = text.indexOf(this.config.excerptMarker);
if (marker != -1) {
return " {{excerpt{<nowiki>" + text.substr(0,marker) + "</nowiki>}}}";
}
else if (text.length < this.config.excerptSize) {
return " {{excerpt{<nowiki>" + t.text + "</nowiki>}}}";
}
else {
return " {{excerpt{<nowiki>" + t.text.substr(0,this.config.excerptSize) + "..." + "</nowiki>}}}";
}
}
else if (t && displayMode == "contents") {
return "\n{{contents indent"+indent+"{\n" + t.text + "\n}}}";
}
else if (t && displayMode == "sliders") {
return "<slider slide>\n{{contents{\n" + t.text + "\n}}}\n</slider>";
}
else if (t && displayMode == "descr") {
var descr = store.getTiddlerSlice(title,'Description');
return descr ? " {{excerpt{" + descr + "}}}" : "";
}
else if (t && displayMode == "slices") {
var result = "";
var slices = store.calcAllSlices(title);
for (var s in slices)
result += "|%0|<nowiki>%1</nowiki>|\n".format([s,slices[s]]);
return result ? "\n{{excerpt excerptIndent{\n" + result + "}}}" : "";
}
return "";
},
notHidden: function(t,inTiddler) {
if (typeof t == "string")
t = store.getTiddler(t);
return (!t || !t.tags.containsAny(this.config.excludeTags) ||
(inTiddler && this.config.excludeTags.contains(inTiddler)));
},
// this is for normal and commas mode
createTagglyListNormal: function(place,title,useCommas,isTagExpr) {
var list = config.taggly.getTiddlers(title,this.getTagglyOpt(title,"sortBy"),isTagExpr);
if (this.getTagglyOpt(title,"sortOrder") == "desc")
list = list.reverse();
var output = [];
var first = true;
for (var i=0;i<list.length;i++) {
if (this.notHidden(list[i],title)) {
var countString = this.getTaggingCount(list[i].title);
var excerpt = this.getExcerpt(title,list[i].title);
if (useCommas)
output.push((first ? "" : ", ") + "[[" + list[i].title + "]]" + countString + excerpt);
else
output.push("*[[" + list[i].title + "]]" + countString + excerpt + "\n");
first = false;
}
}
return this.drawTable(place,
this.makeColumns(output,useCommas ? 1 : parseInt(this.getTagglyOpt(title,"numCols"))),
useCommas ? "commas" : "normal");
},
// this is for the "grouped" mode
createTagglyListGrouped: function(place,title,isTagExpr) {
var sortBy = this.getTagglyOpt(title,"sortBy");
var sortOrder = this.getTagglyOpt(title,"sortOrder");
var list = config.taggly.getTiddlers(title,sortBy,isTagExpr);
if (sortOrder == "desc")
list = list.reverse();
var leftOvers = []
for (var i=0;i<list.length;i++)
leftOvers.push(list[i].title);
var allTagsHolder = {};
for (var i=0;i<list.length;i++) {
for (var j=0;j<list[i].tags.length;j++) {
if (list[i].tags[j] != title) { // not this tiddler
if (this.notHidden(list[i].tags[j],title)) {
if (!allTagsHolder[list[i].tags[j]])
allTagsHolder[list[i].tags[j]] = "";
if (this.notHidden(list[i],title)) {
allTagsHolder[list[i].tags[j]] += "**[["+list[i].title+"]]"
+ this.getTaggingCount(list[i].title) + this.getExcerpt(title,list[i].title) + "\n";
leftOvers.setItem(list[i].title,-1); // remove from leftovers. at the end it will contain the leftovers
}
}
}
}
}
var allTags = [];
for (var t in allTagsHolder)
allTags.push(t);
var sortHelper = function(a,b) {
if (a == b) return 0;
if (a < b) return -1;
return 1;
};
allTags.sort(function(a,b) {
var tidA = store.getTiddler(a);
var tidB = store.getTiddler(b);
if (sortBy == "title") return sortHelper(a,b);
else if (!tidA && !tidB) return 0;
else if (!tidA) return -1;
else if (!tidB) return +1;
else return sortHelper(tidA[sortBy],tidB[sortBy]);
});
var leftOverOutput = "";
for (var i=0;i<leftOvers.length;i++)
if (this.notHidden(leftOvers[i],title))
leftOverOutput += "*[["+leftOvers[i]+"]]" + this.getTaggingCount(leftOvers[i]) + this.getExcerpt(title,leftOvers[i]) + "\n";
var output = [];
if (sortOrder == "desc")
allTags.reverse();
else if (leftOverOutput != "")
// leftovers first...
output.push(leftOverOutput);
for (var i=0;i<allTags.length;i++)
if (allTagsHolder[allTags[i]] != "")
output.push("*[["+allTags[i]+"]]" + this.getTaggingCount(allTags[i]) + this.getExcerpt(title,allTags[i]) + "\n" + allTagsHolder[allTags[i]]);
if (sortOrder == "desc" && leftOverOutput != "")
// leftovers last...
output.push(leftOverOutput);
return this.drawTable(place,
this.makeColumns(output,parseInt(this.getTagglyOpt(title,"numCols"))),
"grouped");
},
// used to build site map
treeTraverse: function(title,depth,sortBy,sortOrder,isTagExpr) {
var list = config.taggly.getTiddlers(title,sortBy,isTagExpr);
if (sortOrder == "desc")
list.reverse();
var indent = "";
for (var j=0;j<depth;j++)
indent += "*"
var childOutput = "";
if (depth > this.config.siteMapDepthLimit)
childOutput += indent + this.lingo.tooDeepMessage + "\n";
else
for (var i=0;i<list.length;i++)
if (list[i].title != title)
if (this.notHidden(list[i].title,this.config.inTiddler))
childOutput += this.treeTraverse(list[i].title,depth+1,sortBy,sortOrder,false);
if (depth == 0)
return childOutput;
else
return indent + "[["+title+"]]" + this.getTaggingCount(title) + this.getExcerpt(this.config.inTiddler,title,depth) + "\n" + childOutput;
},
// this if for the site map mode
createTagglyListSiteMap: function(place,title,isTagExpr) {
this.config.inTiddler = title; // nasty. should pass it in to traverse probably
var output = this.treeTraverse(title,0,this.getTagglyOpt(title,"sortBy"),this.getTagglyOpt(title,"sortOrder"),isTagExpr);
return this.drawTable(place,
this.makeColumns(output.split(/(?=^\*\[)/m),parseInt(this.getTagglyOpt(title,"numCols"))), // regexp magic
"sitemap"
);
},
macros: {
tagglyTagging: {
handler: function (place,macroName,params,wikifier,paramString,tiddler) {
var parsedParams = paramString.parseParams("tag",null,true);
var refreshContainer = createTiddlyElement(place,"div");
// do some refresh magic to make it keep the list fresh - thanks Saq
refreshContainer.setAttribute("refresh","macro");
refreshContainer.setAttribute("macroName",macroName);
var tag = getParam(parsedParams,"tag");
var expr = getParam(parsedParams,"expr");
if (expr) {
refreshContainer.setAttribute("isTagExpr","true");
refreshContainer.setAttribute("title",expr);
refreshContainer.setAttribute("showEmpty","true");
}
else {
refreshContainer.setAttribute("isTagExpr","false");
if (tag) {
refreshContainer.setAttribute("title",tag);
refreshContainer.setAttribute("showEmpty","true");
}
else {
refreshContainer.setAttribute("title",tiddler.title);
refreshContainer.setAttribute("showEmpty","false");
}
}
this.refresh(refreshContainer);
},
refresh: function(place) {
var title = place.getAttribute("title");
var isTagExpr = place.getAttribute("isTagExpr") == "true";
var showEmpty = place.getAttribute("showEmpty") == "true";
removeChildren(place);
addClass(place,"tagglyTagging");
var countFound = config.taggly.getTiddlers(title,'title',isTagExpr).length
if (countFound > 0 || showEmpty) {
var lingo = config.taggly.lingo;
config.taggly.createListControl(place,title,"hideState");
if (config.taggly.getTagglyOpt(title,"hideState") == "show") {
createTiddlyElement(place,"span",null,"tagglyLabel",
isTagExpr ? lingo.labels.exprLabel.format([title]) : lingo.labels.label.format([title]));
config.taggly.createListControl(place,title,"title");
config.taggly.createListControl(place,title,"modified");
config.taggly.createListControl(place,title,"created");
config.taggly.createListControl(place,title,"listMode");
config.taggly.createListControl(place,title,"excerpts");
config.taggly.createListControl(place,title,"numCols");
config.taggly.createTagglyList(place,title,isTagExpr);
if (countFound == 0 && showEmpty)
createTiddlyElement(place,"div",null,"tagglyNoneFound",lingo.labels.noneFound);
}
}
}
}
},
// todo fix these up a bit
styles: [
"/*{{{*/",
"/* created by TagglyTaggingPlugin */",
".tagglyTagging { padding-top:0.5em; }",
".tagglyTagging li.listTitle { display:none; }",
".tagglyTagging ul {",
" margin-top:0px; padding-top:0.5em; padding-left:2em;",
" margin-bottom:0px; padding-bottom:0px;",
"}",
".tagglyTagging { vertical-align: top; margin:0px; padding:0px; }",
".tagglyTagging table { margin:0px; padding:0px; }",
".tagglyTagging .button { visibility:hidden; margin-left:3px; margin-right:3px; }",
".tagglyTagging .button, .tagglyTagging .hidebutton {",
" color:[[ColorPalette::TertiaryLight]]; font-size:90%;",
" border:0px; padding-left:0.3em;padding-right:0.3em;",
"}",
".tagglyTagging .button:hover, .hidebutton:hover, ",
".tagglyTagging .button:active, .hidebutton:active {",
" border:0px; background:[[ColorPalette::TertiaryPale]]; color:[[ColorPalette::TertiaryDark]];",
"}",
".selected .tagglyTagging .button { visibility:visible; }",
".tagglyTagging .hidebutton { color:[[ColorPalette::Background]]; }",
".selected .tagglyTagging .hidebutton { color:[[ColorPalette::TertiaryLight]] }",
".tagglyLabel { color:[[ColorPalette::TertiaryMid]]; font-size:90%; }",
".tagglyTagging ul {padding-top:0px; padding-bottom:0.5em; margin-left:1em; }",
".tagglyTagging ul ul {list-style-type:disc; margin-left:-1em;}",
".tagglyTagging ul ul li {margin-left:0.5em; }",
".editLabel { font-size:90%; padding-top:0.5em; }",
".tagglyTagging .commas { padding-left:1.8em; }",
"/* not technically tagglytagging but will put them here anyway */",
".tagglyTagged li.listTitle { display:none; }",
".tagglyTagged li { display: inline; font-size:90%; }",
".tagglyTagged ul { margin:0px; padding:0px; }",
".excerpt { color:[[ColorPalette::TertiaryDark]]; }",
".excerptIndent { margin-left:4em; }",
"div.tagglyTagging table,",
"div.tagglyTagging table tr,",
"td.tagglyTagging",
" {border-style:none!important; }",
".tagglyTagging .contents { border-bottom:2px solid [[ColorPalette::TertiaryPale]]; padding:0 1em 1em 0.5em;",
" margin-bottom:0.5em; }",
".tagglyTagging .indent1 { margin-left:3em; }",
".tagglyTagging .indent2 { margin-left:4em; }",
".tagglyTagging .indent3 { margin-left:5em; }",
".tagglyTagging .indent4 { margin-left:6em; }",
".tagglyTagging .indent5 { margin-left:7em; }",
".tagglyTagging .indent6 { margin-left:8em; }",
".tagglyTagging .indent7 { margin-left:9em; }",
".tagglyTagging .indent8 { margin-left:10em; }",
".tagglyTagging .indent9 { margin-left:11em; }",
".tagglyTagging .indent10 { margin-left:12em; }",
".tagglyNoneFound { margin-left:2em; color:[[ColorPalette::TertiaryMid]]; font-size:90%; font-style:italic; }",
"/*}}}*/",
""].join("\n"),
init: function() {
merge(config.macros,this.macros);
config.shadowTiddlers["TagglyTaggingStyles"] = this.styles;
store.addNotification("TagglyTaggingStyles",refreshStyles);
}
};
config.taggly.init();
//}}}
/***
InlineSlidersPlugin
By Saq Imtiaz
http://tw.lewcid.org/sandbox/#InlineSlidersPlugin
// syntax adjusted to not clash with NestedSlidersPlugin
// added + syntax to start open instead of closed
***/
//{{{
config.formatters.unshift( {
name: "inlinesliders",
// match: "\\+\\+\\+\\+|\\<slider",
match: "\\<slider",
// lookaheadRegExp: /(?:\+\+\+\+|<slider) (.*?)(?:>?)\n((?:.|\n)*?)\n(?:====|<\/slider>)/mg,
lookaheadRegExp: /(?:<slider)(\+?) (.*?)(?:>)\n((?:.|\n)*?)\n(?:<\/slider>)/mg,
handler: function(w) {
this.lookaheadRegExp.lastIndex = w.matchStart;
var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
if(lookaheadMatch && lookaheadMatch.index == w.matchStart ) {
var btn = createTiddlyButton(w.output,lookaheadMatch[2] + " "+"\u00BB",lookaheadMatch[2],this.onClickSlider,"button sliderButton");
var panel = createTiddlyElement(w.output,"div",null,"sliderPanel");
panel.style.display = (lookaheadMatch[1] == '+' ? "block" : "none");
wikify(lookaheadMatch[3],panel);
w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
}
},
onClickSlider : function(e) {
if(!e) var e = window.event;
var n = this.nextSibling;
n.style.display = (n.style.display=="none") ? "block" : "none";
return false;
}
});
//}}}
When editing programs, there is often a need to jump to another location, for example, to see how a function is defined. To help, Vim uses a tags file that lists each word you are likely to want, and their locations (file path and line number). Each wanted word is known as a "tag", for example, each function name or global variable may be a tag.
The tags file has to be created by a utility, and has to be updated after significant editing has occurred. [[Continue|http://vim.wikia.com/wiki/Browsing_programs_with_tags]]
''Installation''
* [[Install utility Exuberant Ctags|http://ctags.sourceforge.net/]]
* use mapping to re-build tags file after editing
<code class="brush:">
nmap <silent> <F4>
\ :!ctags -f ./tags
\ --langmap="php:+.inc"
\ -h ".php.inc" -R --totals=yes
\ --tag-relative=yes --PHP-kinds=+cf-v .<CR>
set tags=./tags,tags
</code>
* Open any file from project, find out it's current directory :pwd and press F4 => tags file will be in this directory!
http://writecodeonline.com/php/
Запускаем скрипт на auto@str1.drom.ru :
<code class="brush:">
/opt/php-5.3.10/bin/php -c /opt/php-5.3.10/etc/php.ini <admin_dir>/lindrid_sandbox/baza_farpost_get_xml_tires.php
</code>
<html><a href="http://tiddlywiki.com/#[[List%20Formatting]]"><b>Списки</b></a></html>
''Справка: Formatting, Macros, Shadow tiddlers''
http://tiddlywiki.com/#Reference
''Подсветка синтаксиса''
http://syntaxhighlighter.tiddlyspace.com/
http://www.fsk141.com/blog/tiddlywiki-syntax-highlighter/
http://groups.google.com/group/tiddlywiki/browse_thread/thread/3cb645cd34b92c56
''Форум''
http://softwareas.com/tiddlywiki-screencast-forum-in-15-minutes
* alfabank/common_functions: timeoutInSeconds,... вынести в GLOBAL_SITE_DATA
* vimrc :set ic ;ignore case in searches, there is no need to write /\c always
* svn conflict solution in vim
* const array through php read-only property http://stackoverflow.com/questions/402215/php-readonly-properties
* read http://www.joelonsoftware.com/articles/Unicode.html http://habrahabr.ru/sandbox/47663/
* bash alias ssd3 for sudo ssh auto@ssd3.drom.ru
* vim diff two files
* create good regexp tiddler
* tires_bulls.tpl , вынести логику, сделать php вставки <?= blabla ?>
* внести общую часть "Купить шины" из разных шаблонов в tires_bulls.tpl
* log for common_bulls_functions.php :: drom_sales_update_sticky_bull
* vim php "unexpected $end" -- чтобы в виме мог легко находить незакрытые скобки { [ (
/***
|Name:|ToggleTagPlugin|
|Description:|Makes a checkbox which toggles a tag in a tiddler|
|Version:|3.1.0 ($Rev: 4907 $)|
|Date:|$Date: 2008-05-13 03:15:46 +1000 (Tue, 13 May 2008) $|
|Source:|http://mptw.tiddlyspot.com/#ToggleTagPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
!!Usage
{{{<<toggleTag }}}//{{{TagName TiddlerName LabelText}}}//{{{>>}}}
* TagName - the tag to be toggled, default value "checked"
* TiddlerName - the tiddler to toggle the tag in, default value the current tiddler
* LabelText - the text (gets wikified) to put next to the check box, default value is '{{{[[TagName]]}}}' or '{{{[[TagName]] [[TiddlerName]]}}}'
(If a parameter is '.' then the default will be used)
* TouchMod flag - if non empty then touch the tiddlers mod date. Note, can set config.toggleTagAlwaysTouchModDate to always touch mod date
!!Examples
|Code|Description|Example|h
|{{{<<toggleTag>>}}}|Toggles the default tag (checked) in this tiddler|<<toggleTag>>|
|{{{<<toggleTag TagName>>}}}|Toggles the TagName tag in this tiddler|<<toggleTag TagName>>|
|{{{<<toggleTag TagName TiddlerName>>}}}|Toggles the TagName tag in the TiddlerName tiddler|<<toggleTag TagName TiddlerName>>|
|{{{<<toggleTag TagName TiddlerName 'click me'>>}}}|Same but with custom label|<<toggleTag TagName TiddlerName 'click me'>>|
|{{{<<toggleTag . . 'click me'>>}}}|dot means use default value|<<toggleTag . . 'click me'>>|
!!Notes
* If TiddlerName doesn't exist it will be silently created
* Set label to '-' to specify no label
* See also http://mgtd-alpha.tiddlyspot.com/#ToggleTag2
!!Known issues
* Doesn't smoothly handle the case where you toggle a tag in a tiddler that is current open for editing
* Should convert to use named params
***/
//{{{
if (config.toggleTagAlwaysTouchModDate == undefined) config.toggleTagAlwaysTouchModDate = false;
merge(config.macros,{
toggleTag: {
createIfRequired: true,
shortLabel: "[[%0]]",
longLabel: "[[%0]] [[%1]]",
handler: function(place,macroName,params,wikifier,paramString,tiddler) {
var tiddlerTitle = tiddler ? tiddler.title : '';
var tag = (params[0] && params[0] != '.') ? params[0] : "checked";
var title = (params[1] && params[1] != '.') ? params[1] : tiddlerTitle;
var defaultLabel = (title == tiddlerTitle ? this.shortLabel : this.longLabel);
var label = (params[2] && params[2] != '.') ? params[2] : defaultLabel;
var touchMod = (params[3] && params[3] != '.') ? params[3] : "";
label = (label == '-' ? '' : label); // dash means no label
var theTiddler = (title == tiddlerTitle ? tiddler : store.getTiddler(title));
var cb = createTiddlyCheckbox(place, label.format([tag,title]), theTiddler && theTiddler.isTagged(tag), function(e) {
if (!store.tiddlerExists(title)) {
if (config.macros.toggleTag.createIfRequired) {
var content = store.getTiddlerText(title); // just in case it's a shadow
store.saveTiddler(title,title,content?content:"",config.options.txtUserName,new Date(),null);
}
else
return false;
}
if ((touchMod != "" || config.toggleTagAlwaysTouchModDate) && theTiddler)
theTiddler.modified = new Date();
store.setTiddlerTag(title,this.checked,tag);
return true;
});
}
}
});
//}}}
diff
http://www.xul.fr/freeware.html Best free tools for webmasters and programmers
/***
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 = 'lindrid';
// 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?// @@ 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// @@ 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// @@ 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!// @@ 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 :)// @@ 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")
});
//}}}
http://sontek.net/turning-vim-into-a-modern-python-ide
http://www.memonic.com/user/aengus/folder/coding/id/1qxbh
The unix programming environment, Edition 2.2, August 2001.
http://www.iu.hio.no/~mark/unix/unix_toc.html
(C)ommand (L)ine (I)nterface и (G)raphical (U)ser (I)nterface.
Собираю инфу касательно различий этих двух типов интерфейсов из книги "The art of unix programming":
''плюсы и минусы cli, gui:''
"One is that command-line and command-language interfaces are more expressive than visual interfaces, especially for complex tasks. The other is that CLI interfaces are highly scriptable — they readily support the combining of programs, as we discussed in detail in Chapter 7. Usually (though not always) CLIs have an advantage in concision as well.
The disadvantage of the CLI style, of course, is that it almost always has high mnemonic load (low ease), and usually has low transparency.
On the other hand, the ‘user-friendly’ GUIs of other operating systems have their own problems. Finding the right buttons to push is like playing Adventure: the interfaces are just as burdensome as any Unix command line interface, save that one can in theory find the treasure by sufficient exploration. In Unix, one needs the manual."
''cli в сочетании с миниязыками (например, sql):''
"Database queries are a good example of the kind of interface for which pushing buttons is not just burdensome but extremely limiting. Neither keystroke commands to a full-screen character interface nor GUI gestures on a graphic display can express typical actions in the problem domain as expressively or concisely as typing SQL direct to a server.
SQL is a good example for illustrating another point. The most powerful CLIs are not ad-hoc collections of commands, but imperative minilanguages designed along the lines we described in Chapter 8. These minilanguages are the highest-power, highest-complexity end of the CLI spectrum; they maximize expressiveness, but minimize ease. "
''когда gui необходим:''
"Some applications, unlike database queries, are naturally visual. Paint programs, Web browsers, and presentation software make three excellent examples."
''gui для нечастых простых операций, cli для повторяющихся трудных:''
"In applications that are not naturally visual, however, visual interfaces are most appropriate for simple one-shot or infrequent tasks performed by novice users.
Resistance to CLI interfaces tends to decrease as users become more expert. In many problem domains, users (especially frequent users) reach a crossover point at which the concision and expressiveness of CLI becomes more valuable than avoiding its mnemonic load."
"CLIs also tend to gain utility as problems scale up and involve more in the way of canned, procedural and repetitive actions."
''пример 1''
"Case Study: Making Word Lists
A more interesting example is one in which pipelined programs cooperate to do some kind of data transformation for which, in less flexible environments, one would have to write custom code.
Consider the pipeline (combining of programs)
echo "it is (*^&*(#$*(^ a first gas#&*^station 2" | tr -c '[:alnum:]' '[\\n*]' | sort -iu | grep -v '^[0-9]*$'
The first command translates non-alphanumerics on standard input to newlines on standard output. The second sorts lines on standard input and writes the sorted data to standard output, discarding all but one copy of spans of adjacent identical lines. The third discards all lines consisting solely of digits. Together, these generate a sorted wordlist to standard output from text on standard input."
оператор "|" берет вывод программы слева и передает на ввод программе справа.
результат данного конвейера(pipeline):
a
first
gas
is
it
station
Тот же самый результат можно получить используя перенаправление(redirection) и введя 2 команды:
echo "it is (*^&*(#$*(^ a first gas#&*^station 2" > fileWithText //слить текст в файл:
tr -c '[:alnum:]' '[\\n*]' < fileWithText | sort -iu | grep -v '^[0-9]*$' //выполнить конвейер над текстом из файла
''пример2''
"Case Study: Two Ways to Write a Calculator Program
To be more concrete, let us contrast how the GUI and CLI styles can be usefully applied to the design of a simple interactive program: a desk calculator. Our examples for contrast are dc(1)/bc(1) and xcalc(1).
The xcalc(1) approach is simpler to describe because it mimics an interface with which novice users will be familiar; the man page says, in fact, “The numbered keys, the +/− key, and the +, −, *, /, and = keys all do exactly what you would expect them to”. All the capabilities of the program are conveyed by the visible button labels. This is the Rule of Least Surprise in its strongest form, and a real advantage for infrequent and novice users who will never have to read a man page to use the program.
However, xcalc also inherits the almost complete non-transparency of a calculator; when evaluating a complex expression, you don't get to see and sanity-check your keystrokes — which can be a problem if, say, you misplace a decimal point in an expression like (2.51 + 4.6) * 0.3. There's no history, so you can't check. You'll get a result, but it won't be the result of the calculation you intended.
With the dc(1) and bc(1) programs, on the other hand, you can edit mistakes out of the expression as you build it. Their interface is more transparent, because you can see the calculation that is being performed at every stage. It is more expressive because the dc/bc interpreter, not being limited to what fits on a reasonably-sized visual mockup of a calculator, can include a much larger repertoire of functions (and facilities such as if/then/else, stored variables, and iteration). It also incurs, of course, a higher mnemonic load.
Concision is more of a toss-up; good typists will find the CLI more concise, while poor ones may find it faster to point and click. Scriptability is not a toss-up; dc/bc can easily be used as a filter, but xcalc can't be scripted at all.
The tradeoff between ease for novices and utility for expert users is very clear here. For casual use in situations where a mental-arithmetic error check is not hard, xcalc wins. For more complex calculations where the steps must not only be correct but must be seen to be correct, or in which they are most conveniently generated by another program, dc/bc wins."
===================
''Отсебятина:''
если нужно быстро решить задачу, не имея времени на разбор программы, то GUI со своей интуитивностью подходит лучше.
юниксовые cli-программы (с их километровыми мануалами) для решения задачи "с наскока" не подходят.
мощность и гибкость в решении трудных и/или повторяющихся задач я пока оценил лишь на примере программы Vim. Хотя, я использовал gVim (GUI), но суть в том, что:
1) __я юзал клаву, а не мышь.__
2) __юзал спец.команды для быстрой навигации по тексту, копирования, вставки, поиска и пр. работы с текстом.__
3) __юзал скрипты для повторяющихся действий (например, набор преобразований над каждой строкой из большого множества cводится к созданию скрипта в виме - а по сути это запоминание твоих действий над одной строкой - и применении этого скрипта над множеством строк -- всё это может делаться за минуты).__
Я надеюсь, что переход на cli-программы из gui будет подобен переходу из notepad++ в gvim:
- придется преодолеть более высокий порог вхождения (выучить команды до автоматизма)
+ получу более продуктивное решение повседневных программистских задач.
Кстати, на мой взгляд - глупо отказываться от GUI там где он выгоден, скажем, Eclipse для отладки php-скриптов пока рулит.
веб-браузер, почтовик, аська-джабер, визуальные средства проектирования(аля Dia), чтение pdf, djvu -- всё это в gui-среде,
а вот для работы с svn можно и в консоль перебраться.
всю остальную работу с текстом хочу попробовать выполнять только на клаве в cli-среде.
На последок: вся эта unix-кутерьма сделана "программистами для программистов". А значит программисту имеет смысл попробовать CLI-программы.
* put that into .bashrc:
<code class="brush:">
export HISTFILESIZE=
export HISTSIZE=
</code>
There you go, unlimited history. Currently I have 27000 entries :)
From "man bash":
<code class="brush:">
If HIST‐FILESIZE is not set, no truncation is performed.
That means .bash_history is never truncated
</code>
Also the same seems to apply to HISTSIZE, although I couldnt find that documented.
* Go into your .bash_profile now and add these lines
<code class="brush:">
HISTFILESIZE=1000000000
HISTSIZE=1000000
</code>
| !date | !user | !location | !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |
| 16/01/2014 10:57:34 | Lindrid | [[/|http://lindrid.tiddlyspot.com/]] | [[store.cgi|http://lindrid.tiddlyspot.com/store.cgi]] | . | [[index.html | http://lindrid.tiddlyspot.com/index.html]] | . |
| 16/01/2014 11:00:14 | Lindrid | [[/|http://lindrid.tiddlyspot.com/]] | [[store.cgi|http://lindrid.tiddlyspot.com/store.cgi]] | . | [[index.html | http://lindrid.tiddlyspot.com/index.html]] | . |
| 26/01/2014 14:21:24 | Lindrid | [[/|http://lindrid.tiddlyspot.com/]] | [[store.cgi|http://lindrid.tiddlyspot.com/store.cgi]] | . | [[index.html | http://lindrid.tiddlyspot.com/index.html]] | . |
| 29/01/2014 12:42:18 | Lindrid | [[/|http://lindrid.tiddlyspot.com/]] | [[store.cgi|http://lindrid.tiddlyspot.com/store.cgi]] | . | [[index.html | http://lindrid.tiddlyspot.com/index.html]] | . |
| 18/07/2020 00:18:11 | Lindrid | [[/|http://lindrid.tiddlyspot.com/]] | [[store.cgi|http://lindrid.tiddlyspot.com/store.cgi]] | . | [[index.html | http://lindrid.tiddlyspot.com/index.html]] | . |
| 19/07/2020 13:21:00 | Lindrid | [[/|http://lindrid.tiddlyspot.com/]] | [[store.cgi|http://lindrid.tiddlyspot.com/store.cgi]] | . | [[index.html | http://lindrid.tiddlyspot.com/index.html]] | . |
| 15/06/2023 14:15:48 | Lindrid | [[/|http://lindrid.tiddlyspot.com/]] | [[store.cgi|http://lindrid.tiddlyspot.com/store.cgi]] | . | [[index.html | http://lindrid.tiddlyspot.com/index.html]] | . | ok |
| 15/06/2023 14:17:39 | Lindrid | [[/|http://lindrid.tiddlyspot.com/]] | [[store.cgi|http://lindrid.tiddlyspot.com/store.cgi]] | . | [[index.html | http://lindrid.tiddlyspot.com/index.html]] | . | ok |
| 15/06/2023 14:20:36 | Lindrid | [[/|http://lindrid.tiddlyspot.com/]] | [[store.cgi|http://lindrid.tiddlyspot.com/store.cgi]] | . | [[index.html | http://lindrid.tiddlyspot.com/index.html]] | . | ok |
| 15/06/2023 14:23:25 | Lindrid | [[/|http://lindrid.tiddlyspot.com/]] | [[store.cgi|http://lindrid.tiddlyspot.com/store.cgi]] | . | [[index.html | http://lindrid.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");
//}}}
[[Могут быть проблемы без $backupGlobals|http://www.phpunit.de/manual/current/en/fixtures.html#fixtures.global-state]]
<code class="brush:php">
// hide all notices
error_reporting(E_ALL ^ E_NOTICE);
require_once 'PHPUnit/Autoload.php';
require_once('/var/www/auto/www/init_functions.inc.php');
PHPUnit_Framework_Error_Warning::$enabled = FALSE;
PHPUnit_Framework_Error_Notice::$enabled = FALSE;
class UrlManagerTest extends PHPUnit_Framework_TestCase {
private $urlManager;
protected $backupGlobals = false;
public function setUp() {
error_reporting(E_ALL ^ E_NOTICE);
$this->urlManager = new UrlManager();
}
public function parserTest($expected_array, $uri, $deep_parse = false) {
$actual_array = $this->urlManager->parseUri($uri, $deep_parse);
$this->assertEquals($expected_array, $actual_array);
}
public function createSefUrlTest($expected_sef_url, $actual_url, $params = array()) {
$actual_sef_url = $this->urlManager->createSefUrl($actual_url, $params);
$this->assertEquals($expected_sef_url, $actual_sef_url);
}
public function testParseUriOnAllToyotaCars() {
$this->parserTest(array('fid' => 9), '/toyota/');
}
public function testCreateSefUrlExtendedSearchAllToyotasInRegion25OnPage3All() {
$this->createSefUrlTest("http://auto.drom.ru/search_extended/region25/toyota/page3/all/", "http://auto.drom.ru?search_extended&rid=25&fid=9&pg=3&s=all");
}
}
</code>
* [[Firebug Lite|https://chrome.google.com/webstore/detail/bmagokdooijbeehmkpknfglimnifench]] позволяет просматривать и редактировать HTML, CSS и JavaScript любой страницы «на лету», не выходя из браузера.
* [[IE Tab|http://www.proofsite.com.ua/goto/https://chrome.google.com/extensions/detail/hehijbfgiekmjfkfjpbkbammjbdenadd]] — запускает движок Internet Explorer непосредственно в интерфейсе Google Chrome, позволяя разработчику быстро просматривать и находить проблемные места в верстке сайта. Кроме того, иногда встречается обратная ситуация, при которой сайт адекватно отображается в Internet Explorer, но проблемно — в Mozilla Firefox или Google Chrome (в основном это относится к старым сайтам). Для таких сайтов в IE Tab предусмотрен режим автоматической загрузки определенного сайта сразу же в Internet Explorer, минуя его загрузку в Google Chrome.
* [[Resolution Test|http://www.proofsite.com.ua/goto/https://chrome.google.com/extensions/detail/idhfcdbheobinplaamokffboaccidbal]] для Google Chrome позволяет эмулировать изменение разрешение монитора за счет изменения размеров окна браузера.
* [[MeasureIt!|http://www.proofsite.com.ua/goto/https://chrome.google.com/extensions/detail/aonjhmdcgbgikgjapjckfkefpphjpgma]] — добавляет в Google Chrome — линейку, которая позволяет вам измерять в пикселях любой элемент или блок на сайте.
* [[Speed Tracer|http://www.proofsite.com.ua/goto/https://chrome.google.com/extensions/detail/ognampngfcbddbfemdapefohjiobgbdl]] — этот плагин позволит вам проанализировать, обнаружить и исправить проблемы в производительности вашего сайта.
* [[Chrome Sniffer|http://www.proofsite.com.ua/goto/https://chrome.google.com/extensions/detail/homgcnaoacgigpkkljjjekpignblkeae]] — позволяет узнать, какие Frameworks, CMS и JavaScript библиотеки используются на сайте. Использовать его очень просто — при загрузке сайта, в адресной строке появляется иконка того или иного приложения.
*[[Plugin for quick close another window and keep working in current window |http://www.vim.org/scripts/script.php?script_id=3573]]
*[[The NERD tree : A tree explorer plugin for navigating the filesystem|http://www.vim.org/scripts/script.php?script_id=1658]]
http://vladivostok.farpost.ru/sistemnyj-administrator-smennyj-grafik-raboty-2-2-7518386.html
http://vladivostok.hh.ru/vacancy/6863878
''Брать ли это?''
http://vk.com/away.php?to=http%3A%2F%2Fvladivostok.farpost.ru%2Fsoprovozhdenie-sajta-17687730.html
http://vladivostok.farpost.ru/trebuetsja-programmist-na-ne-polnyj-rabochij-den-17594895.html
http://vladivostok.farpost.ru/napisanie-i-podderzhka-programmy-autsors-17661079.html
*http://www.fprintf.net/vimCheatSheet.html
*http://www.worldtimzone.com/res/vi.html
*[[Ёмкий список VIM команд на русском|http://freesource.info/wiki/Stat'i/KratkoOboVsjom/VIM]]
*[[100 vim commands every programmer should know|http://www.catswhocode.com/blog/100-vim-commands-every-programmer-should-know]]
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='commentBreadcrumb' macro='commentBreadcrumb'></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>
<!--}}}-->
*http://eriwen.com/tools/vim-is-a-beautiful-tool/
* [[Семь привычек эффективного редактирования в Vim|http://www.moolenaar.net/habits_ru.html]]
This happens because:
* You have an actual syntax error with a mismatched paren or curly brace somewhere.
* You have a value in cpoptions that prevents semi-intelligent brace matching. Look up :help cpoptions and :help %.
* You have something too sophisicated for plain old Vim matching to handle. Try installing the matchit plugin, which may help. Common culprits are braces inside comments or regexes.
* Где-то есть коммент в котором есть bracket { или }
''Links''
http://zmievski.org/c/dl.php?file=talks/codeworks-2009/vim-for-php-programmers.pdf
http://zmievski.org/c/dl.php?file=other/andrei-vim-files.tar.gz
|Hotkey |Action |h
|Ctrl-N |auto-completion|
http://vimeo.com/user1690209/videos
http://vimcasts.org/
*http://www.catswhocode.com/blog/
* PK - Primary Key
* NN - Not Null
* BIN - Binary
* UN - Unsigned
* UQ - Create/remove Unique Key
* ZF - Zero-Filled
* AI - Auto Incremenent
Session itself is stored on the server side. Each browser accessing the server will get from the server unique Session ID. This Session ID browser sends to each page requested to the same server. So on client (browser) side, only Session ID is stored in the browser cookie (this is default behavior, when session cookies are enabled in the browser settings... there is also a technique called "URL rewriting" to embed SessionID as URL query parameter, each time the server is called, enabling the application to work even if browser session cookies are disabled - but, it is not so important for the basic session understanding)
So, in order that session for a browser works, the browser sends Session ID to each page being accessed on the same web site. Application server (web site server) finds the saved objects related to that Session ID in the session store (memory/disk/database...) on the server side and could work with those objects when processing the JSP page. Meaning - session objects data is stored on the server side.
The behavior you have experienced by executing "test1.jsp" after application restart is related to some other thing: The application servers (e.g. Apache Tomcat) have a possibility to persist the sessions after the server goes for restart and bring them back when the server is restarted again. The server actually serializes session objects from memory to disk (when going to restart) and deserializes them back from disk to memory afterwards (when restarting again).
If you stop the server and than start it again (not restart), those session objects will be most probably lost, and by executing "test1.jsp" in the same browser window again will give you null.
надоело мне записывать пометки на клочках бумаги и в левых файликах, которые я потом теряю, поставил себе прогу WinOrganizer.
заметки всякие, задачи, можно днюхи забить. а плюс, хочу сделать оповещение, типа 11:00 - перерыв, 12-30 -- на обед и тд. чтобы на часы не отвлекаться. хотя, это у меня пока виндовыми средствами сделано, но криво -- вызывается прога - форма на дельфи :D на ней написано: перерыв, обед и тд. :D
качать отсюда:
http://vsofte.ru/soft/text/6547-winorganizer-42-build-1585-crack-keygen-russkaya.html
один из лучших судя по http://rsdn.ru/forum/other/3578471.aspx
мне понравился.
* __''Ctrl-W s''__ for horizontal splitting
* __''Ctrl-W v''__ for vertical splitting
* __''Ctrl-w q''__ to close one
[[Original document here|http://stackoverflow.com/questions/1521501/how-to-open-files-in-vertically-horizontal-split-windows-in-vim]]
Операционные системы корпорации Microsoft для настольных и переносимых компьютеров можно разделить на три семейства:
Изначально это была 32ух разрядная система, NT - обозначает New Technology. Система предназначалась для деловых приложений, решающих критически важные, ответственные задачи, а также для домашнего использования.
С самого начала операционная система NT разрабатывалась в расчете на переносимость системы на другие платформы, поэтому она была практически полностью написана на C с очень небольшими включениями на ассемблере для низкоуровневых функций, таких как обработка прерываний. Первый выпуск состоял из 3.1 млн строк кода на C для операционной системы, библиотек и подсистем окружения.
''Некоторые отличия между Windows 95/98 и Windows NT''
|!Аспект|!Windows 95/98|!Windows NT|
|Полностью 32-разрядная система | нет | да |
|Безопасность? | нет | да |
|Защищенное отображение файлов? | нет | да |
|Приватное адресное пространство для каждой программы MS-DOS? | нет | да |
|Unicode? | нет | да |
|Процессор | Intel 80x86 | 80x86, Alpha, MIPS,... |
|Многопроцессорная поддержка? | нет | да |
|Реентерабельность кода операционной системы? | нет | да |
|Plug and Play | да | нет |
|Управление питанием? | да | нет |
|Файловая система FAT-32? | да | По желанию |
|Файловая система NTFS? | нет | да |
|Win32 API? | да | да |
|Поддержка всех старых программ MS-DOS? | да | нет |
|Критические данные ОС, доступные пользователю для записи? | да | нет |
*http://support.microsoft.com/kb/301583
*How to access the system tray using the keyboard?
You can move the keyboard focus directly to the systray area (system notification icons) with Win+B.
After selecting an icon with the arrow keys, you can simulate a left-click with Space or Enter, and a right-click with AppMenu or Shift+F10
http://www.eclipse.org/pdt/documents/XDebugGuide.pdf
!1
Try this:
<code class="brush:">
:let @" = expand("%")
</code>
this will copy the file name to the unamed register, then you can use good old 'p' to paste it. and of course you can map this to a key for quicker use.
<code class="brush:">
:nmap cp :let @" = expand("%")
</code>
you can also use this for full path
<code class="brush:">
:let @" = expand("%:p")
</code>
use '':help expand'' for more details
!2
Almost what you're asking for, and it might do: Ctrl+R % pulls the current filename into where you are (command prompt, edit buffer, ...). See this Vim Tip for more.
[[Original document here|http://stackoverflow.com/questions/916875/yank-file-name-path-of-current-buffer-in-vim]]
/<c-r><c-w>
or
:%s/foo/<c-r><c-w>/g
<c-r><c-w> means that you press Ctrl-R then Ctrl-W.
The word under the cursor will be inserted as though you typed it.
http://www.yiiframework.com/doc/guide/1.1/en/basics.mvc
/***
|''Name:''|YourSearchPlugin|
|''Version:''|2.1.6 (2012-04-19)|
|''Summary:''|Search your TiddlyWiki with advanced search features such as result lists, tiddler preview, result ranking, search filters, combined searches and many more.|
|''Source:''|http://tiddlywiki.abego-software.de/#YourSearchPlugin|
|''Twitter:''|[[@abego|https://twitter.com/#!/abego]]|
|''GitHub:''|https://github.com/abego/YourSearchPlugin|
|''Author:''|UdoBorkowski (ub [at] abego-software [dot] de)|
|''License:''|[[BSD open source license|http://www.abego-software.de/legal/apl-v10.html]]|
!About YourSearch
YourSearch gives you a bunch of new features to simplify and speed up your daily searches in TiddlyWiki. It seamlessly integrates into the standard TiddlyWiki search: just start typing into the 'search' field and explore!
For more information see [[Help|YourSearch Help]].
!Compatibility
This plugin requires TiddlyWiki 2.1.
Check the [[archive|http://tiddlywiki.abego-software.de/archive]] for ~YourSearchPlugins supporting older versions of TiddlyWiki.
!Revision history
* v2.1.6 (2012-04-19)
** Fix issue with IE8. Thanks to Roger Gallion for reporting and providing the fix. (For details see: https://github.com/abego/YourSearchPlugin/issues/1)
** remove warnings
* v2.1.5 (2010-02-16)
** Fix problems with CSS and search textfield. Thanks to Guido Glatzel for reporting.
* v2.1.4 (2009-09-04)
** Fix "this command is not supported" error under IE 8. Thanks to rouilj for reporting. (For details see: http://groups.google.com/group/TiddlyWiki/browse_thread/thread/cffee3254381e478)
* v2.1.3 (2008-04-16)
** Fix problem with Firefox3. Thanks to Andreas Hoefler for reporting.
* v2.1.2 (2008-03-17)
** Bug: on IE (6.0) the first letter is dropped from the search string. Thanks to Kashgarinn and Nick Padfield for reporting.
* v2.1.1 (2007-03-11)
** Extend "New tiddler" feature: Ctrl-Return invokes the "new tiddler" feature (create tiddler based on search text)
** Extend "New tiddler" feature: tiddler's text and tags may also be specified (see abego.parseNewTiddlerCommandLine)
** Support searching for URLs (like http://www.example.com)
** Provided extended public API (abego.YourSearch.getFoundTiddlers/getQuery/onShowResult)
** Clear MessageBox when search field gets focus (so the box no longer hides the search field)
** Reset search result when TiddlyWiki is changed
** Fix function abego.BoolExp
* v2.1.0 (2006-10-12)
** Release version with TiddlyWiki 2.1 support
*** Support (Extended) Field search
*** Support parenthesis in Boolean Search
*** Support direct regular expression input
*** Support JavaScript Expressions for filtering
*** "new tiddler" feature (create tiddler based on search text)
* v2.0.2 (2006-02-13)
** Bugfix for Firefox 1.5.0.1 related to the "Show prefix" checkbox. Thanks to Ted Pavlic for reporting and to BramChen for fixing.
** Internal
*** Make "JSLint" conform
* v2.0.1 (2006-02-05)
** Support "Exact Word Match" (use '=' to prefix word)
** Support default filter settings (when no filter flags are given in search term)
** Rework on the "less than 3 chars search text" feature (thanks to EricShulman)
** Better support SinglePageMode when doing "Open all tiddlers" (thanks to EricShulman)
** Support Firefox 1.5.0.1
** Bug: Fixed a hilite bug in "classic search mode" (thanks to EricShulman)
* v2.0.0 (2006-01-16)
** Add User Interface
* v1.0.1 (2006-01-06)
** Support TiddlyWiki 2.0
* v1.0.0 (2005-12-28)
** initial version
!Source Code
***/
//{{{
//============================================================================
//============================================================================
// YourSearchPlugin
//============================================================================
//============================================================================
// Ensure that the Plugin is only installed once.
//
if (!version.extensions.YourSearchPlugin) {
version.extensions.YourSearchPlugin = {
major: 2, minor: 1, revision: 6,
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-2012 (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 = "…";
};
//#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 (true) {
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 = false;
re.lastIndex = offset;
while (true) {
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];
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 reCloseParenthesis = /\s*\)/g; // match )
var reAndOr = /\s*(?:(and|\&\&)|(or|\|\|))/gi; // group 1: AND, group 2: OR
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 = false;
var result = null;
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 (true) {
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) 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;
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 = undefined; // Array of tiddlers that matched the last search
var lastQuery = undefined; // 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 = null; // The last search text, as passed to findMatches
var resultElement = null; // The (popup) DOM element containing the search result [may be null]
var searchInputField = null; // The "search" input field
var searchButton = null; // The "search" button
var lastNewTiddlerButton = null;
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 = undefined; // The index (in the current page) of the tiddler currently rendered.
var currentTiddler = undefined; // 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) 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);
// either create the button to the left or the right of the text.
var buttonAtRight = getFlag(args, "buttonAtRight");
var sizeTextbox = getParam(args, "sizeTextbox", this.sizeTextbox);
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 if (!config.browser.isIE)
txt.setAttribute("type","text");
var btn = createTiddlyButton(null,this.label,this.prompt,clickHandler);
if (place) {
if (!buttonAtRight)
place.appendChild(btn);
place.appendChild(txt);
if (buttonAtRight)
place.appendChild(btn);
}
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">© 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) {
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 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 of <span class=\"yourSearchCount\" macro=\"yourSearch count\"></span>\n"+
"\t\tfor <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> - \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-2012 ([[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.
***/
''Предисловие от Джеймса О. Коплина''
Мелочи важны. Эта книга посвещена вещам простым, но вовсе не малозначительным...
Мы считаем само собой разумеющимся, что ответственные профессионалы выделяют //некоторое// время на обдумывание и планирование проекта. Однако, внимание к мелочам является еще более важным аспектом профессионализма, чем любые грандиозные планы. Во-первых, благодаря практике в мелочах профессионалы приобретают квалификацию и репутацию для серьезных проектов. Во-вторых, даже мельчайшее проявление небрежности при строительстве - дверь, которая неплотно закрывается, или криво положенная плитка на полу, или даже захламленный стол - полностью рассеивает очарование всего сооружения. Чтобы этого не происходило с вашими программами, //код должен быть чистым//.
__Книга являет лучшим практическим применением принципов [[Lean|http://en.wikipedia.org/wiki/Lean_software_development]] в области разработки ПО__. В основу методологии Lean заложены "принципы 5S", взятые из методологии повышения качества TPM, использованной в японской промышленности. TPM была ориентирована прежде всего на сопровождение, а не на производство. А так как 80% и более того, что программисты делают - это сопровождение (или починка), то "принципы 5S" могут быть весьма полезными:
* //Сэйри//, или __организация__. Абсолютно необходимо знать, где что находится - и в этом помогает грамотный выбор имен идентификаторов.
* //Сэйтон//, или __аккуратность__. Старая американская пословица гласит: всему свое место, и все оказывается на своих местах. Фрагмент кода должен находится там, где читатель кода ожидает его найти, - а если он находится где-то в другом месте, переработайте свой код и разместите его там, где ему положено быть.
* //Сэйсо//, или __чистка__. Рабочее место должно быть свободно от висящих проводов, грязи, мусора и хлама. В этой книге авторы советуют избавиться от загромождения кода комментариями и закоментированными строками кода.
* //Сэйкэцу//, или __стандартизация__: группа достигает согласия по поводу того, как поддерживать чистоту на рабочем месте. В этой книге сказано о наличии единого стиля кодирования и набора правил в группах.
* //Сюцукэ//, или __дисциплина__. Программист должен быть достаточно дисциплинированным, чтобы следовать правилам, он должен часто размышлять о своей работе и быть готовым к изменениям.
По правилам TPM аварийный ремонт (аналог проявления ошибок) является исключением. Вместо этого машины ежедневно //осматривают и заменяют изнашивающиеся части до того, как они сломаются//. Безжалостно перерабатывайте свой код. Ваш код должен не только работать, но и хорошо читаться. Как нас учит Фред Брукс, крупные блоки программного кода стоит переписывать "с нуля" каждые семь лет или около того, чтобы они не обрастали мхом. Но может быть, временную константу Брукса стоит вывести на уровень недель, дней и часов вместо годов. Именно на этом уровне живут мелочи.
К сожалению, описанные аспекты редко рассматриваются как краеугольные камни искусства программирования. Однако в ходе исследований в лаборатории Bell Labs выяснилось, что последовательный стиль применения отступов является одним из самых статически значимых признаков низкой плотности ошибок. Мы же хотим, чтобы причиной качества была архитектура, язык программирования или что-то другое, столь же почтенное. Нас, как профессионалов, оскорбляет сама идея, что простое последовательное применение отступов может иметь такую ценность. __Качество возникает в результате миллиона проявлений небезразличного отношения к делу,- а не от применения какого-то великого метода__.
Книга соответствует текущим мировоззрениям настоящих программистов - таких, как Peter Sommerlad, Kevlin Henney. Giovanni Asproni. "Код есть архитектура" и "простой код" - так звучат их мантры. Очень важно помнить, что архитектура живет в коде. __Рассматривайте свой код как процесс, а не как статическую конечную точку__.
Датская народная мудрость рекомендует нам не только обращать внимание на мелочи, но и быть //честными// в мелочах. Это означает честность в коде, честность с коллегами и, что самое важное, - честность перед самим собой по поводу состояния вашего кода. Действительно ли мы сделали все возможное для того, чтобы "оставить место лагеря чище, чем было до нашего прихода"? Переработали ли свой код перед тем, как сдавать его? Эти проблемы лежать в самом сердце системы ценностей Agile.
P.S. Как указывает Дядюшка Боб в своем введении, хорошая практика программирования требует таких качеств, как сосредоточенность, присутствие духа и мышление.
P.P.S. Завершая свои высокопарные размышления, я отправляюсь наводить порядок на своем столе.
{{{#}}}
{{{#}}} ----------------------------------------------
{{{#}}} Keymap file for Ancient Domains Of Mystery
{{{#}}} ----------------------------------------------
{{{#}}}
{{{#}}} Lines starting with a '{{{#}}}' are ignored. Empty lines are also ignored.
{{{#}}}
{{{#}}} If you want to use more than one keycode for a specific command, you can
{{{#}}} define multiple key-bindings by separating them with a SPACE character
{{{#}}} (see the 'Wait' command for an example).
{{{#}}}
{{{#}}} The following special characters are used:
{{{#}}}
{{{#}}} \Mx -- press the control key and some key x (for letters use the
{{{#}}} the lowercase letter)
{{{#}}} \Cx -- press the control key and some key x
{{{#}}} \S -- SPACE
{{{#}}} \\ -- the backslash '\' itself
{{{#}}} \L, \R, \U, \D -- the cursor keys left, right, up and down
{{{#}}} \1 -- F1
{{{#}}} \2 -- F2
{{{#}}} \3 -- F3
{{{#}}} \4 -- F4
{{{#}}} \5 -- F5
{{{#}}} \6 -- F6
{{{#}}} \7 -- F7
{{{#}}} \8 -- F8
{{{#}}} \9 -- F9
{{{#}}}
{{{#}}} Attention: not all combinations of meta keys and normal keys might be
{{{#}}} possible. Make sure to check this if you redefine the keyboard.
{{{#}}} Note that the ENTER key is equal to (and thus represented by) \Cm.
{{{#}}}
{{{#}}} IMPORTANT NOTE:
{{{#}}} While in theory you can redefine the keys in any way you like in
{{{#}}} practice this is not necessarily recommened, because some functions
{{{#}}} in ADOM expect certain commands *not* to be bound to certain letters.
{{{#}}}
{{{#}}} The following commands (the abbreviations from the definitions are
{{{#}}} used)
{{{#}}}
{{{#}}} MON MNW MOW MSW MOS MSE MOE MNE WAT
{{{#}}}
{{{#}}} should *NOT* be bound to one of the following keys (separated by white-
{{{#}}} space):
{{{#}}}
{{{#}}} t T z Z \S + -
{{{#}}}
{{{#}}} You *can* set them to one of the keys mentioned but this breaks all
{{{#}}} functions for targetting and determining directions. You have been
{{{#}}} warned.
{{{#}}}
{{{#}}} Current version of ADOM: Version 1.1.1
{{{#}}}
{{{#}}}
{{{#}}} Activate trap
{{{#}}}
ACT:\Ct
{{{#}}}
{{{#}}} Apply skill
{{{#}}}
ASK:a
{{{#}}}
{{{#}}} Ascend stairway/Leave location
{{{#}}}
ASC:<
{{{#}}}
{{{#}}} Cast spell
{{{#}}}
CST:Z
{{{#}}}
{{{#}}} Chat with monsters
{{{#}}}
TLK:C
{{{#}}}
{{{#}}} Change highlight mode
{{{#}}}
HIL:H
{{{#}}}
{{{#}}} Change tactic
{{{#}}}
TAC:T
{{{#}}}
{{{#}}} Check literacy
{{{#}}}
LIT:L
{{{#}}}
{{{#}}} Clean ears
{{{#}}}
CLE:E
{{{#}}}
{{{#}}} Close door
{{{#}}}
CLO:c
{{{#}}}
{{{#}}} Continuous search
{{{#}}}
CSE:ws
{{{#}}}
{{{#}}} Create short character logfile
{{{#}}}
CSL:(
{{{#}}}
{{{#}}} Create verbose character logfile
{{{#}}}
CVL:)
{{{#}}}
{{{#}}} Create screenshot
{{{#}}}
CSS:[
{{{#}}}
{{{#}}} Descend stairway/Enter location
{{{#}}}
DSC:>
{{{#}}}
{{{#}}} Describe weather
{{{#}}}
DEW::W
{{{#}}}
{{{#}}} Dip (something) into (potion)
{{{#}}}
DIP:!
{{{#}}}
{{{#}}} Display available talents
{{{#}}}
DAT::T
{{{#}}}
{{{#}}} Display and quick-mark skills
{{{#}}}
DSK:A
{{{#}}}
{{{#}}} Display background
{{{#}}}
BKG:B
{{{#}}}
{{{#}}} Display bill
{{{#}}}
BIL:P
{{{#}}}
{{{#}}} Display burden levels
{{{#}}}
DBL::b
{{{#}}}
{{{#}}} Display configuration variables
{{{#}}}
CFG:=
{{{#}}}
{{{#}}} Display chaos powers
{{{#}}}
CHP:\\
{{{#}}}
{{{#}}} Display character information
{{{#}}}
DCI:@
{{{#}}}
{{{#}}} Display companions
{{{#}}}
DCO::c
{{{#}}}
{{{#}}} Display current wealth
{{{#}}}
MNY:$
{{{#}}}
{{{#}}} Display name of your deity
{{{#}}}
DID::g
{{{#}}}
{{{#}}} Display elapsed game time
{{{#}}}
DET:\Ce
{{{#}}}
{{{#}}} Display identified items
{{{#}}}
IDI:/
{{{#}}}
{{{#}}} Display kick statistics
{{{#}}}
KST:K
{{{#}}}
{{{#}}} Display killed monsters
{{{#}}}
DKM::k
{{{#}}}
{{{#}}} Display level map
{{{#}}}
DLM:\Ml
{{{#}}}
{{{#}}} Display message buffer
{{{#}}}
MSG::m
{{{#}}}
{{{#}}} Display missile statistics
{{{#}}}
DMS:M
{{{#}}}
{{{#}}} Display monster wound status
{{{#}}}
MWS::w
{{{#}}}
{{{#}}} Display quest status
{{{#}}}
QST:q
{{{#}}}
{{{#}}} Display recipes
{{{#}}}
RCP:R
{{{#}}}
{{{#}}} Display required experience
{{{#}}}
EXP:x
{{{#}}}
{{{#}}} Display talents
{{{#}}}
DTL:\Mt
{{{#}}}
{{{#}}} Display version
{{{#}}}
VER:V
{{{#}}}
{{{#}}} Display weapon skills
{{{#}}}
DWS:\Cw
{{{#}}}
{{{#}}} Display weapon statistics
{{{#}}}
WST:W
{{{#}}}
{{{#}}} Drink
{{{#}}}
DRK:D
{{{#}}}
{{{#}}} Drop item(s)
{{{#}}}
DRO:d
{{{#}}}
{{{#}}} Drop items in a comfortable way
{{{#}}}
DRC:\Cd
{{{#}}}
{{{#}}} Eat
{{{#}}}
EAT:e
{{{#}}}
{{{#}}} Examine environment
{{{#}}}
EXE:l
{{{#}}}
{{{#}}} Extended drop
{{{#}}}
EDR::d
{{{#}}}
{{{#}}} Extended pay
{{{#}}}
EPA::p
{{{#}}}
{{{#}}} Extended use
{{{#}}}
EUS::u
{{{#}}}
{{{#}}} Give item to monster
{{{#}}}
GIV:g
{{{#}}}
{{{#}}} Handle something
{{{#}}}
HDL:h
{{{#}}}
{{{#}}} Inventory
{{{#}}}
INV:i
{{{#}}}
{{{#}}} Invoke mindcraft
{{{#}}}
INM:\Ci
{{{#}}}
{{{#}}} Issue order to companion
{{{#}}}
ISO:\Co
{{{#}}}
{{{#}}} Kick
{{{#}}}
KCK:k
{{{#}}}
{{{#}}} Look
{{{#}}}
LOK:\Cl
{{{#}}}
{{{#}}} Mark spells
{{{#}}}
MSP::Z
{{{#}}}
{{{#}}} Miscellaneous equipment
{{{#}}}
STF:I
{{{#}}}
{{{#}}} Move to the southwest
{{{#}}}
MSW:1 f\D\L f\L\D
{{{#}}}
{{{#}}} Move to the south
{{{#}}}
MOS:2 \D
{{{#}}}
{{{#}}} Move to the southeast
{{{#}}}
MSE:3 f\D\R f\R\D
{{{#}}}
{{{#}}} Move to the west
{{{#}}}
MOW:4 \L
{{{#}}}
{{{#}}} Move to the east
{{{#}}}
MOE:6 \R
{{{#}}}
{{{#}}} Move to the northwest
{{{#}}}
MNW:7 f\U\L f\L\U
{{{#}}}
{{{#}}} Move to the north
{{{#}}}
MON:8 \U
{{{#}}}
{{{#}}} Move to the northeast
{{{#}}}
MNE:9 f\U\R f\R\U
{{{#}}}
{{{#}}} Name monster/yourself
{{{#}}}
BAP:n
{{{#}}}
{{{#}}} Online help
{{{#}}}
HLP:?
{{{#}}}
{{{#}}} Open door
{{{#}}}
OPN:o
{{{#}}}
{{{#}}} Pay
{{{#}}}
PAY:p
{{{#}}}
{{{#}}} Pick up items primitively (fast)
{{{#}}}
PPK:;
{{{#}}}
{{{#}}} Pick up items
{{{#}}}
PCK:,
{{{#}}}
{{{#}}} Pick up items comfortably
{{{#}}}
CPC:\Cp
{{{#}}}
{{{#}}} Pray
{{{#}}}
PRA:_
{{{#}}}
{{{#}}} Quit game
{{{#}}}
QIT:Q
{{{#}}}
{{{#}}} Read
{{{#}}}
REA:r
{{{#}}}
{{{#}}} Recall monster memory
{{{#}}}
RMM:&
{{{#}}}
{{{#}}} Redraw screen
{{{#}}}
RED:\Cr
{{{#}}}
{{{#}}} Sacrifice
{{{#}}}
SAC:O
{{{#}}}
{{{#}}} Save and quit game
{{{#}}}
SAV:S
{{{#}}}
{{{#}}} Search
{{{#}}}
SEA:s
{{{#}}}
{{{#}}} Set tactics to 'berserker'
{{{#}}}
ST0:\1
{{{#}}}
{{{#}}} Set tactics to 'very aggressive'
{{{#}}}
ST1:\2
{{{#}}}
{{{#}}} Set tactics to 'aggressive'
{{{#}}}
ST2:\3
{{{#}}}
{{{#}}} Set tactics to 'normal'
{{{#}}}
ST3:\4
{{{#}}}
{{{#}}} Set tactics to 'defensive'
{{{#}}}
ST4:\5
{{{#}}}
{{{#}}} Set tactics to 'very defensive'
{{{#}}}
ST5:\6
{{{#}}}
{{{#}}} Set tactics to 'coward'
{{{#}}}
ST6:\7
{{{#}}}
{{{#}}} Set variable
{{{#}}}
SEV::=
{{{#}}}
{{{#}}} Shoot/Throw missile
{{{#}}}
SHT:t
{{{#}}}
{{{#}}} Swap position with monster
{{{#}}}
SWA::s
{{{#}}}
{{{#}}} Switch auto-pickup on/off
{{{#}}}
CAP:\Ca
{{{#}}}
{{{#}}} Switch the dynamic display
{{{#}}}
STS::t
{{{#}}}
{{{#}}} Switch the required (more) key
{{{#}}}
CMK:\Ck
{{{#}}}
{{{#}}} Unlock door
{{{#}}}
ULD:\Cu
{{{#}}}
{{{#}}} Use item
{{{#}}}
USE:U
{{{#}}}
{{{#}}} Use class power
{{{#}}}
UMP:\Cx
{{{#}}}
{{{#}}} Use special ability
{{{#}}}
SPA:m
{{{#}}}
{{{#}}} Use tool
{{{#}}}
UTO:u
{{{#}}}
{{{#}}} Wait
{{{#}}}
WAT:. 5
{{{#}}}
{{{#}}} Walk to the southwest
{{{#}}}
WM1:w1 wf\D\L wf\L\D
{{{#}}}
{{{#}}} Walk to the south
{{{#}}}
WM2:w2 w\D
{{{#}}}
{{{#}}} Walk to the southeast
{{{#}}}
WM3:w3 wf\D\R wf\R\D
{{{#}}}
{{{#}}} Walk to the west
{{{#}}}
WM4:w4 w\L
{{{#}}}
{{{#}}} Walk on the spot
{{{#}}}
WM5:w5 w.
{{{#}}}
{{{#}}} Walk to the east
{{{#}}}
WM6:w6 w\R
{{{#}}}
{{{#}}} Walk to the northwest
{{{#}}}
WM7:w7 wf\U\L wf\L\U
{{{#}}}
{{{#}}} Walk to the north
{{{#}}}
WM8:w8 w\U
{{{#}}}
{{{#}}} Walk to the northeast
{{{#}}}
WM9:w9 wf\U\R wf\R\U
{{{#}}}
{{{#}}} Wipe face
{{{#}}}
WIF:F
{{{#}}}
{{{#}}} Zap wand
{{{#}}}
ZAP:z
http://eriwen.com/tools/awk-is-a-beautiful-tool/
!Да будет код
Код никогда не исчезнет, потому что код представляет подробности требований. На определенном уровне эти подробности невозможно игнорировать или абстрагировать; их приходится определять. А когда требования определяются настолько подробно, чтобы они могли быть выполнены компьютером, это и есть программирование. А их определение есть код.
Вероятно, уровень абстракции наших языков продолжит расти. Я также ожидаю, что количество предметно-ориентированных языков продолжит расти. Но код от этого существовать не перестанет.
!Плохой код
Одна компания в конце 80-х годов написала приложение-бестселлер. Приложение стало чрезвычайно популярным, многие профессионалы покупали и использовали его. Но потом циклы выпуска новых версий стали затягиваться. Ошибки не исправлялись между версиями. Время загрузки росло, а сбои происходили все чаще. Помню тот день, когда я в раздражении закрыл этот продукт и никогда не запускал его. Вскоре эта компания разорилась.
Два десятилетия спустя я встретил одного из работников той компании и спросил его, что же произошло. Ответ подтвердил мои опасения. Они торопились с выпуском продукта на рынок и не обращали внимания на качество кода. С добавлением новых возможностей код становился все хуже и хуже, пока в какой-то момент не вышел из-под контроля. //Плохой код привел к краху компании.//
!Расплата за хаос в коде
Если вы занимались программированием более двух-трех лет, вам наверняка доводилось вязнуть в чужом — или в своем собственном — беспорядочном ходе.
Замедление может быть весьма значительным. За какие-нибудь год-два группы, очень быстро двигавшиеся вперед в самом начале проекта, начинают ползти со скоростью улитки. Каждое изменение, вносимое в код, нарушает работу кода в двух-трех местах. Ни одно изменение не проходит тривиально. Для каждого дополнения или модификации системы необходимо «понимать» все хитросплетения кода — чтобы в программе их стало еще больше. Со временем неразбериха разрастается настолько, что справиться с ней уже не удается. Выхода просто нет.
__По мере накопления хаоса в коде производительность группы начинает снижаться, асимптотически приближаясь к нулю.__
!Грандиозная переработка
В конечном итоге группа устраивает бунт. Она сообщает начальству, что не может продолжать разработку отвратительной кодовой базы, и требует переработки архитектуры. Для этого набирается новая «ударная группа»...
Однако к моменту завершения грандиозной переработки оказывается, что исходный состав давно покинул «ударную группу», а текущие участники требуют переработать новую систему, потому что в ней творится сущий хаос.
Если вы сталкивались хотя бы с некоторыми частями истории, которую я сейчас поведал, то вы уже знаете, что __поддержание чистоты кода не только окупает затраченное время; оно является делом профессионального выживания.__ (для больших проектов?)
!Отношение
Вам доводилось продираться через код настолько запутанный, что у вас уходили недели на то, что должно было занять несколько часов? Вы видели, как изменение, которое вроде бы должно вноситься в одной строке, приходится вносить в сотнях разных модулей? Эти симптомы стали слишком привычными.
Почему это происходит с кодом? Почему хороший код так быстро загнивает и превращается в плохой код? У нас обычно находится масса объяснений. Мы жалуемся на изменения в требованиях, противоречащие исходной архитектуре. Мы стенаем о графиках, слишком жестких для того, чтобы делать все, как положено. Мы сплетничаем о глупом начальстве, нетерпимых клиентах и бестолковых типах из отдела маркетинга. Однако вина лежит вовсе не на них, а на нас самих. __Дело в нашем непрофессионализме__.
!Основной парадокс
Программисты сталкиваются с основным парадоксом базовых ценностей. Каждый разработчик, имеющий сколько-нибудь значительный опыт работы, знает, что предыдущий беспорядок замедляет его работу. Но при этом все разработчики под давлением творят беспорядок в своем коде для соблюдения графика. Короче, у них нет времени, чтобы работать быстро!
Настоящие профессионалы знают, что вторая половина этого парадокса неверна. Невозможно выдержать график, устроив беспорядок. На самом деле этот беспорядок сразу же замедлит вашу работу, и график будет сорван. __Единственный способ выдержать график — и единственный способ работать быстро — заключается в том, чтобы постоянно поддерживать чистоту в коде.__
!Искусство чистого кода?
К сожалению, написание чистого кода имеет много общего с живописью. Таким образом, умение отличать чистый код от грязного еще не означает, что вы умеете писать чистый код!
Чтобы написать чистый код, необходимо сознательно применять множество приемов, руководствуясь приобретенным усердным трудом чувством «чистоты». Ключевую роль здесь играет «чувство кода». Программист без «чувства кода» посмотрит на грязный модуль и распознает беспорядок, но понятия не имеет, что с ним делать. Программист с «чувством кода» смотрит на грязный модуль и видит различные варианты и возможности. «Чувство кода» поможет ему выбрать лучший вариант и спланировать последовательность преобразований, сохраняющих поведение программы и приводящих к нужному результату.
!Что такое «чистый код»?
Я спросил у некоторых известных, чрезвычайно опытных программистов, что они думают по этому поводу.
''БЬЁРН СТРАУСТРУП, СОЗДАТЕЛЬ C++ И АВТОР КНИГИ «THE C++ PROGRAMMING LANGUAGE»''
>Я люблю, чтобы мой код был элегантным и эффективным. Логика должны быть достаточно прямолинейной, чтобы ошибкам было трудно спрятаться; зависимости — минимальными, чтобы упростить сопровождение; обработка ошибок — полной в соответствии с выработанной стратегией; а производительность — близкой к оптимальной, чтобы не искушать людей загрязнять код беспринципными оптимизациями. Чистый код хорошо решает одну задачу.
''ГРЭДИ БУЧ, АВТОР КНИГИ «OBJECT ORIENTED ANALYSIS AND DESIGN WITH APPLICATIONS»''
>Чистый код прост и прямолинеен. Чистый код читается, как хорошо написанная проза. Чистый код никогда не затемняет намерения проектировщика; он полон четких абстракций и простых линий передачи управления.
''«БОЛЬШОЙ» ДЭЙВ ТОМАС, ОСНОВАТЕЛЬ OTI, КРЕСТНЫЙ ОТЕЦ СТРАТЕГИИ ECLIPSE''
>Чистый код может читаться и усовершенствоваться другими разработчиками, кроме его исходного автора. Для него написаны модульные и приемочные тесты. В чистом коде используются содержательные имена. Для выполнения одной операции в нем используется один путь (вместо нескольких разных). Чистый код обладает минимальными зависимостями, которые явно определены, и четким, минимальным API. Код должен быть грамотным, потому что в зависимости от языка не вся необходимая информация может быть четко выражена в самом коде.
''МАЙКЛ ФИЗЕРС, АВТОР КНИГИ «WORKING EFFECTIVELY WITH LEGACY CODE»''
>Я мог бы перечислить все признаки, присущие чистому коду, но существует один важнейший признак, из которого следуют все остальные. Чистый код всегда выглядит так, словно его автор над ним тщательно потрудился. Вы не найдете никаких очевидных возможностей для его улучшения. Все они уже были продуманы автором кода. Попытавшись представить возможные усовершенствования, вы снова придете к тому, с чего все началось: вы рассматриваете код, тщательно продуманный и написанный настоящим мастером, небезразличным к своему ремеслу.
''УОРД КАННИНГЕМ, СОЗДАТЕЛЬ WIKI, СОЗДАТЕЛЬ FIT, ОДИН ИЗ СОЗДАТЕЛЕЙ ЭКСТРЕМАЛЬНОГО ПРОГРАММИРОВАНИЯ. ВДОХНОВИТЕЛЬ
НАПИСАНИЯ КНИГИ «DESIGN PATTERNS». ДУХОВНЫЙ ЛИДЕР SMALLTALK И ОБЪЕКТНО-ОРИЕНТИРОВАННОГО ПОДХОДА. КРЕСТНЫЙ ОТЕЦ ВСЕХ, КТО ТЩАТЕЛЬНО ОТНОСИТСЯ К НАПИСАНИЮ КОДА.''
>Вы работаете с чистым кодом, если каждая функция делает примерно то, что вы от нее ожидали. Код можно назвать красивым, если у вас также создается впечатление, что язык был создан специально для этой задачи.
!Важный вывод
''__Соотношение времени чтения и написания кода превышает 10:1__''. Мы постоянно читаем свой старый код, поскольку это необходимо для написания нового кода.
Из-за столь высокого соотношения наш код должен легко читаться, даже если это затрудняет его написание. Конечно, написать код, не прочитав его, невозможно, так что упрощение чтения в действительности упрощает и написание кода.
Уйти от этой логики невозможно. Невозможно написать код без предварительного чтения окружающего кода. Код, который вы собираетесь написать сегодня, будет легко или тяжело читаться в зависимости от того, насколько легко или тяжело читается окружающий код. Если вы хотите быстро справиться со своей задачей, если вы хотите, чтобы ваш код было легко писать — позаботьтесь о том, чтобы он легко читался.
''"It is not possible to check out a single file. The finest level of checkouts you can do is at the directory level."''
How do I get around this issue when using Subversion?
We have this folder in Subversion where we keep all our images. I just want to check out one file (image) from that. This folder is really big and has ton of other stuff which I don't need now.
''Answer:''
* The simple answer is that you svn export the file instead of checking it out.
But that might not be what you want. You might want to work on the file and check it back in, without having to download GB of junk you don't need.
If you have subversion 1.5, then do a sparse checkout:
<code class="brush:">
svn checkout <url_of_big_dir> <target> --depth empty
cd <target>
svn up <file_you_want>
</code>
For older svn, you might benefit from the following:
Checkout the directory using a revision back in the distant past, when it was less full of junk you don't need.
Update the file you want, to create a mixed revision. This works even if the file didn't exist in the revision you checked out.
Profit!
An alternative (for instance if the directory has too much junk right from the revision in which it was created) is to do a URL->URL copy of the file you want into a new place in the repository (effectively this is a working branch of the file). Check out that directory and do your modifications.
I'm not sure whether you can then merge your modified copy back entirely in the repository without a working copy of the target - I've never needed to. If so then do that.
If not then unfortunately you may have to find someone else who does have the whole directory checked out and get them to do it. Or maybe by the time you've made your mods, the rest of it will have finished downloading...
* try export
<code class="brush:">
svn export <path_to_file>
</code>
|:b Filename |Toggle to buffer with name filename|
|:tag funcName |Toggle to file with function funcName|
|"+x |Cut data to global buffer|
|"+y |Copy data to global buffer|
|"+p |Paste data from global buffer|
sudo svn delete some_file
Ничто не помогает так, как уместный комментарий. Ничто не загромаждает модуль так, как бессодержательные и безапеляционные комментарии. Ничто не приносит столько вреда, как старый, утративший актуальность комментарий, распространяющий ложь и дезинформацию.
Вы оказались в ситуации, в которой необходимо написать комментарий? Хорошенько подумайте, нельзя ли пойти по другому пути и выразить свои намерения в коде.
Комментарии лгут. Не всегда и не преднамеренно, но это происходит слишком часто. Причина проста: программисты не могут нормально сопровождать комментарии. Программный код изменяется и эволюционирует. Его фрагменты перемещаются из одного места в другое, раздваиваются, размножаются и сливаются. К сожалению, комментарии не всегда сопровождают их - и не всегда //могут// сопровождать их. Слишком часто комментарии отделяются от описываемого ими кода и превращаются в пометки непонятной принадлежности, с постоянно снижающейся точностью.
Только код может правдиво сообщить, что он делает. Это единственный источник действительно достоверной информации. Таким образом, хотя комментарии иногда необходимы, мы потратим немало усилий для того, чтобы свести их использование к минимуму.
!!Допустимые комментарии
*''Объясните свои намерения в коде''
:В некоторых ситуациях (каких?) код оказывается не лучшим средством для объяснений. Однако, __нередко задача сводится к созданию функции, которая сообщает то же, что и комментарий__, который вы собираетесь написать.
*''Хорошие комментарии - те, без которых удается обойтись''
*''Описание намерений, заложенных в решении''
*''Прояснение кода, который вы не можете изменить''
:В общем случае лучше подумать, как изменить имя загадочного аргумента или возвращаемого значения, чтобы они говорили сами за себя; но если они являются частью стандартной библиотеки или используются в коде, который вы не можете изменить, то пояснительный комментарий может быть весьма полезным. Прежде чем писать такие комментарии, убедитесь в том, что лучшего способа не существует, и еще внимательнее следите за их правдивостью (__комментарии которые лгут, хуже их отсутствия__).
*''Предупреждение о последствиях от каких-либо действий''
<code class="brush:java">
public static SimpleDateFormat makeStandartHttpDateFormat()
{
// Класс SimpleDateFormat не является потоково-безопасным,
// поэтому экземпляры должны создаваться независимо друг от друга
SimpleDateFormant df = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z");
df.setTimeZone(TimeZone.getTimeZone("GMT"));
return df;
}
</code>
*''Юридические комментарии''
:Например, авторские права. Вместо того, чтобы писать юридический трактат, ограничьтесь ссылкой на стандартную лицензию или другой внешний документ.
*''Комментарии TODO''
:Комментарии TODO напоминают о том, что, по мнению программиста, сделать необходимо, но по какой-то причине нельзя сделать прямо сейчас. Впрочем, это не повод оставлять плохой код в системе. Также код не должен загромождаться лишними комментариями TODO. Регулярно просматривайте их и удаляйте те, которые потеряли актуальность.
*''Усиление''
:Комментарий может подчеркивать важность обстоятельства, которое на первый взгляд кажется несущественным.
<code class="brush:java">
String listltemContent = match.group(3).trim();
// Вызов trim() очень важен. Он удаляет начальные пробелы,
// чтобы строка успешно интерпретировалась как список.
new ListItemWidget(this, listltemContent. this.level + 1);
return bui1dList(text.substring(match.end())):
</code>
*''Комментарии Javadoc в общедоступных API''
:Если вы разрабатываете API для общего пользования, несомненно, для него следует написать хорошие комментарии Javadoc.
*''Позиционные маркеры''
<code class="brush:java">
// Действия //////////////////////////////////
</code>
:Заголовки привлекают внимание только в том случае, если они встречаются не слишком часто. Используйте их умеренно и только тогда, когда они приносят ощутимую пользу.
!!Комментарии, которых стоит избегать
*''Комментарии не компенсируют плохого кода''
:Ясный и выразительный код с минимумом комментариев гораздо лучше громоздкого, сложного кода с большим количеством комментариев.
*''Комментарии, поясняющие код''
:Вместо них лучше писать самодокументированный код.
*''Комментарии как подпорки некачественного кода или оправдания сомнительных решений''
*''Комментарии «на скорую руку»''
:Не стоит лепить комментарии «на скорую руку» только потому, что вам кажется, что это уместно или этого требует процесс. Если уж вы решаете написать комментарий, не жалейте времени и напишите лучший из всех возможных комментариев.
*''Избыточные комментарии''
:Избыточный комментарий не объясняет код, не предоставляет обоснований и не раскрывает намерений.
:Он читается не проще, чем сам код. Более того, комментарий уступает коду в точности и навязывает читателю эту неточность взамен истинного понимания.
:Рассмотрим легион бесполезных, избыточных комментариев Javadoc, позаимствованных из Tomcat.
<code class="brush:java">
public abstract class ContainerBase implements Container,
Lifecycle, Pipeline, MBeanRegistration, Serializable
{
/**
* Задержка процессора для этого компонента.
*/
protected int backgroundProcessorDelay = -1;
/**
* Поддержка событий жизненного цикла для этого компонента.
*/
protected LifecycleSupport lifecycle = new LifecycleSupport(this);
/**
* Объект Pipeline, связанный с данным контейнером.
*/
protected Pipeline pipeline = new StandardPipeline(this);
//...
}
</code>
*''Недостоверные комментарии''
:__Комментарии которые лгут, хуже их отсутствия__
*''Обязательность комментирования кода может привести к бессмысленным комментариям''
:Правила, говорящие, что каждая функция должна иметь комментарий Javadoc или что каждая переменная должна быть помечена комментарием, — обычная __глупость__. Бессмысленные комментарии не приносят никакой пользы. Они только запутывают код, повышая риск обмана и недоразумений.
*''Комментарии за закрывающей фигурной скобкой''
<code class="brush:java">
main() {
//...
try {
while (dine = in.readLineO) != null) {
lineCount++;
charCount += line.lengthO;
String words[] = line.splitCWW");
wordCount += words.length;
} //while
System.out.printIn("wordCount = " + wordCount);
System.out.println("lineCount = " + lineCount);
System, out. printlnCcharCount = " + charCount);
} // try
catch (IOException e) {
System.err.printlnC'Error;" + e.getMessage());
} //catch
} //main
</code>
:Применение таких комментариев оправдано в длинных функциях с многоуровневой вложенностью, но они только загромождают компактные специализированные функции, которым мы отдает предпочтение. Итак, если у вас возникает желание прокомментировать закрывающие фигурные скобки, лучше постарайтесь укоротить свои функции.
*''Не используйте комментарии там, где можно использовать функцию или переменную''
Возьмем следующий фрагмент кода
<code class="brush:java">
// Зависит ли модуль из глобального списка <mod> от подсистемы,
// частью которой является наш код?
if (smodulе.getDependSubsystems().contains(subSysMod.getSubSystem()))
</code>
Его можно было бы перефразировать без комментария в следующем виде:
<code class="brush:java">
ArrayList moduleDependees = smodule.getDependSubsystems();
String ourSubSystem = subSysMod.getSubSystem();
if (moduleDependees.contains(ourSubSystem))
</code>
*''Ссылки на авторов''
<code class="brush:java">
/* Добавлено Риком */
</code>
:Системы контроля исходного кода отлично запоминают, кто и когда внес то или иное исправление. Нет необходимости загрязнять код подобными ссылками.
*''Закомментированный код''
:В программировании редко встречаются привычки более отвратительные, чем закрытие комментариями неиспользуемого кода.
:Читая код, могут возникнуть вопросы. Почему строки кода закомментированы? Они важны? Их оставили как напоминание о будущих изменениях? Или это «хлам», который кто-то закомментировал сто лет назад и не удосужился убрать из программы?
:Используйте системы контроля исходного кода. Эти системы запоминают изменения в коде за нас. Нам уже не нужно закрывать их комментариями. Просто удалите ненужный код. Он никуда не исчезнет. Честное слово.
*''Комментарии HTML''
:HTML в комментариях к исходному коду выглядит отвратительно. Он затрудняет чтение комментариев именно там, где они должны легко читаться — в редакторе/IDE. Если комментарии должны извлекаться внешним инструментом (например, Javadoc) для отображения в вебстранице, то за украшение комментариев соответствующим кодом HTML должен отвечать этот инструмент, а не программист.
*''Нелокальная информация''
:Если вы должны написать комментарий, проследите за тем, чтобы он описывал находящийся поблизости код. Не излагайте информацию системного уровня в контексте локального комментария. Иначе ничто не гарантирует, что комментарий будет изменен при изменении кода, который он комментирует.
*''Слишком много информации''
:Не включайте в комментарии исторические дискуссии или описания подробностей, не относящиеся к делу. Вполне достаточно ссылки или номера RFC.
*''Неочевидные комментарии''
:Цель комментария — объяснить код, который не объясняет сам себя. Плохо, когда сам комментарий нуждается в объяснениях.
*''Заголовки функций''
:Короткие функции не нуждаются в долгих описаниях. Хорошо выбранное имя компактной функции, которая выполняет одну операцию, обычно лучше заголовка с комментарием.
*''Заголовки Javadoc во внутреннем коде''
:При всей полезности комментариев Javadoc для API общего пользования не применяйте их в коде, не предназначенном для общего потребления. Генерирование страниц Javadoc для внутренних классов и функций системы обычно не приносит реальной пользы, а формализм комментариев Javadoc только отвлекает читателя.
''Вертикальные расстояния''
Концепции, тесно связанные друг с другом, должны находиться поблизости друг от друга по вертикали.
Тесно связанные концепции не должны находиться в разных файлах, если только это не объясняется очень вескими доводами.
http://eriwen.com/productivity/find-is-a-beautiful-tool/
http://danielmiessler.com/study/find/
http://betterthangrep.com/ - ''ack'' is a tool like grep, designed for programmers with large trees of heterogeneous source code.
http://eriwen.com/tools/grep-is-a-beautiful-tool/
<code class="brush:">
find . -name '*.php' | xargs grep <your pattern here>
</code>
<code class="brush:">
ctrl+alt+t = terminal
ctrl+alt+c = google chrome
</code>
''Terminal''
<code class="brush:">
ctrl+shift+c = copy
ctrl+shift+v = paste
</code>
''Midnight Commander''
<code class="brush:">
C-x + h = add dir to favorites
C-\ = favorite dirs
C-s = find file/catalog
</code>
shortcuts
The documentation for NERDTree shows that you can change the mapping letter for most, if not all of the mappings. For example,
<code class="brush:">
":help NERTree-t"
</code>
shows this:
<code class="brush:">
Default key: t
Map option: NERDTreeMapOpenInTab
Applies to: files and directories.
</code>
So you can put in your vimrc something like this to change it from "t" to "\t":
<code class="brush:">
let NERDTreeMapOpenInTab='\t'
</code>
Then NERDTree will stop overriding your preferred functinality of the "t" key in normal mode.
<code class="brush:">
apt-get install vim vim-scripts vim-doc vim-latexsuite vim-gui-common vim-gnome
</code>
List of repositories
<code class="brush:">
/etc/apt/sources.list
</code>
* Download https://getcomposer.org/composer.phar
* go to your dir
* php composer.phar global require "laravel/installer"
* laravel new <project name>
* solve problem [[Compatibility with sass-loader 8.0.0]]
* php composer.phar install == create folder vendor
* copy .env.example to .env
* run command = php artisan key:generate = (to eliminate the error: production.ERROR: No application encryption key has been specified.)
* npm install vue
* npm install vue-router
* npm install bootstrap-vue
* php artisan create:view spa
* Edit spa.blade.php: Copy-paste the stylesheet <link> into your <head> before all other stylesheets to load our CSS. from here https://getbootstrap.com/docs/4.5/getting-started/introduction/
> vim plugin.vba
Then source it:
:so %
http://blog.termit.name/jquery/
http://www.rsdn.ru/article/inet/jQuery.xml
To define a mapping which uses the "mapleader" variable, the special string
"<Leader>" can be used. It is replaced with the string value of "mapleader".
If "mapleader" is not set or empty, a backslash is used instead.
Example:
:map <Leader>A oanother line <Esc>
Works like:
:map \A oanother line <Esc>
But after:
:let mapleader = ","
It works like:
:map ,A oanother line <Esc>
Note that the value of "mapleader" is used at the moment the mapping is
defined. Changing "mapleader" after that has no effect for already defined
mappings.
создаем пустой git репозиторий
$ git init
Линкуем к новому репозиторию
$ git remote add origin https://lindrid32@bitbucket.org/lindrid32/h2h.git
http://vim.wikia.com/wiki/Editing_remote_files_via_scp_in_vim
* [[Download|http://www.vim.org/scripts/script.php?script_id=1075]]
* install:
<code class="">
gvim netrw.vba
:so %
:q
</code>
''Tips from Zmievsky''
* makes it possible to read, write, and browse remote directories and files
* i usually use it over ssh connections via scp
* need to run ssh-agent to avoid continuous prompts for passphrase
* don't use passphrase-less keys!
* once set up:
* vim scp://hostname/path/to/file
* :new scp://hostname/path/to/dir/
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='commentBreadcrumb' macro='commentBreadcrumb'></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='viewer' macro='view text wikified'></div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='tagClear'></div>
<div class='comments' macro='comments'></div>
private void compactExpectedAndActualО {
prefixlndex = findCommonPrefix();
suffixlndex = findCommonSuffixO;
compactExpected = compactString(expected);
compactActual = compactString(actual);
}
private int findCommonPrefix() {
int prefixlndex = 0;
int end = Math.min(expected.length(), actual .lengthO);
for (; prefixlndex < end; prefixlndex++) {
if (expected.charAt(prefixIndex) != actual.charAt(prefixlndex))
break;
}
return prefixlndex;
}
private int findCommonSuffix() {
int expectedSuffix - expected.length О - 1;
int actualSuffix = actual.lengthО - 1;
for (; actualSuffix >= prefixlndex && expectedSuffix >= prefixlndex;
actualSuffix--, expectedSuffix--) {
if (expected.charAt(expectedSuffix) != actual.charAt(actualSuffix))
break;
}
return expected.length0 - expectedSuffix:
}
Тщательное изучение f i ndCommonSuf f i x выявляет скрытую временную привязку
[G31]; работа функции зависит от того, что значение prefixlndex вычисляется
функцией findCommonPrefix. Если вызвать эти две функции в неверном порядке,
вам предстоит непростой сеанс отладки. Чтобы эта временная привязка стала
очевидной, значение prefixlndex будет передаваться при вызове findCommonSuffix
в аргументе.
private void compactExpectedAndActualО {
prefixlndex = findCommonPrefixO;
suffixlndex = findCommonSuffix(prefixlndex);
{{{:}}}sp filename (horizontal)
{{{:}}}vsp filename (vertical)
Для работы в окружении, показанном на рис. 1.12, операционная система должна знать о том, какие периферийные устройства подключены компьютеру, и сконфигурировать эти устройства. Это требование заставило корпорации Intel и Microsoft разработать для PC-совместимых компьютеров систему, называемую plug and play (подключи и работай). Она основанна на аналогичной концепции, первоначально реализованной в Apple Macintosh. //До появления plug and play каждая плата ввода-вывода имела фиксированный уровень запроса на прерывание и постоянные адреса для своих регистров ввода-вывода//. Например, клавиатура использовала прерывание 1 и адреса ввода-вывода от 0x60 до 0x64; контроллер гибкого диска использовал прерывание 6 и адреса ввода-вывода от 0x3F0 до 0x3F7; принтер использовал прерывание 7 и адреса ввода-вывода от 0x378 до 0х37А и т. д.
До поры до времени все это неплохо работало. Проблемы начинались, когда пользователь покупал звуковую карту и внутренний модем, и обнаруживалось, что оба устройства использовали, скажем, прерывание 4. Возникал конфликт, не позволяющий им работать вместе. Решением стало появление на каждой плате ввода-вывода DIP-переключателей или перемычек (jumpers) с последующим инструктированием пользователя о необходимости выбрать уровень запроса на прерывание и адреса ввода-вывода для данного устройства, которые не конфликтовали бы со всеми другими прерываниями и адресами, задействованными на его системе. Иногда выполнить эти требования без ошибок удавалось тем подросткам, которые посвятили свою жизнь решению головоломок компьютерного оборудования. Но, к сожалению, кроме них это практически никому не удавалось, что приводило к полному хаосу.
''Технология plug and play заставляет систему автоматически собирать информацию об устройствах ввода-вывода, централизованно присваивая уровни
запросов на прерывания и адреса ввода-вывода, а затем сообщать каждой карте, какие ей присвоены значения.'' Эта работа тесно связана с загрузкой компьютера.
scp copy_that_file.php you@192.168.1.1:/copy/here
http://eriwen.com/tools/get-sed-savvy-1/
http://eriwen.com/tools/get-sed-savvy-2/
http://eriwen.com/tools/get-sed-savvy-3/
<code class="brush:">
SELECT [параметры] элементы
[ INTO инф_файла ]
FROM таблицы
[ WHERE условие ]
[ GROUP BY тип_группировки ]
[ HAVING определение_where ]
[ ORDER BY тип_упорядочивания ]
[ LIMIT критерий ограничения ]
[ PROCEDURE имя_процедуры(аругменты) ]
[ параметры_блокировки ]
;
</code>
Ubuntu/Debian: cron start
* [[download|http://sourceforge.net/projects/vim-taglist/files/]] and install
* stick this in ~/.vim/after/plugin/general.vim
<code class="brush:">
let Tlist_Use_Right_Window = 1
let Tlist_Inc_Winwidth = 1
let Tlist_Exit_OnlyWindow = 1
let Tlist_File_Fold_Auto_Close = 1
let Tlist_Process_File_Always = 1
let Tlist_Enable_Fold_Column = 0
let tlist_php_settings = 'php;c:class;d:constant;f:function'
if exists('loaded_taglist')
nmap <silent> <F8> :TlistToggle<CR>
endif
</code>
* you can add
<code class="brush:">
Tlist_Ctags_Cmd = "/usr/local/bin/ctags-ex"
</code>
to ~/.vim/after/plugin/general.vim, if something went wrong.
* use plugin on F8
http://danielmiessler.com/study/tr/
* [[download|http://www.vim.org/scripts/script.php?script_id=90]] and install
* run command in vim
<code class="brush:">
:helptags Data/settings/vimfiles/doc
</code>
* setup subversion (git, cvs, etc...)
<code class="brush:">
" Make external commands work through a pipe instead of a pseudo-tty
"set noguipty
" You can also specify a different font, overriding the default font
"if has('gui_gtk2')
" set guifont=Bitstream\ Vera\ Sans\ Mono\ 12
"else
" set guifont=-misc-fixed-medium-r-normal--14-130-75-75-c-70-iso8859-1
"endif
" If you want to run gvim with a dark background, try using a different
" colorscheme or running 'gvim -reverse'.
" http://www.cs.cmu.edu/~maverick/VimColorSchemeTest/ has examples and
" downloads for the colorschemes on vim.org
" Source a global configuration file if available
if filereadable("/etc/vim/gvimrc.local")
source /etc/vim/gvimrc.local
endif
set encoding=cp1251
set fileencoding=windows-1251
set autoindent
set nowrap
set nobackup
set shiftwidth=2
set softtabstop=2
set expandtab
"set guifont=Courier_New:h12:cDEFAULT
colorscheme oceandeep
set guioptions-=m " turn off menu bar
set guioptions-=T " turn off toolbar
:map <F2> :NERDTreeToggle %:p<CR> set columns=100
:map <F3> :bp<CR>
:map <F4> :bn<CR>
:map <F5> :Project<CR> :vertical res 50<CR>
:map <F6> :e ++enc=cp1251<CR>
:map <F7> :e ++enc=utf-8 <CR>
map <C-s> :w <Return>
map <C-e> :VCSUpdate <Return>
map <C-c> :VCSCommit <C-R>=expand("%:p:t")<CR>
map <C-a> :VCSAdd <Return>
map <C-M-i> :VCSDiff <Return>
map <C-q> :bd <cr>
nnoremap <Space> :normal a <ESC>
map <M-f> :CommandT<Return>
noremap ' ;
noremap ; l
noremap l k
noremap k j
noremap j h
noremap <C-w>; <C-w>l
noremap <C-w>l <C-w>k
noremap <C-w>k <C-w>j
noremap <C-w>j <C-w>h
nnoremap <NL> i<CR><ESC>
"""""" Open new file from current file directory
" open file
map ,e :e <C-R>=expand("%:p:h") . "/" <CR>
map ,t :tabe <C-R>=expand("%:p:h") . "/" <CR>
" horizontal split edit file
map ,s :split <C-R>=expand("%:p:h") . "/" <CR>
" vertical split open file
map ,v :vsp <C-R>=expand("%:p:h") . "/" <CR>
let g:CommandTMaxFiles=40000
let g:CommandTMaxHeight=10
"let g:CommandTMatchWindowReverse=0
"let NERDTreeMapActivateNode='z'
"set wildmenu
"set wcm=<Tab>
"menu Encoding.windows-1251 :e ++enc=cp1251<CR>
"menu Encoding.utf-8 :e ++enc=utf-8 <CR>
"menu Encoding.koi8-r :e ++enc=koi8-r<CR>
"menu Encoding.ibm-866 :e ++enc=ibm866<CR>
"map <F8> :emenu Encoding.<TAB>
"set statusline+=%{&encoding},
"set statusline+=%{&fileformat}]
syntax on
filetype on
au BufNewFile,BufRead *.tmpl set filetype=php
set wfh
set wfw
map <F12>
\ :!ctags -f ./tags
\ --langmap="php:+.inc"
\ -h ".php.inc" -R --totals=yes
\ --tag-relative=yes --PHP-kinds=+cf-v .<CR>
set tags=./tags,tags
:lcd /home/lindrid/sources
""""""""""""""""""""""""" snippets!
:Iabbr dbg if ($isLindrid) {<cr>echo "<pre>";<cr>var_dump(<{}>);<cr>echo "</pre>";<cr>}
:Iabbr dbga if ($isAdmin) {<cr>echo "<pre>";<cr>var_dump(<{}>);<cr>echo "</pre>";<cr>}
</code>
<code class="brush:">
set nocompatible
source $VIMRUNTIME/vimrc_example.vim
source $VIMRUNTIME/mswin.vim
behave mswin
"filetype plugin on
set encoding=cp1251
set fileencoding=windows-1251
"set fileencodings=ucs-bom,utf-8
"set fileencodings=euc-jp
set autoindent
set nowrap
set nobackup
set softtabstop=4
set shiftwidth=4
set tabstop=4
set expandtab
set guifont=Courier_New:h10:cDEFAULT
colorscheme oceandeep
set diffexpr=MyDiff()
function MyDiff()
let opt = '-a --binary '
if &diffopt =~ 'icase' | let opt = opt . '-i ' | endif
if &diffopt =~ 'iwhite' | let opt = opt . '-b ' | endif
let arg1 = v:fname_in
if arg1 =~ ' ' | let arg1 = '"' . arg1 . '"' | endif
let arg2 = v:fname_new
if arg2 =~ ' ' | let arg2 = '"' . arg2 . '"' | endif
let arg3 = v:fname_out
if arg3 =~ ' ' | let arg3 = '"' . arg3 . '"' | endif
let eq = ''
if $VIMRUNTIME =~ ' '
if &sh =~ '\<cmd'
let cmd = '""' . $VIMRUNTIME . '\diff"'
let eq = '"'
else
let cmd = substitute($VIMRUNTIME, ' ', '" ', '') . '\diff"'
endif
else
let cmd = $VIMRUNTIME . '\diff'
endif
silent execute '!' . cmd . ' ' . opt . arg1 . ' ' . arg2 . ' > ' . arg3 . eq
endfunction
set guioptions-=m " turn off menu bar
set guioptions-=T " turn off toolbar
:map <F2> :NERDTreeToggle %:p<CR>
:map <F3> :bp<CR>
:map <F4> :bn<CR>
":map <F5> :NERDTree projects<CR>
:map <F5> :Project<CR>
:map <F7> :e ++enc=cp1251<CR>
:map <F8> :e ++enc=utf-8 <CR>
let NERDTreeMapActivateNode='z'
"set wildmenu
"set wcm=<Tab>
"menu Encoding.windows-1251 :e ++enc=cp1251<CR>
"menu Encoding.utf-8 :e ++enc=utf-8 <CR>
"menu Encoding.koi8-r :e ++enc=koi8-r<CR>
"menu Encoding.ibm-866 :e ++enc=ibm866<CR>
"map <F8> :emenu Encoding.<TAB>
"set statusline+=%{&encoding},
"set statusline+=%{&fileformat}]
syntax on
filetype on
au BufNewFile,BufRead *.tmpl set filetype=php
set wfh
set wfw
nmap <silent> <F4>
\ :!ctags -f ./tags
\ --langmap="php:+.inc"
\ -h ".php.inc" -R --totals=yes
\ --tag-relative=yes --PHP-kinds=+cf-v .<CR>
set tags=./tags,tags
</code>
30 * * * * export DISPLAY=:0.0; /usr/bin/zenity {{{--}}}info {{{--}}}title="Information" {{{--}}}text="REST" &> /tmp/dbg; whoami >> /tmp/dbg; date >> /tmp/dbg
It's a "rest" dialog box alerting every 30 minutes
[[Алгоритмы сортировки и их сложности|http://profinet.org.ua/?p=42]]
<code class="brush:javascript">
var xmlhttp = getXmlHttp();
xmlhttp.open('GET', '/xhr/test.html', true);
xmlhttp.onreadystatechange = function()
{
if (xmlhttp.readyState == 4)
{
if(xmlhttp.status == 200)
{
alert(xmlhttp.responseText);
}
}
};
xmlhttp.send(null);
</code>
Синхронные запросы применяются только в крайнем случае, когда кровь из носу необходимо дождаться ответа сервера до продолжения скрипта. В 999 случаях из 1000 можно использовать асинхронные запросы. При этом общий алгоритм такой:
Делаем асинхронный запрос
Рисуем анимированную картинку или просто запись типа "Loading..."
В onreadystatechange при достижении состояния 4 убираем Loading и, в зависимости от status вызываем обработку ответа или ошибки.
Пример:
<code class="brush:javascript">
var xmlhttp = getXmlHttp();
xmlhttp.open("POST", "/someurl", true);
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState != 4) return;
clearTimeout(timeout); // очистить таймаут при наступлении readyState 4
if (xmlhttp.status == 200)
{
// Все ок
...
alert(xmlhttp.responseText);
...
}
else
{
handleError(xmlhttp.statusText); // вызвать обработчик ошибки с текстом ответа
}
}
xmlhttp.send("a=5&b=4");
// Таймаут 10 секунд
var timeout = setTimeout( function(){ xmlhttp.abort(); handleError("Time over") }, 10000);
function handleError(message)
{
// обработчик ошибки
...
alert("Ошибка: "+message)
...
}
</code>
Буду тут писать о возможностях PDT Eclipse Galileo.
1)Одна из самых удобных возможностей - наводишь на функцию (конструктор класса в данном случае), удерживая control нажимаешь на нее, тебя перекидывает в ее описание. Просто офигеть как удобно, не нужно лазить в ручную по файлам:
http://vbfs5q.blu.livefilestore.com/y1pTu-FLnCTpTUCDfekwNnOfRsZD-d2Vmitdeu_8kBnWcyYy88WnVsXu35wxHpwuwOB8Ea9vzGoDkZ6LO-kxxiPURg0G01Xi9Hm/Навел%20на%20функцию%2C%20нажал%20на%20control.JPG?psid=1
2) Просмотр описания функции прямо в среде => не нужно лазить и искать описание в мануале. Более того, можно самому писать к своему коду описание в формате http://phpdoc.org и просматривать его:
http://vbfs5q.blu.livefilestore.com/y1pizpcztXDJk4UJ_ZfXWF4ELLXKt1t7dePHxIMNwEwRl5TUzPSr-yoNyNYs_NvjQYfLl4x_aTbhMNH6XvHPwlu1foN8oS2Xb4z/Навел%20мышку%20на%20DbSession.JPG?psid=1
3) Работа с SVN прямо из среды:
http://vbfs5q.blu.livefilestore.com/y1pKAsWrft5ootcqM39sfBSAelBlzInN2op3bj1QpENgUZLGNLkeBU8OyPvGh0dkgK0slOP6yIvJWJdKO6aYJjpyeJEM5kxVdAl/Работа%20с%20SVN.JPG?psid=1
Просматриваем лог:
http://vbfs5q.blu.livefilestore.com/y1p1BSV0zBXmUtsHeXXM7wbrtzB6453APUXaIPHmuNh-qQD_0vo36Dxu1dwTnzliBlj2p7K-QiOZHHk3DbGJRo-HCsKilsh7Y7l/Просмотр%20svn-лога%20и%20просмотр%20внесенных%20изменений.JPG?psid=1
Видишь там справа иконка нажата, еще раз по ней нажимаешь и возвращаешься к коду =)
Видно модифицированный файл, тыкаешь по нему и нажимаешь сравнить:
http://vbfs5q.blu.livefilestore.com/y1pG6E2fBwh3xUQMlD-w85lijMl7GyOvCyZCVRgFSUx6gyYBhwKjP4vLRd42_bXdRq5QmpgqNptXX0ix-w-WVD1mZFm1HkXOBXH/Сравнение%20или%20просмотр%20внесенных%20в%20файл%20изменений.JPG?psid=1
4)Одновременная работа с несколькими проектами. Можно делать поиск по этим проектам. Например, ты помнишь, что в таком-то проекте уже была реализация чего-то похожего на то, что ты делаешь. Находишь, перекидываешь себе в проект этот файл, правишь его.
Удаление какого-то файла будет отражено в commit'е (просто в эксплорере тебе нужно нажимать по файлам правой кнопкой и вызывать TortoiseSVN->delete, иначе при коммите их удаление не зафиксируется, если ты там галочки не проставишь на ранее удаленных файлах)
http://vbfs5q.blu.livefilestore.com/y1pKVPmBcEpHBSwao3uzaqQN_oD3QDxRnaakZ2ig0uproQwyoOryHGPVduqORNUdTuHn5Mfaf0E3hPc58o_4pz93Eh0E6J8CqKD/Работа%20с%20несколькими%20проектами.JPG?psid=1
5) Редактирование в стиле VIM позволяет быстрее (когда научишься, сначала будет медленнее и неудобнее) редактировать текст, это можно легко отрубить нажав по иконке.
6) Можно прям запускать файлы. Например, если у тебя .dia привязаны к проге Dia, то при запуске файла, эклипс вызовет прогу Dia.
7) Встроенный дебагер.
8) Встроенный браузер.
9) Можно просматривать список задач. Помнишь, ты писал AppQueries: //СДЕЛАТЬ проверку существует ли удаляемый блок
Так если написать // TODO: СДЕЛАТЬ проверку существует ли удаляемый блок, то эта штука появится в списке задач, тыркаешь по ней дважды и бах тебя кидает куда нужно. Фактически, можно всякие мелкие задачки (типо этой, тобишь во время разработки конкретного сайта) прямо так и создавать в виде "тудух". Вот:
http://vbfs5q.blu.livefilestore.com/y1pQCz205PWw5O8NJCBDbf_dVQDQdCaGGVqoYMrm8F6kAbNp4kpvissS4LDIg7ThifR9ugjNvHCut4HCKv-KMd6BNTfSHNwHed7/таски.JPG?psid=1
а как сделал, пометил ее как complete. Сделал несколько задач и перед коммитом вызвал "delete completed tasks".
10) Проверка синтаксиса средой.
http://vbfs5q.blu.livefilestore.com/y1pCVO8pN3X-MPFL5aZTtwPlJK0rxLZRZRUsD1M13Iw458dkJ5gv0IiQKUdxuaQrbwpmzfSs5DzH_UG8WOsxCXarSIcqLHOwwLp/проверка%20синтаксиса.JPG?psid=1
11) Code Assist: если написать def выскочит менюшка с возможностью выбора всех доступных идентификаторов начинающихся на def. например:
default, define, define_syslog_variables и тд. когда что то из этого выбираешь, то тебе показывается описание этой штуки.
Чтобы активировать автоматическое выскакивание менюшки, нужно зайти в Window | Preferences | PHP | Editor | Code Assist and mark the 'Enable auto-activation' checkbox.
12) Написал define( , теперь чтобы узнать параметры, можно нажать Ctrl + Shift + Alt
13) Также можно написать if и вылезет менюшка где можно выбрать if и он вставит шаблон if'а по умолчанию эти шаблоны скобочку ставят на ту же строку где и условие, чтобы было как у нас, нужно:
Window | Preferences | PHP | Editor | Templates и делаешь import файла http://lindrid.no-ip.org/bt/viewattachment.php?attachmentid=21
14)как из эклипса смотреть документацию по пхп, а также видеть панельку со списком встроенных функций.
чтобы видеть панельку со списком встроенных функций : window -> show view -> php functions
чтобы увидеть документацию нужно : в php functions тыкнуть правой кнопкой по функции и нажать open manual
эклипс по умолчанию просматривает мануал взятый с php.net (может и не отобразить), чтобы он просматривал локальный мануал, нужно
http://www.eclipse.org/forums/index.php?t=msg&S=84abbf448a52421190fd3349fbfdf2d1&th=27573&goto=89542#msg_89701
http://stackoverflow.com/questions/118808/best-php-ide-for-linux-gnome
http://habrahabr.ru/qa/1941/
!!!Внимание
<code class="">
Информация о локали модифицируется во всем процессе, а не по каждому потоку отдельно.
Если вы используете PHP на многопоточном сервере, таком как IIS или Apache под Windows,
вы можете обнаружить неожиданные изменения в настройках локали во время выполнения скриптов,
никогда и не вызывавших setlocale(). Это происходит из-за того, что другие скрипты, запущенные
в параллельных потоках данного процесса, в то же самое время поменяли настройки локали для всего
процесса с помощью setlocale().
</code>
Чтобы узнать какая локаль используется нужно вызвать
<code class="brush:php">
echo setlocale(LC_ALL, null);
</code>
Построение проекта должно быть одной тривиальной операцией. Без выборки
многочисленных фрагментов из системы управления исходным кодом. Без
длинных серий невразумительных команд или контекстно-зависимых сценариев для
построения отдельных элементов. Без поиска дополнительных файлов в формате
JAR, XML и других артефактов, необходимых для вашей системы. Сначала вы
проверяете систему одной простой командой, а потом вводите другую простую
команду для ее построения.
<code class="">
svn get mySystem
cd mySystem
ant all
</code>
//Все// модульные тесты должны выполняться всего одной командой. В лучшем
случае все тесты запускаются одной кнопкой в IDE. В худшем случае одна
простая команда вводится в командной строке. Запуск всех тестов — настолько
важная и фундаментальная операция, что она должна быть быстрой, простой
и очевидной.
*Прежде всего выполнить [[Настройка XDebug]]
*Приведите настройки к следующему виду: [[PHP Servers|http://lindrid.opendrive.com/files/46132376_MOJ7j/PHP%20servers.JPG]], [[PHP Debug|http://lindrid.opendrive.com/files/46132380_kKVcf/PHP%20Debug.JPG]], [[XDebug Settings|http://lindrid.opendrive.com/files/46132383_DePu3/Xdebug%20settings.JPG]] и главное [[Web Browser|http://lindrid.opendrive.com/files/46132382_6efRA/Web%20browser.JPG]]
[Зависает XDebug], [XDebug hangs]
В кратком изложении загрузка компьютера на базе процессора Pentium происходит следующим образом. У каждого компьютера Pentium есть материнская
плата. На материнской плате находится программа, которая называется базовой системой ввода-вывода — ''BIOS (Basic Input Output System)''. BIOS содержит низкоуровневое программное обеспечение ввода-вывода, включая процедуры считывания состояния клавиатуры, вывода информации на экран и осуществления, ко всему прочему, дискового ввода-вывода. В наши дни эта программа хранится в энергонезависимой флэш-памяти с произвольным доступом, которая может быть обновлена операционной системой в случае обнаружения в BIOS различных ошибок.
При начальной загрузке компьютера BIOS начинает работать первой. Сначала она проверяет объем установленной на компьютере оперативной памяти и
наличие клавиатуры, а также установку и нормальную реакцию других основных устройств. Все начинается со сканирования шин ISA и PCI с целью определения всех подключенных к ним устройств. Некоторые из этих устройств унаследованы из прошлого (то есть разработаны еще до создания технологии [[plug and play]]). Они имеют фиксированные уровни прерываний и адреса ввода-вывода (возможно, установленные с помощью переключателей или перемычек на карте ввода-вывода, но не подлежащие изменению со стороны операционной системы). Эти устройства
регистрируются. Устройства, отвечающие стандарту [[plug and play]], также регистрируются. Если присутствующие устройства отличаются от тех, которые были зарегистрированы в системе при ее последней загрузке, то производится конфигурирование новых устройств.
Затем BIOS определяет устройство, с которого будет вестись загрузка, по очереди проверив устройства из списка, сохраненного в CMOS-памяти. Пользователь может внести в этот список изменения, войдя сразу после начальной загрузки в программу конфигурации BIOS. Обычно делается попытка загрузки с гибкого диска, если, конечно, он присутствует в системе. В случае неудачи идет запрос к приводу компакт-дисков и проверяется наличие в нем загрузочного диска. Если отсутствует и гибкий, и компакт-диск, система загружается с жесткого диска. С загрузочного устройства в память считывается первый сектор, а затем выполняется записанная в нем программа. Обычно эта программа проверяет таблицу разделов, которая находится в конце загрузочного сектора, чтобы определить, какой из разделов имеет статус активного. Затем из этого раздела считывается вторичный загрузчик, который в свою очередь считывает из активного раздела и запускает операционную систему.
После этого операционная система запрашивает BIOS, чтобы получить информацию о конфигурации компьютера. Для каждого устройства она проверяет
наличие драйвера. Если драйвер отсутствует, операционная система просит установить компакт-диск с драйвером (поставляемый производителем устройства).
Как только в ее распоряжении окажутся все драйверы устройств, операционная система загружает их в ядро. Затем она инициализирует свои таблицы, создает все необходимые ей фоновые процессы и запускает программу входа в систему или графический интерфейс пользователя.
!!Комментарии
*[[С1: Неуместная информация]]
*[[С2: Устаревший комментарий]]
*[[СЗ: Избыточный комментарий]]
*[[С4: Плохо написанный комментарий]]
*[[С5: Закомментированный код]]
!!Рабочая среда
*[[Е1: Построение состоит из нескольких этапов]]
*[[Е2: Тестирование состоит из нескольких этапов]]
!!Функции
*[[F1: Слишком много аргументов]]
*[[F2: Выходные аргументы]]
*[[F3: Флаги в аргументах]]
*[[F4: Мертвые функции]]
!!Разное
*[[G1: Несколько языков в одном исходном файле]]
*[[G2: Очевидное поведение не реализовано]]
*[[G3: Некорректное граничное поведение]]
*[[G4: Отключенные средства безопасности]]
*[[G5: Дублирование]]
*[[G6: Код на неверном уровне абстракции]]
*[[G7: Базовые классы, зависящие от производных]]
*[[G8: Слишком много информации]]
*[[G9: Мертвый код]]
*[[G10: Вертикальное разделение]]
*[[G11: Непоследовательность]]
*[[G12: Балласт]]
*[[G13: Искусственные привязки]]
*[[G14: Функциональная зависть]]
*[[G15: Аргументы-селекторы]]
*[[G16: Непонятные намерения]]
*[[G17: Неверное размещение]]
*[[G18: Неуместные статические методы]]
*[[G19: Используйте пояснительные переменные]]
*[[G20: Имена функций должны описывать выполняемую операцию]]
*[[G21: Понимание алгоритма]]
*[[G22: Преобразование логических зависимостей в физические]]
*[[G23: Используйте полиморфизм вместо if/Else или switch/Case]]
*[[G24: Соблюдайте стандартные конвенции]]
*[[G25: Заменяйте «волшебные числа» именованными константами]]
*[[G26: Будьте точны]]
*[[G27: Структура важнее конвенций]]
*[[G28: Инкапсулируйте условные конструкции]]
*[[G29: Избегайте отрицательных условий]]
*[[G30: Функции должны выполнять одну операцию]]
*[[G31: Скрытые временные привязки]]
*[[G32: Структура кода должна быть обоснована]]
*[[G33: Инкапсулируйте граничные условия]]
*[[G34: Функции должны быть написаны на одном уровне абстракции]]
*[[G35: Храните конфигурационные данные на высоких уровнях]]
*[[G36: Избегайте транзитивных обращений]]
!!Java
*[[J1: Используйте обобщенные директивы импорта]]
*[[J2: Не наследуйте от констант]]
*[[J3: Константы против перечислений]]
!!Имена
*[[N1: Используйте содержательные имена]]
*[[N2: Выбирайте имена на подходящем уровне абстракции]]
*[[N3: По возможности используйте стандартную номенклатуру]]
*[[N4: Недвусмысленные имена]]
*[[N5: Используйте длинные имена для длинных областей видимости]]
*[[N6: Избегайте кодирования]]
*[[N7: Имена должны описывать побочные эффекты]]
!!Тесты
*[[Т1: Нехватка тестов]]
*[[Т2: Используйте средства анализа покрытия кода]]
*[[ТЗ: Не пропускайте тривиальные тесты]]
*[[Т4: Отключенный тест как вопрос]]
*[[Т5: Тестируйте граничные условия]]
*[[Т6: Тщательно тестируйте код рядом с ошибками]]
Базы данных в MySQL соответствуют каталогам базовой файловой структуры, а таблицы - файлам. Это соответствие напрямую влияет на присваиваемые им имена, а также на зависимость этих имен от регистра букв - если в установленной ОС имена файлов и каталогов зависят от регистра, то и имена баз данных и таблиц также будут зависеть от него (как например в UNIX), в противном случае - нет (например, в Windows).
Имена столбцов и псевдонимы не зависят от регистра, однако в одном и том же SQL-операторе нельзя применять и строчные, и прописные символы. (''В Windows можно!'')
В качестве идентификаторов можно даже использовать зарезервированные слова и спец. символы всех видов.
Нельзя использовать символы:
*для БД:
<code class="brush:">
/,\ и .
</code>
*для таблицы:
<code class="brush:">
/ и .
</code>
Добавление поля в таблицу требует изменений в файлах include'а:
* GLOBAL_SITE_DATA
* MagickArray
Советы для начинающих изучать английский язык:
http://engramm.su/#%5B%5B%D0%A1%D0%BE%D0%B2%D0%B5%D1%82%D1%8B%20%D0%B4%D0%BB%D1%8F%20%D0%BD%D0%B0%D1%87%D0%B8%D0%BD%D0%B0%D1%8E%D1%89%D0%B8%D1%85%20%D0%B8%D0%B7%D1%83%D1%87%D0%B0%D1%82%D1%8C%20%D0%B0%D0%BD%D0%B3%D0%BB%D0%B8%D0%B9%D1%81%D0%BA%D0%B8%D0%B9%20%D1%8F%D0%B7%D1%8B%D0%BA%20(Hints%20for%20beginners%20on%20learning%20English)%5D%5D
http://dev-ua.livejournal.com/1973.html -- Среда разработки, в которой сохраняются знания.
http://dev-ua.livejournal.com/2284.html -- Как настроить интеграцию Subversion с внешней системой Bug Tracking.
http://tortoisesvn.net/docs/release/TortoiseSVN_en/tsvn-dug-bugtracker.html
Досовской утилитой ttfconv преобразовать "старые" .ttf шрифты: в cmd - ttfconv *.ttf
Ибо xp не работает с не-юникод шрифтами.
Композиция гибче наследования. (?)
Композиция представляет более слабую зависимость, чем наследование.
"При наследовании между классами устанавливаются гораздо более тесные связи, чем при композиции", глава 8, Лаптев, C++. Объектно-ориентированное программирование.
''Наследование'' - это связь классов типа __"is a"__, яблоко является(is a) фруктом, поэтому класс Apple наследуется от класса Fruit.
''Агрегация'' и ''композиция'' - это связь классов типа __"has a"__.
''Агрегация'' встречается, когда один класс является коллекцией или контейнером других. Причём по умолчанию, агрегацией называют ''агрегацию по ссылке'', то есть когда время существования содержащихся классов не зависит от времени существования содержащего их класса. Если контейнер будет уничтожен, то его содержимое — нет.
Графически агрегация представляется пустым ромбиком на блоке класса и линией, идущей от этого ромбика к содержащемуся классу.
''Композиция'' — более строгий вариант агрегации. Известна также как агрегация по значению.
Композиция имеет жёсткую зависимость времени существования экземпляров класса контейнера и экземпляров содержащихся классов. Если контейнер будет уничтожен, то всё его содержимое будет также уничтожено.
Графически представляется как и агрегация, но с закрашенным ромбиком.
''Различия между композицией и агрегацией''
Целое композиции должно иметь мультипликатор 0..1 или 1, что показывает, что часть является частью только одного целого. В агрегации же может быть любой мультипликатор.
Приведём наглядный пример. Комната является частью квартиры, следовательно здесь подходит композиция, потому что комната без квартиры существовать не может. А, например, мебель не является неотъемлемой частью квартиры, но в то же время, квартира содержит мебель, поэтому следует использовать агрегацию.
http://www.structuralist.narod.ru/it/internet/oop.htm
http://www.artima.com/designtechniques/compoinhP.html
http://www.codeproject.com/KB/cpp/oopuml.aspx
http://c2.com/cgi/wiki?CompositionInsteadOfInheritance
__Программы сгруппированы по модели интерфейса__.
diff, sed, find, awk?
''filters'' (ввод и вывод):
tr -- преобразует данные на вводе в данные на выводе
grep -- выбирает из потока ввода строки, соответствующие выражению, указанному в командной строке
sort -- сортирует входящие строки согласно критериям, заданным в ком.строке и отправляет на вывод результат
cat -- ?
less -- пейджер для удобного вывода большого количества текста
''cantrips'' (заклинания -- нет вывода и ввода?):
clear
rm
touch -- ?
''sources'' (источники -- только вывод):
ls
ps
who
''sinks'' (приемники -- только ввод):
lpr
mail в режиме отправки почты
''compiler-like interface'' (нет ввода,вывода. есть поток ошибок stderr; входные файлы подаются как аргументы командной строки)
cc
gcc
gzip, gunzip
<code class="brush:javascript">
function getXmlHttp()
{
var xmlhttp;
try
{
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e)
{
try
{
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (E)
{
xmlhttp = false;
}
}
if (!xmlhttp && typeof XMLHttpRequest != 'undefined')
{
xmlhttp = new XMLHttpRequest();
}
return xmlhttp;
}
</code>
http://www.mnot.net/cache_docs/
http://www.codenet.ru/webmast/php/caching.php
*[["Новые методологии программирования", Мартин Фаулер|http://www.maxkir.com/sd/newmethRUS.html]]
http://c2.com/cgi/wiki?ShellVsIde
http://c2.com/cgi/wiki?IdeInsteadOfEditor
http://c2.com/cgi/wiki?UnixIsAnIde
все инструменты внутри среды или набор лучших, но по отдельности?
''1)'' Прежде чем XDebug настраивать в IDE, настроим его отдельно и проверим в консольном клиенте debugclient. Буду рассказывать на собстенном примере. У меня стоит пакет XAMPP, в папке php находится клиент debugclient, в папке php/exe находится php_xdebug.dll - xdebug версии 2.1.0rc1. В php/php.ini прописываем следующее:
<code class="brush:">
[XDebug]
zend_extension = "G:\xampp\php\ext\php_xdebug.dll"
xdebug.idekey="ECLIPSE_DBGP"
xdebug.remote_enable=1
xdebug.remote_handler=dbgp
xdebug.remote_host=localhost
xdebug.remote_port=9000
xdebug.remote_log = "xdebug.log"
xdebug.trace_output_dir = "G:\xampp\tmp"
xdebug.profiler_enable = 1
xdebug.profiler_output_dir = "G:\xampp\tmp"
xdebug.profiler_output_name = "xdebug_profile.%R::%u"
</code>
Для PHP версии меньше, чем 5.3 нужно прописывать
<code class="brush:">
zend_extension_ts=...
</code>
''2)'' Проверяем работоспособность Xdebug. Перезапускаем Apache, запускаем debugclient, запускаем браузер по ссылке http://localhost/mt/?XDEBUG_SESSION_START=ECLIPSE_DBGP. Теперь в debugclient должен появится такой текст:
<code class="brush:">
Connect
<?xml version="1.0" encoding="iso-8859-1"?>
<init xmlns="urn:debugger_protocol_v1"
xmlns:xdebug="http://xdebug.org/dbgp/xdebug"
fileuri="file:///home/httpd/www.xdebug.org/html/docs/index.php"
language="PHP"
protocol_version="1.0"
appid="13202"
idekey="derick">
<engine version="2.0.0RC4-dev"><![CDATA[Xdebug]]></engine>
<author><![CDATA[Derick Rethans]]></author>
<url><![CDATA[http://xdebug.org]]></url>
<copyright><![CDATA[Copyright (c) 2002-2007 by Derick Rethans]]></copyright>
</init>
(cmd)
</code>
Более подробно о настройке Xdebug можно узнать [[тут|http://xdebug.org/docs/remote]]
''3)'' Итак Xdebug работает, теперь настроим Eclipse. У меня стоит Eclipse Helios. Заходим в Debug configuratuions, создаем новый "PHP Web Page" -- [[смотри картинку|http://lindrid.opendrive.com/files/45262790_m1Mxi/debug%20configurations.JPG]]. Я назвал эту страницу XDebug. Далее надо настроить PHP Web Server, нажимаем кнопкку configure, добавляем путь к папке, где находится отлаживаемый файл, [[типа как тут|http://lindrid.opendrive.com/files/45262792_BXfcW/server_path_mapping.JPG]]. В строке Path on Server должен стоять полный путь к папке, а в Local Path путь относительно проекта.
<code class="brush:php">
$txt = "Стремление стрЕмлЕнИе стреМЛение стремление";
echo preg_match("/стремление/i", $txt); //выводит 0
</code>
Т.е. preg_match не сработал и если проблема не в регулярном выражении, тогда проблема с кодировками.
!!!Решение проблемы
''1)'' [[Здесь|http://www.forum.dklab.ru/viewtopic.php?t=20995]] предлагается перед вызовом функции ставить вызов директивы
<code class="brush:php">
setlocale(LC_ALL, "russian", "ru_RU.CP1251");
</code>
__У данного решения есть побочный эффект__! В топике [[Директива setlocale]] можно об этом узнать.
''2)'' Использовать вместо символов коды символов:
<code class="brush:php">
$txt = "Стремление стрЕмлЕнИе стреМЛение стремление";
</code>
Допустим, $txt хранит данные в кодировке cp1251, тогда пользуясь [[таблицей ASCII-символов|http://www.fileformat.info/info/charset/windows-1251/list.htm]], выполним команду поиска по шаблону, используя ASCII-коды:
<code class="brush:php">
echo preg_match("/\xf1\xf2\xf0\xe5\xec\xeb\xe5\xed\xe8\xe5/", $txt); //выводит 1
</code>
Правда, в данном случае модификатор регистро-независимости i не сработает.
И поэтому нужно каждую букву проверять в таком духе [\xf1\xd1], т.е. [cC].
[[Как добавить красивые веб-шрифты с помощью google font api|http://ktonanovenkogo.ru/html/shrifty-dlya-sajta-kak-dobavit-krasivye-web-shrifty-google-font-api.html]]
(по книге databases demystified)
''First Normal Form: Eliminating Repeating Data''
Отношение находится в 1НФ если:
1. оно имеет первичный ключ (далее просто ключ),
2. значения всех его атрибутов атомарны.
''Second Normal Form: Eliminating Partial Dependencies''
Отношение находится во 2НФ если:
1. оно находится в 1НФ,
2. нет такого неключевого атрибута который зависит от части составного ключа
(если ключ не составной, то достаточно условия 1.)
''Third Normal Form: Eliminating Transitive Dependencies''
Отношение находится во 3НФ если:
1. оно находится в 2НФ,
2. нет такого неключевого атрибута который зависит от другого неключевого атрибута
Отношение находится в 3НФ тогда и только тогда, когда каждый неключевой атрибут зависит от ключа, только от всего ключа и ничего кроме ключа.
''Third normal form will cover well over 90 percent of the cases you will see in business information systems'', and it’s considered the “gold standard” in business systems.
Boyce-Codd normal form (BCNF) is a stronger version of third normal form. It addresses anomalies that occur when a non-key attribute is a determinant of an attribute that is part of the primary key (that is, when an attribute that is part of the primary key is functionally dependent on a non-key attribute).
http://job-interview.ru/questions/cpp
SHOW ENGINE INNODB STATUS
http://www.structuralist.narod.ru/it/internet/oop.htm
Undoing Changes
<code class="brush:">
$ sudo svn merge -r 33301:33273 svn://autonew.autovl.loc/drom/trunk/sales/
# verify that the change is removed
$ svn commit -m "Undoing change committed in r33301."
</code>
/\cupdate\|insert\|delete
- для яндекса - http://help.yandex.ru/webmaster/?id=1111316
- для гугла - http://www.google.com/support/webmasters/bin/answer.py?hl=ru&hlrm=en&answer=35769
- вики - http://ru.wikipedia.org/wiki/SEO
http://berdart.blogspot.com/2009/06/eclipse.html -- настройка eclipse для веб-программирования
http://fractalizer.wordpress.com/2007/11/02/installing-and-configuring-eclipse-pdt/ -- устанавливаем и настраиваем eclipse PDT
http://dmy999.com/article/29/using-eclipse-efficiently
http://bizness-women.ru/anxiety/page.php?id=1
http://vlad8.com/feldenkrais/lessons/kak_sidet_bez_napryazheniya/
http://ru-feldenkrais.livejournal.com/2455.html
сервис http://jsfiddle.net/
Профессионализм имеет две составляющие: знания и практический опыт. Вы должны узнать принципы, паттерны, приемы и эвристические правила, известные каждому профессионалу, а также «втереть» полученные знания в свои пальцы, глаза и внутренности усердной работой и практикой.
Я могу объяснить вам физику езды на велосипеде. В самом деле, классическая физика относительно прямолинейна. Сила тяжести, сила трения, ротационный момент, центр тяжести и т. д. — все это можно описать менее чем на одной странице уравнений. Этими формулами я докажу вам, что езда на велосипеде возможна, и предоставлю всю необходимую для этого информацию. Но когда вы впервые заберетесь на велосипед, вы все равно неизбежно упадете.
С программированием дело обстоит точно так же. Конечно, мы могли бы записать все «хорошие» принципы чистого кода, а потом доверить вам всю практическую работу (другими словами, позволить вам упасть, забравшись на велосипед), но какие бы из нас тогда были учителя?
Нет. В этой книге мы пойдем по другому пути.
Умение писать чистый код — тяжелая работа. Она не ограничивается знанием паттернов и принципов. Над кодом необходимо попотеть. Необходимо пытаться и терпеть неудачи. Необходимо наблюдать за тем, как другие пытаются и терпят неудачи. Необходимо видеть, как они спотыкаются и возвращаются к началу; как мучительно принимаются решения и какую цену приходится платить за неверный выбор.
Приготовьтесь основательно потрудиться во время чтения книги. Перед вами не «легкое чтиво», которое можно проглотить в самолете и перевернуть последнюю страницу перед посадкой. Книга заставит вас потрудиться, и потрудиться усердно. Какая работа вам предстоит? Вы будете читать код — много кода. И вам придется как следует подумать, что в этом коде правильно, а что нет. Вы будете наблюдать за тем, как мы разбираем эти модули, а потом собираем заново. Это потребует немало времени и усилий; но мы считаем, что результат того стоит.
В комментариях неуместно размещать информацию, которую удобнее хранить в других источниках: в системах управления исходным кодом, в системах
контроля версий и в других системах протоколирования. Например, история изменений только загромождает исходные файлы длинным историческим и малоинтересным текстом. Метаданные (авторы, дата последней модификации и т. д.) в общем случае также неуместны в комментариях. Комментарии должны быть зарезервированы для технической информации о коде и его архитектуре.
Комментарий, содержимое которого потеряло актуальность, считается устаревшим. Комментарии стареют довольно быстро. Не пишите комментарии, которые с течением времени устареют. Обнаружив устаревший комментарий, обновите его или избавьтесь от него как можно быстрее. Устаревшие комментарии часто «отрываются» от кода, который они когда-то описывали. Так в вашем коде появляются плавучие островки недостоверности и бесполезности.
Если уж вы беретесь за написание комментария, напишите его хорошо. Не жалейте времени и позаботьтесь о том, чтобы это был лучший комментарий, который вы способны создать. Тщательно выбирайте слова. Следите за правильностью орфографии и пунктуации. Не пишите сумбурно. Не объясняйте очевидное. Будьте лаконичны.
Фрагменты закомментированного кода выводят меня из себя. Кто знает, когда был написан этот код? Кто знает, есть от него какая-нибудь польза или нет? Однако никто не удаляет закомментированный код — все считают, что он понадобится кому-то другому.
Этот код только попусту занимает место, «загнивая» и утрачивая актуальность с каждым днем. В нем вызываются несуществующие функции. В нем
используются переменные, имена которых давно изменились. В нем соблюдаются устаревшие конвенции. Он загрязняет модуль, в котором он содержится, и отвлекает людей, которые пытаются его читать. Закомментированный код отвратителен.
Увидев закомментированный код, удалите его. Не беспокойтесь, система управления исходным кодом его не забудет. Если кому-то этот код действительно понадобится, то он сможет вернуться к предыдущей версии. Не позволяйте закомментированному коду портить вам жизнь.
Избыточным считается комментарий, описывающий то, что и так очевидно. Например:
<code class="brush:java">
i++; // Увеличение переменной i
</code>
Или другой пример — комментарий Javadoc, который содержит не больше (а вернее, меньше) полезной информации, чем простая сигнатура функции:
<code class="brush:java">
/**
* @param sell Request
* @return
* @throws ManagedComponentException
*/
public SellResponse beginSel1ItemCSel1 Request sellRequest) throws ManagedComponentException
</code>
Комментарии должны говорить то, что не может сказать сам код.
<code class="brush:javascript">
var xmlhttp = getXmlHttp();
xmlhttp.open('GET', '/xhr/test.html', false);
xmlhttp.send(null);
if(xmlhttp.status == 200)
{
alert(xmlhttp.responseText);
}
</code>
Собеседование проходит в 2 этапа - сначала устное, потом письменное.
''Общие вопросы''
#Ваш любимый ЯП?
#Какие структуры данных вы знаете?
#Участвовали ли в олимпиадах по программированию?
#Напишите как выглядит двунаправленный список (на C/С++ написать структуру данных)
#Как именно этот двунаправленный список хранится в памяти?
#Чем стек от очереди отличается?
#Есть отсортированный набор чисел, нужно найти число x. Каким алгоритмом воспользуетесь? -- Бинарным поиском.
#Какова сложность бинарного поиска? Просчитайте ее.
#А вообще оптимизировали ли когда-нибудь программы? Если на PHP, то как? А на C++?
#Использовали ООП? Расскажите основные принципы. Что такое инкапсуляция, наследование и полиморфизм?
#Решите логическую задачку: есть 8 шариков, один из них неправильной массы. За какое минимальное число взвешиваний это можно определить?
''C++''
#С указателями работали?
#Напишите какой-нибудь класс с конструктором и деструктором.
#Что такое виртуальная функция? Чем она отличается от невиртуальной? Как храниться виртуальная функция? (таблица виртуальных функций)
#Чем отличается оператор delete [] p; от delete p;
#Какие побитовые операции вы знаете?
#Есть десятичное число. Написать на C++ код, который выяснит сколько единиц в двоичном представлении данного числа.
#Есть класс у которого есть конструктор и деструктор (оба невиртуальных). От него наследуется другой класс. Какой косяк тут может быть?
#Каких типов бывают конструкторы?
#Использовали ли exception'ы? Объясните на примере, как они работают?
''Web-разработчик''
#Почему для веба выбрали именно PHP?
#Что нового появилось в 5ой версии PHP?
#Какие фрэймворки вы знаете?
#Насколько вы оцениваете свои знания CSS?
#Насколько вы оцениваете знания Javascript?
#Что такое CMS и какие вы знаете?
#Что такое сериализация?
#Какие веб серверы вы знаете?
#Зачем писали свой фрэймворк, если есть куча готовых?
#Что нового появилось в 5ой версии MySQL?
#Что такое транзакция?
#Что такое первичный ключ?
#Что такое внешний ключ?
#Что такое Jason?
#Опишите поэтапно что происходит, когда пользователь вводит в браузер адрес.
#Как называются шаблоны проектирования? Какие вы знаете?
#Расскажите про паттерн проектирования MVC
#Ваш средний бал в университете?
''Тестирование''
#Что такое тестирование по белому и по черному ящику?
#Назовите два основных параметра для сайта и БД, которые надо тестировать (безопасность и целостность данных).
#Какова средняя посещаемость вашего сайта?
#Тестировали свои сайты на нагрузку? (сайт выдержит до 1000 человек одновременно)
#Какие виды тестирования вы знаете?
#Вы выполняли визуальное автоматическое тестирование своих сайтов?
#Как именно, вручную, "нешарящая в программировании бабуля" поможет протестировать вам функцию регистрации на сайте?
#Что такое граничное тестирование?
http://www.metod-psv.ru/lechenie-bolezney/bol-v-spine/uprajneniya-bolit-spina.html
http://clb-vrn.ru/articles/archive1/ukreplyayushie_uprazhneniya.html
''===== Логическая схема БД =====''
(концептуальный уровень в архитектуре ANSI-SPARC)
- названия таблиц пишутся в единственном числе, разделять слова в названии символом "_"
"Table names should be descriptive and should reflect the name of the real-world entity they represent."
"The point here is to establish naming standards at the outset so that names are not assigned
in a haphazard manner, which only leads to confusion later. As a case in
point, Microsoft Access permits embedded spaces in table and column names,
which is counter to industry standards. Moreover, Microsoft Access, Sybase, and
Microsoft SQL Server allowmixed-case names, such asOrderDetails,whereas Oracle,
DB2, and others force all names to uppercase letters. Because table names such as
ORDERDETAILS are not very readable, the use of an underscore to separatewords
per industry standards is a much better choice."
''===== Физическая схема БД =====''
(внутренний уровень в архитектуре ANSI-SPARC)
*[[Автоматические приемочные тесты с Selenium|http://www.ibm.com/developerworks/ru/library/wa-selenium-ajax/]]
[[Процесс удаленной разработки|http://rsdn.ru/forum/job/2503641.all.aspx]]
[[Найм прогера-фрилансера|http://rsdn.ru/forum/job/3751733.all.aspx]]
Предположим есть корневая(текущая) директория с путем ''"."'' . Есть скрипт ''"./scripts/main.php"''.
В нем прописано:
<code class="brush:php">
include_once('config.php');
</code>
Подключаемый скрипт находится тут ''"./config.php"'', но его нет в директории ''"./scripts"''.
Теперь из командной строки, находясь в текущей директории, выполняем команду:
<code class="">
php ./scripts/main.php
</code>
И получаем ошибку:
<code class="">
Warning: include_once(config.php): failed to open stream: No such file or directory in ./scripts/main.php on line 2
</code>
Логично, но, читаем доку по пхп:
>Files are included based on the file path given or, if none is given, the include_path specified. If the file isn't found in the include_path, ''include() will finally check in'' the calling script's own directory and ''the current working directory before failing''.
Т.е. скрипт ''"./config.php"'' должен был быть найден, но увы. Можно config.php переместить в ''./scripts/config.php'', но если требуется, чтобы конфиг лежал выше уровнем (и в точке вызова) от main.php, тогда проблему можно решить изменением файла php.ini, нужно добавить в include_path текущий каталог ''"."'':
<code class="">
include_path = ".;C:\xampp\xampp\php\"
</code>
Кстати, другое, более очевидное, решение заменить строку кода в main.php на:
<code class="brush:php">
include_once('../config.php');
</code>
почему-то не срабатывает.