現在 CPU 廠商大打 "多核心" 的口號, 讓大家都知道多核心的好處了, 不過每個評論的人也都會補上一句, "要有專為多核心設計的軟體才能發恢效能". 到底什麼叫作專為多核設計的軟體?
簡單的說, 就是程式不能再以單一流程來思考, 必需引用平行處理的概念. 就像工作分派一樣, 有十個人幫你做事, 一定比一個人好. 不過這也是考驗你分派及管理的能力. 做的不好, 可能工作還是都只有一個人在做, 另外九個在偷懶, 更糟的是還造成溝通的問題, 比只有一個人還糟.
在程式設計的領域裡, 實現平行處理, 它的困難有幾個:
早期的 Unix 提供的 fork( ) 就是個典型的例子, 呼叫後有兩份一模一樣的程式一起執行, 你要自己想辦法分出誰是誰, 然後讓它們各自執行. 兩個程式怎麼溝通? 只能靠 IPC (Inter-Process Communication), 方式不外呼開 socket 或是 share memory, 互相等待要靠 signal( )... 總之你大概會有 80% 以上的精力是在解決這些問題, 不是在解決你要處理的問題.
後來較新的 OS 紛紛引入了 thread 的關念, 解決了部份 IPC 問題, 其它的還是一樣困難. 直到 Java 出來, 寫 multi-threading 程式就簡單多了. 到了 .net 3.5, 又更進一步, 就是我這篇要講的主題.
在 MSDN Magazine 看到一篇文章, 覺的還不錯, 就貼上來跟大家分享一下心得. 原文在此:
為多重核心電腦最佳化 Managed 程式碼
http://msdn.microsoft.com/msdnmag/issues/07/10/Futures/default.aspx?loc=zx
細節我就不多討論了, 那篇文章裡面都說明的非常清楚, 很棒的一篇文章. 主要的重點是, 即使用了 Java / .NET 這樣的開發環境, 你仍然要面對許多 threading 的問題, 像是 thread 如何開始, 如何結束, 這個 thread 如何去通知另一個 thread 完成的問題. 但是大部份的情況下, 我只不過是有一堆工作, 想要丟給電腦處理, 最好就是所有可用 CPU 通通叫來幫忙...
這篇文章介紹的 TPL ( Task Parallel Library ) 很巧妙的利用 delegate, 把整套 Library 包裝的像一個 for loop 一樣簡單. 基本的觀念就是, 只要用它提供的類似 for loop 寫法改寫你的程式, 原本 loop 裡要執行 100 次的工作, 現在就會自動的分配到你所有的 CPU 一同執行. 聽起來很酷, 真的用起來也是如此. 我簡單貼一下內文兩段 sample code:
1: // 一般的迴圈
2: for (int i = 0; i < 10; i++) {
3: a[ i ] = a[ i ] * a[ i ];
4: }
5:
6: // 改用 TPL 的迴圈
7: Parallel.For(0, 100, delegate(int i) {
8: a[ i ] = a[ i ] * a[ i ];
9: });
上面兩段 code 做的事情都一樣, 就是把陣列 a 的內容, 每一筆都算平方, 再寫回來. 差別在於第一段程式會在同一個 thread 裡依序完成每一筆計算, 而第二個例子則利用 anonymous delegate, 讓 code 看起來像迴圈, 實際上每圈都是執行一次 delegate. 而這個 delegate 會自動透過 task manager 分配到合適的 thread 執行. 它跟 thread pool 有許多不同, 文章內有一些說明... 如此一來就能享用的到多核心 CPU 的好處, 你的每一個核心都會被充份的利用.
其實這樣的作法, 並不是 Microsoft 或是 .NET 特有的創新, 早在更重視效能的 C/C++ 就有了. Intel 就大力的支持了這個 open source project: http://threadingbuildingblocks.org/ 裡面提供了大量的 C++ template, 也是用類似的方式替 C++ 加入了平行處理的支援.
ZD Net 上面有一系列的 video (http://www.zdnet.com.tw/white_board/intel/video-8.htm), 講的相當不錯, 我很認同裡面的幾個觀念, 主講人 James Reinders 提到, 平行處理你第一個應該要想到的是函式庫, 或是編譯器等等, 讓你的程式不自覺就能自動享用到平行處理的好處, 第二是用這類 library, 針對各種的 loop 去調整, 讓他能適用平行處理, 最後也是最不建議的作法, 才是大家常聽到的 multi-threading. 原因很簡單, threading 必需是你設計軟體架構就考慮進去的東西, 相對之下開發不易, 效能也不見得比較好, 更糟的是你可能會設計用 4 threads 來處理問題, 結果就是你的程式在超過四核的系統上就沒有明顯的效能增強了.
昨天晚上仔細的看完這幾篇文章, 果然科技的進步真是神速啊, 過去寫到翻掉的 Multi-Process 程式, 如今一個 For Loop 就解決掉, 沒走過這一段的人應該不能體會吧. 不過也因為這樣, 更能體會這些技術的價值在那裡. TPL 真的是個好東西, 強力推薦大家學一學!!
--
文中題到的 TPL 已經有 Tech Preview 可以下載了. 感謝 Unicorn 提供資訊.
http://www.microsoft.com/downloads/details.aspx?FamilyID=e848dc1d-5be3-4941-8705-024bc7f180ba&DisplayLang=en
--
這篇是寫了貼在別的地方, 當然自己的 blog 也要貼一份... [H]
效能問題, 就跟我自己寫的小工具一起講好了. 話說之前 Microsoft 提供了一個很讚的小工具: Resize Pictures Power Toys, 功能超簡單, 大概就是檔案總管把圖檔選一選, 按右鍵選 "Resize pictures" 就好了:
選了之後就有簡單的對話視窗:
很簡單吧, 我個人非常愛用, 而且轉出來的效果也不差, 看起來 JPEG quality 大約有 80% ~ 90% 吧... 無耐 windows xp 裡有幾個跟 image 相關的 power toys, 到了 vista 通通不能用. 看來應該都是碰到 GDI+ 要轉換到 WPF 的陣痛期吧, 這幾個小工具還真是讓我繼續撐在 XP 的主要理由之一...
扯遠了, 所以我的目標就是寫個類似的小工具, 讓我簡單的做批次縮圖就好. 有了上一篇的基礎, 要寫這種 tools 實在是沒什麼挑戰, 大概會寫 winform 的拉兩下就可以收工了...
不過, 大話說太早. 先貼一下成品的畫面, 後面說明比較清楚:
要做的東西很簡單. 選好一堆圖按右鍵選 resize pictures 後就跳這畫面, 按 Resize 就開始跑. 用的是前一篇弄好的 library. 結果碰到的障礙還不少. 雖然可以跑, 但是看了就很礙眼...
(1) 的問題其實沒這麼嚴重. Microsoft HD Photo 有一個 feature, 就是大檔放在網路上, 你也能夠很快的透過網路看到小圖. 有點類似早期漸進式的 jpeg 那樣. 不過看起來 codec 的設計更好一點. 實驗的結果是, Full Size .CR2 (4000x3000) 存成同大小的 JPEG 檔需要 60sec, 而存成 800x600 只要 5 sec. 但是拿對照組 .JPG (4000x3000) -> .JPG (800x600), 差距又沒這麼大. 因此推測起來, 應該在 decode 階段就已經針對這樣的需求設計過了.
剩下的問題我試了好幾種方法, 目標都擺在如何安排這堆 thread 在合適的時間做合適的工作. canon codec 就不適合同時丟好幾個 thread 下去跑, 因為完全沒用, 反而拉長每個 .CR2 從開始到輸出的時間. jpeg 的部份就很適合, 因為時間短, 多核的好處也可以藉著多 thread 用的到. 另外 canon codec 因為限制較多, 我需要它以較高的 priority, 並且要在第一時間就開始跑, 才不會拖慢整個轉檔的處理時間... 理想的 task 安排狀況應該要像這樣:
最後找到一個我比較滿意的解, 就是另外寫一個合用的 ThreadPool... @_@
其實我是很不想做重新發明輪子這件事, 不過除此之外實在沒什麼好方法. 所幸 .net 下要自己弄出個 thread pool 也不難. 這一切都要感謝當年在 yam, 當時研發部的一位主管, 交大的學長, 現在跑到 Microsoft 去了, 我們都叫他 "旺旺" .. 他技術能力只能用 "神" 來形容... 當時他在公司內開了門課, 真是印像深刻. 就用 java 示範了如何寫 ThreadPool ... 寫起來還真沒幾行... 扣掉一堆 import (相當於 c# 的 using) 等宣告之類的 code, 整個功能 "完整" 的 thread pool 大概只有一百行左右的 code... 而且 thread 動態 create 跟回收等功能一樣不少... threads 之間同步問題也沒漏掉..
我歸納了一下我需要的 ThreadPool 到底要什麼功能, 而內建的到底缺什麼... 要怎麼做就很清楚了... 要解決上面的問題, 我大概需要這樣的 thread pool 來支援我的想法:
這些剛好都是我需要, 但是 .NET 內建的 thread pool 做不到的需求. 因此自己寫了個簡單的 SimpleThreadPool .. 介面規格就儘量比照內建的 ThreadPool (因為 code 已經寫好不想改太多 [:P]). 用起來像這樣:
1: private static void SimpleThreadPoolTest()
2: {
3: SimpleThreadPool stp1 = new SimpleThreadPool(2, System.Threading.ThreadPriority.BelowNormal);
4: SimpleThreadPool stp2 = new SimpleThreadPool(1, System.Threading.ThreadPriority.Lowest);
5:
6: stp1.StartPool();
7: stp2.StartPool();
8:
9: for (int count = 0; count < 10; count++)
10: {
11: stp1.QueueWorkItem(
12: new WaitCallback(ShowMessage),
13: string.Format("STP1[{0}]", count));
14: stp2.QueueWorkItem(
15: new WaitCallback(ShowMessage),
16: string.Format("STP2[{0}]", count));
17:
18: Thread.Sleep(13);
19: }
20:
21:
22: Console.WriteLine("wait stop");
23: stp1.EndPool();
24: stp2.EndPool();
25: }
26:
27:
28: private static void ShowMessage(object state)
29: {
30: Console.WriteLine("ThreadID: {0}, state: {1}", Thread.CurrentThread.ManagedThreadId, state);
31: Thread.Sleep((new Random()).Next(1000));
32: }
嗯, 功力跟旺旺比差了一點, 不過也是一百出頭行就搞定這個 ThreadPool ... [:D], 接下來就是火力展示了... 因為介面跟內建的 ThreadPool 幾乎一樣. 就簡單測一下 125 JPEG + 20 G9 RAW + 2 G2 RAW files 一起做轉檔時的 CPU 使用率記錄...
圖一. 用內建的 ThreadPool, 110 sec ( UI 回應正常, 進度列也會跑. 不過礙於 CPU loading 關係, ImageBox 的圖都沒出來)
圖二. 改用我自己寫的 SimpleThreadPool, 90 sec. 因為調整過 priority, 每張圖轉完 ImageBox 都會立即顯示出來.
第一張圖, 所有的 job 都依序執行, 簡單的 jpeg 都擠在前段, 那段 cpu 100% 就是這樣來的. 後面就都是 canon decoder 在跑, cpu 大約都維持在 50% 左右, 直到跑完為止.
而第二張圖, jpeg / canon 都強迫同時一起執行. 而 canon 的 priority 略高於 jpeg. 因此排程的策略是優先執行較慢的 canon decoder, 而剩餘的 cpu 運算能力就拿來處理 jpeg 的部份. 因為 cpu 使用率的統計圖下的面積 (積分) 就是總共需要的運算量. 看的出來維持在 100% 的部份越短, 則總體完成的時間就會拉長... 後面自定的 thread pool 的作法, 不論在 UI 回應, 跟整體處理的時間都比較好. 看來適度的調整 thread 數量, 跟 thread priority 還是很有用的. 不過題外話, thread 再怎麼用, 效果還是不如 lib or compiler level 做的平行處理效果來的好. ZD Net 上有一系列 intel 提供的 video, 講的還不錯. Microsoft 也替 .NET 開發了一套 Library (download), 只要調整一點語法, 就可以把 loop 內的運算轉成平行運算, 這種效果遠比用 thread pool 來的聰明 & 有效. 不過還在 community preview 就暫時不考慮採用了.
總算, 搞定了 thread pool, 也搞定了 metadata, 幾個主要的障礙都排除了. 兩個要開發的工具也完成了一個 ( image resizer ), 剩下的歸檔程式就剩下納入 video encoder 的部份也就大功告成了. 有力氣的話會再寫一篇吧, 敬請期待 [:D]
託 Canon G9 的福, 這一個月來的空閒時間都在研究 Windows Presentation Foundation 裡的 Image Codec 相關事項. 幹嘛買個相機還這麼辛苦? 因為原本算計好的計劃, 就差這一環啊... 雖然老早就有換機的計劃, 為什麼龜了那麼久 G9 一出來就跑去買? 除了之前講了一堆相機本身的考量之外, 剩下的關鍵因素是 RAW support. 因為:
RAW support 在我看來是必要的. 照片可不能等十年後再搭時光機回來照, 而現有的 JPEG 又已經是老古董的規格了, 未來是一定會有取而代之的新規格. 會是什麼我不曉得, 不過留著 RAW 準沒錯. 只要 Canon 沒倒, 未來一定有辦法把 RAW 轉成新的通用格式, 而不用經過 JPEG 的折損...
未來看起來很美好, 不過當 G9 入手後, 事情沒有想像的順利, 有了 WPF + Codec, 我自己必需寫些小程式來簡化未來例行的相片歸檔動作. Codec 只要去 Canon 下載就有, WPF 則是新東西, 得自己先研究一番... 搭配 WPF, Microsoft 也推出了新的圖型檔格式: HD Photo. 它的一堆好處我就不多說了, Microsoft 網站多的是. 我在意的是, HD Photo 提供的新功能, 包括廣大的色域等, 也會對應的在 image codec 裡提供. 因此如果 RAW file 本身就包含這些資訊的話, 透過 codec 讀出來就不會有資訊的折損, 存成 JPEG 就沒有這些好處了.
實作第一步, 當然是先研究 WPF 關於 Image 物件的基本處理. 嗯, 果然是跟之前的 GDI / GDI+ 不一樣. 感覺起來 GDI 典型 application 就是像 "小畫家" 這類的 AP, 而 WPF 典型的 application 就是像 flash 這類的, 裡面的物件已經變成圖型來源, 套用各種 transform, 層層處理套上去後得到的結果才是你看到的東西, 大概就類似 photoshop 的 layer 那樣的東西.
講了那麼多, 其實我也只是要用到 codec 來讀取 canon raw file, 把圖檔縮成我要的像素, 存成指定的 jpeg 檔而以... 我就以這個例子貼一段 sample code
1: BitmapDecoder source = BitmapDecoder.Create(
2: new Uri(@"C:\IMG_0001.CR2"),
3: BitmapCreateOptions.DelayCreation,
4: BitmapCacheOption.None);
5: JpegBitmapEncoder target = new JpegBitmapEncoder();
6:
7: target.Frames.Add(BitmapFrame.Create(
8: new TransformedBitmap(source.Frames[0], new ScaleTransform(0.3, 0.3)),
9: source.Frames[0].Thumbnail,
10: metadata,
11: null));
12: target.QualityLevel = 80;
13:
14: FileStream trgs = File.OpenWrite(@"C:\IMG_0001.JPG");
15: target.Save(trgs);
16: trgs.Close();
而過去也寫過 GDI+ 版本的, 那個我就不貼了. 老實說 code 也不會太多, 不過寫起來就覺的是兩種不同層次的思考邏輯. 也隨著這次機會花了點心思研究 System.Windows.Media.Imaging 裡的東西, 就開始想把舊的程式都翻一翻.. 包括了之前的歸檔程式, 及另一個批次縮圖的工具. 後面有機會再貼.
圖檔基本內容處理掉之後, 接下來就是 exif. 我很在意這些圖檔隱藏的資訊, 也不知道為什麼, 哈哈. 上面的 code 轉完是沒有半點 EXIF 的, 沒轉過來感覺就像少了什麼... 無奈在處理 metadata 時又碰到了一些小 trouble ...
花了一些時間搞定了 metadata, 不過又碰到不同檔案格式之間的 metadata 轉換問題. WPF 的 Image Codec 已經把 metadata 的讀寫方式給 "抽像化" 了, 所有圖檔的 metadata 都用一樣的方式讀寫. 它採用的是類似 xpath 的 metadata query 來指明目標是那個 metadata, 然後再用 GetQuery( ) 來讀值, 或是用 SetQuery( ) 把值寫進去. 現在碰到的問題是 Canon Raw 的 query 跟 JPEG exif 用的對應不起來. 我也不知道怎麼解, google 找幾個 sample 對照著比一比, 摸黑試了幾種對應方式, 竟然看起來還好像猜中了, 就不管先用下去. 我簡單的把整理的對照表貼一下...
/ifd/{ushort=256} --> /app1/ifd/exif/{ushort=256}
/ifd/{ushort=257} --> /app1/ifd/exif/{ushort=257}
...
請不要問我這是啥意思, 我真的也搞不懂, 看了 w3c 一些 spec, 真是天書... 大概只知道 metadata 有幾種規範, exif, xmp, ifd 等等. 而 ushort=256 大概就是指整個 block 裡, 第 256 bytes 位置的 ushort 的值就是這筆資料存放的地方等等. 我是拿幾張照片轉換後對照著看, 看起來對就將就著用了. 最後是用程式跑了一份看起來可用的對照表, 存成 xml 檔, 丟在自己寫的 library project 裡, 當作 embedded resource. 供未來轉檔的動作時拿出來用. library 包裝好之後用起來像這樣:
1: ImageUtil.SaveToJPEG(
2: @"c:\IMG_0001.CR2",
3: @"c:\IMG_0001.JPG",
4: 800,
5: 800,
6: 75);
弄到現在, 總算把最基本的動作: 轉檔 (含 exif) 給搞定了. 總算有足夠的資訊把 library 給弄好. 不過馬上就碰到第二個大問題... "效能". 這部份就留著下一篇吧.
搞了好幾天, 終於理出點頭緒了. 自從 Canon 推出 1.2 版的 codec 之後, G9 拍的 .CR2 支援問題總算是往前跨了一大步, 至少在 XP / Vista 下可以直接顯示 .CR2 了. 接下來就是如何讓它自動化等等問題.
WPF寫起來很簡單, 效率的問題就先擺一邊了 (很理想的預期 canon 會在未來版本會改善... 咳...), 不過 EXIF 的問題還真是令我傷透腦筋... 前前後後碰到幾個問題, 加上官方文件很多細節沒有提供, 讓我碰了不少釘子... Orz. 先整理一下碰過的釘子有那些 (現在當然拔乾淨了才有心情打這篇.. 哈哈 [H]), 先列一下問題最大的 metadata:
另外其它跟 metadata 無關的問題也有幾個:
這些鳥問題都在 MSDN 找不到直接的答案, 只好埋頭苦TRY了. 好消息是主要問題都解的差不多了. 先簡單列一下 solution, 後續的等我 [歸檔程式] 改版完成後再來專欄報導..
前言大概就先打到這裡, 沒啥內容, 都只是預告片而以, 被它折磨了兩個禮拜, 當然要先貼一篇發洩一下. 剩下的工作就單純多了, code 改到一個段落我就會繼續寫後續幾篇. 這次會包括兩個 project, 一個是 Image Resizer, 另一個就是之前好幾篇都在講的歸檔工具. 敬請期待!
替舊文章打一下廣告... [H]
周日下午趁小孩都回外婆家, 花了點時間把家裡該裝的裝一裝, 該接的接一接, 還有一點空檔, 就把拖了很久的網站升級處理一下... 原本的版本是 CS 2007 (3.0), 中間推出了 3.0 SP1, SP2, SP3 beta 都跳過去沒理它, 這次 2007.1 (3.1) 出來手又癢了起來...
過程就沒啥好說了, 失敗了好幾次, 最後決定整個重裝... 抓了 2007.1 的官方版本, 把舊的 db 配上它的 upgrade script 執行完後掛上去, 基本功能就會動了, 最後再把 ~/blogs, ~/photos, ~/forums 等有 storage 的目錄搬過去, 再把我自己客制過的 themes 重改一次 ( my god, themes 裡的檔案全都調過, 原本的 themes 蓋過來可以跑, 不過心裡毛毛的 )... 總算大功告成. 事後順手也把同一台 server 另外兩套 CS 也順便升級了一下.
老實說我也沒很注意 2007.1 到底改了啥, 就貼一下吧, 搞不好大家之前碰到的鳥問題已經被解決掉了... 正好鴕鳥混過去, 哈哈 [H]
以下是 CS2007.1 release notes:
Below are changes available in Community Server 2007.1
-------------------------------------------------------------------
Enhancements
- Updated caching framework, performance updates, added locking support for several of the application-wide collections
- SQL performance updates and best-practices updates
- Added CreateEditWeblogPostForm, DeleteWeblogPostForm, and associated sub-form controls from CS2008 to support creating/editing/deleting blog posts in the front UI using Chameleon.
- Updated styles on the TinyMCE wrapper's content to provide some default spacing and use a larger default font size.
- Updated TagCloud controls to support disabling the "no tags" message and "no related tags" messages. Updated all existing themes (except for tag browsing pages) to not render the "no tags" message.
- Updated SqlProviders to resolve LINQ SortOrder namespace ambiguity
- Added support for sorting and paging LinkCategory and Link objects in the API and via Chameleon.
- Added toggle button for enabling/disable application tokens
- Tweaked app tokens list a little bit to show the time for the last used column
- Added a new AdPlacementOptions to WrappedRepeater, AlternatingSeperator - places an ad after every other item starting after the first.
- Updated TinyMCE to use the latest wrapper.
- Updated the email job only retrieves as many messages as it will send from the email queue (prevent large queues from causing timeouts)
- Updated notifications and mass emails to enforce the check on a user's "Enable Email" global setting and "Allow Site to contact me" setting
- Updated email notifications to check the enable thread tracking for post replies
- Updated mass emailing to take place on a background thread
- Updated Telligent.Registration.dll to address an issue where the add-ons could get stuck if they start before SQL on a reboot/startup
- Updated Telligent.MailGateway.Common.dll to address issues with XML cleaning in the core library and downloading only as many messages as needed from the email queue
- Updated user date formats so that month-day-year is 6-1-2007 instead of 06-01-2007
- Updated Windows Live Writer support by implementing keywords for custom tags and removing excerpt support since it gets confused with text-mode.
- The error messages were updated so that the actual error message is displayed more prominently.
- Removed the AutoDeleteThreshold setting from the forum control panel since it is not implemented.
- Updated stylesheet to not underline the group expand/collapse toggle button.
- Updated version of CookComputing XML-RPC.NET library to use new .NET 2.0 optimized verison
- Updated list of default Weblog Ping URLS (removed Blo.gs and PubSub.com, added PingOMatic.com)
- Implemented TruncationEllipsisTemplate on the ObjectDataBase control to support custom markup/controls being used in the TruncationEllipsis
- Enabled adding new categories inline through Windows Live Writer
- Added rsd.ashx and wlwmanifest.ashx in web project, and added namespaces (Added support for RSD and WLWManifest).
- Updated MetaBlog to support excerpts, read-more, and post names
- Updated blog truncation to use readmore links
- Updated Metablog to default to the users current blog
- Added auto discovery for the current blogs metablog path
- Added basic site and blog theme
- Updated email templates for forum and forum thread emails to remove the background grey color.
- CSContext.User is only overridden with TokenUser when told via AllowTokenRequests(bool requirePrivateToken)
- Added rendering of news to the "Traveler" blog theme's sidebar.
- Added support for TemporaryUserTokens that expire after 3 hours
- Change password now uses a temporary user token
- Added support for disabling exception logging. It is disabled by default.
- Moved keep-alive code from global.js into the KeepAlive control. Updated Editor control to *always* render a KeepAlive control. Deleted web/utility/keepalive.aspx
- Added a few performance improvements to ThreadQueryBuilder classes: Only joining to cs_threads if we really have to, Adding a cs_Sections.ApplicationType filter back in
- Changed the expiration date from 30 days to 7
- Exception logging now occurs in background cache tasks
Bug Fixes:
- FileSystemWatcher pathing fix
- Request/Response encoding fix
- You can now resize the editor horizontally in the content editor modals
- You can now override an editor option without specifying type on the control
- You are no longer redirected to login when browsing a site that has forums at root while you are anonymous.
- Updated inline text editor to not overlap its popup container
- Updated Telligent.Glow.Modal to use frameborder='0' instead of frameborder='no'
- Create/Edit Blog Page Validation fixed so that appkey cannot be blank
- Added code and note bbcode and updated existing processing order of scrubbing modules
- Enabled checking of the user's Enable Email setting on a wide variety of message types
- Corrected all references in Chameleon controls to OpenWindow function in global.js to use a direct call to window.open.
- Updated Forum BreadCrumb control to use the current rewritten URL name instead of the rendered URL to determine the current page
- Updated EntryThumbnail control to render the file extension in the alt attribute.
- Updated EntryThumbnail control to render with an Image control and default to 0 border width and no alignment.
- The parent post cache is now expired properly when creating a new post in a thread. This allows a reply to post to always display in a thread after it is created.
- Create edit blog post now maintains state better
- Added validation for the user's email address to Users.Create
- Fix for Gallery search results from searchbarrel linking to image not to gallery page
- Removed the ability to rename or delete the anonymous user
- Fixed issue where GalleryService.Update failed to set the PostID, which caused it to always fail.
- Updated cs_User_Delete sproc to update author/post ID's as well as names
- Disabled subforums no longer require user to login in parent forum
- Fixed theme cache name so that the cache key is correct. Previously theme configuration were never getting retrieved from cache correctly.
- Changed create user page so that validation occurs when fields change as oppose to whenever a key was pressed.
- Group RSS Feed no longer causes Exception
- Pager added to the default aggregateentrylist control for the file gallery
- Clicking the Advanced Search link from a search results page now populates the advanced search options form for the lean and green theme as well as default
- Corrected QuickReply link to only refresh the page if false (and not undefined OR false) is passed as the callback parameter.
- Fixed EXIF page to show the full list of tags.
- Fixed photo post edit so it decodes the subject before populating the text box in the CP (to prevent double encoding)
- Fixed all auto-syndication registration to not re-html-encode section names.
- Fixed issue with users in the Member Administrators role not being able to change user passwords
- Fixed spelling error in the API... renamed User.EnableAvtar to User.EnableAvatar
- Updated default and leanandgreen themes to hide "view all users" link when "Display Member List" is set to "No" in the Control Panel.
- The SaveExtendedUserData call was moved into the event handler for the submit button, before the first call to sub-forms.
- You can now delete a tag that is disabled.
- User Points can now display without Post Points.
- Fixed issue with order of permissions not being handled properly
- Control Panel Report page title now shows correct text
- Fix for linking over to Shutterfly showing 0x0 as the picture's size.
- Fix for null reference on private messages from CS 2.x that were to users that were later deleted
- Fixed ForumSqlProvider to save sticky info on edited posts
- Corrected issue resulting in multiple encoding of the AvatarUrl property.
- Updated edit user form in the control panel to always show the user's Username in the "Alias" field.
- Updated blog admin control panel to properly decode the blog name.
- Corrected FireFox rendering issue on user+avatar lists in the default and lean and green themes.
- Fixed issue where Weblog XML-RPC pings do not get sent in some scenarios.
- Corrected misplaced </div> tag issue in PoisonIvy, Gertrude, Luxinterior, and Photos blog themes causing nested comments.
- Changed Roller Blog add-feed sproc to set Last Modified to current time - interval, so that the feed gets pulled the next time the job runs after the feed is added.
- Corrected rendering issue in the Control Panel in FireFox prior to JavaScript loading
- Updated the HTMLScrubber regex to use slightly different syntax which prevents infinite loop issue in FireFox.
- Corrected invalid anchor tag in blog themes.
- Added check for cs_Posts.IsIndexed in all SearchBarrel-generated queries.
- Fixed failed check to see if the user was anonymous within MailGateway
- Fixed how SPAM blocker counts links
- Fixed an issue with a missing resource label
- Updated CallbackPager to always render the PagedContent contents.
- Fixed issue with deserialization returning as successful when the output object is null
- Blog pages now show up in the tag post list if set to be aggregated, and the aggregate options are visible when creating a new page.
- Corrected thread view count to register one view per thread per rendered page regardless of the number of posts displayed on the page.
- Removed script to enable/disable "Join" button on the registration form in the default and lean-and-green themes to prevent issues with auto-complete.
- Updated TinyMCE wrapper to set the document_base_url TinyMCE option to the parent window's URL when the editor is opened in a Modal.
- Fixed notifications of message being flagged for moderation by MailGateway being queued with SettingsID of 0
- License usage colors are now cleared after uploading a license.
- Updated truncation ellipsis markup to render within the content wrapper (link) on ObjectDataBase control.
- Corrected next/previous thread links to direct to the thread's URL.
- Updated UserAvatarSubForm to set the remote avatar URL (if available) when an avatar is uploaded.
- cs_system_GenerateWeblogYearMonthDayList and cs_vw_weblog_PostByYearMonth now has some sql included to attempt to build the roll-up tables.
- Fixed regression from Bug Fix #1391 with AppKey being a required field on the blog creation page
- Selecting 'Hide Topics I've Read' in the forum filtered thread control now keeps the unread announcements visible on the first page
- You can now delete a forum post without it sending email
- Tweaks to cs_weblog_Post_Create and cs_weblog_Post_Update to ensure that UserTime was never NULL.
- Corrected potential XSS issue in User RSS Feeds
- Added EnsureHtmlEncoded calls to loaded TemporaryRssFeeds and TemporaryRssFeedItems content.
- Updated UserSearchForm to redirect to the rewritable URL instead of directly into the current theme.
- Pager fixed in the manage photo comments page so that you can page past the first 2 pages.
- Membership.GetRoles result set creation updated to ensure roles and role icons are re-populated after cache expiration
- Updated default Regex validation patterns for user names and passwords and ensured that these patterns always match the entire string when set.
- Updated sql to only change the regex pattern if the pattern [a-zA-Z]+[^\<\>]* was in the UsernameRegex before
- Added tabindex="-1" to all TinyMCE buttons to prevent tab-stops when navigating into the editor using the keyboard.
- Added validation of RSS feed URLs and external avatar URLs to ensure they are HTTP-based.
- Updated SearchBarrel to require Read access from applications supporting Read permissions.
- Adding ']' to a post no longer causes the post to pass the duplicate post check.
- Disabling post emoticons now hides the emoticon radio button list from the Forum options tab
- File Gallery comment URL's now work correctly, displaying the entry they belong to
- Corrected issue preventing section filters from being saved.
- Updated the form adapter to only update the form's action attribute when the page's URL has been rewritten by CS to ensure compatibility with external, non-rewritten pages within CS.
- Updated the thread queries used by blog and file gallery search indexing to specify IgnorePermissions=true so that all blogs and file gallery posts are indexed.
- Corrected infinite redirect issue when an invalid character exists in the URL.
- Changed const string cacheKey = "UserLookupTable" to include SettingsID
- Photo Gallery now supports HTMLEncoding a submitted user name field
- Added ApplicationName to the UserRoleNames cache key
- Corrected page height issue in IE when using tabbed panes.