I'm trying to clone a mesh using GraphicsBuffer because its read/write option is false, and I can't change that. This is my current code:
public static bool Run(Mesh sourceMesh, out Mesh generatedMesh)
{
GraphicsBuffer sourceDataBuffer = sourceMesh.GetVertexBuffer(0);
GraphicsBuffer sourceIndexBuffer = sourceMesh.GetIndexBuffer();
var vertexCount = sourceDataBuffer.count;
var indexCount = sourceIndexBuffer.count;
byte[] sourceData = new byte[vertexCount * (sourceDataBuffer.stride / sizeof(byte))];
byte[] sourceIndex = new byte[(int)(indexCount * ((float)sourceIndexBuffer.stride / sizeof(byte)))];
sourceDataBuffer.GetData(sourceData);
sourceIndexBuffer.GetData(sourceIndex);
var attributes = sourceMesh.GetVertexAttributes();
generatedMesh = new Mesh();
generatedMesh.vertexBufferTarget |= GraphicsBuffer.Target.Raw;
generatedMesh.SetVertexBufferParams(vertexCount, attributes);
generatedMesh.SetVertexBufferData(sourceData, 0, 0, sourceData.Length);
generatedMesh.SetIndexBufferParams(indexCount, sourceMesh.indexFormat);
generatedMesh.SetIndexBufferData(sourceIndex, 0, 0, sourceIndex.Length);
generatedMesh.subMeshCount = sourceMesh.subMeshCount;
for (int i = 0; i < sourceMesh.subMeshCount; i++)
{
var subMeshDescriptor = sourceMesh.GetSubMesh(i);
generatedMesh.SetSubMesh(i, subMeshDescriptor);
}
sourceDataBuffer.Release();
sourceIndexBuffer.Release();
generatedMesh.RecalculateBounds();
return true; // No error
}
It works like a charm in my test project. But when I try to clone things in my main project, GetData(sourceData) and GetData(sourceIndex) both return arrays of 0s. What could be causing that? Could it be because of the read/write being disabled?
Edit: The problem only happens in bundles with non-readable meshes. I thought GraphicsBuffer should work with them, but it doesn't.
Related
My game lets the user modify the terrain at runtime, but now I need to save said terrain. I've tried to directly save the terrain's heightmap to a file, but this takes almost up to two minutes to write for this 513x513 heightmap.
What would be a good way to approach this? Is there any way to optimize the writing speed, or am I approaching this the wrong way?
public static void Save(string pathraw, TerrainData terrain)
{
//Get full directory to save to
System.IO.FileInfo path = new System.IO.FileInfo(Application.persistentDataPath + "/" + pathraw);
path.Directory.Create();
System.IO.File.Delete(path.FullName);
Debug.Log(path);
//Get the width and height of the heightmap, and the heights of the terrain
int w = terrain.heightmapWidth;
int h = terrain.heightmapHeight;
float[,] tData = terrain.GetHeights(0, 0, w, h);
//Write the heights of the terrain to a file
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
//Mathf.Round is to round up the floats to decrease file size, where something like 5.2362534 becomes 5.24
System.IO.File.AppendAllText(path.FullName, (Mathf.Round(tData[x, y] * 100) / 100) + ";");
}
}
}
As a sidenote, the Mathf.Round doesn't seem to influence the saving time too much, if at all.
You are making a lot of small individual File IO calls. File IO is always time consuming and expensive as it contains opening the file, writing to it, saving the file and closing the file.
Instead I would rather generate the complete string using e.g. a StringBuilder which is also more efficient than using something like
var someString
for(...)
{
someString += "xyz"
}
because the latter always allocates a new string.
Then use e.g. a FileStream and StringWriter.WriteAsync(string) for writing async.
Also rather use Path.Combine instead of directly concatenating string via /. Path.Combine automatically uses the correct connectors according to the OS it is used on.
And instead of FileInfo.Directory.Create rather use Directory.CreateDirectory which doesn't throw an exception if the directory already exists.
Something like
using System.IO;
...
public static void Save(string pathraw, TerrainData terrain)
{
//Get full directory to save to
var filePath = Path.Combine(Application.persistentDataPath, pathraw);
var path = new FileInfo(filePath);
Directory.CreateDirectory(path.DirectoryName);
// makes no sense to delete
// ... rather simply overwrite the file if exists
//File.Delete(path.FullName);
Debug.Log(path);
//Get the width and height of the heightmap, and the heights of the terrain
var w = terrain.heightmapWidth;
var h = terrain.heightmapHeight;
var tData = terrain.GetHeights(0, 0, w, h);
// put the string together
// StringBuilder is more efficient then using
// someString += "xyz" because latter always allocates a new string
var stringBuilder = new StringBuilder();
for (var y = 0; y < h; y++)
{
for (var x = 0; x < w; x++)
{
// also add the linebreak if needed
stringBuilder.Append(Mathf.Round(tData[x, y] * 100) / 100).Append(';').Append('\n');
}
}
using (var file = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.Write))
{
using (var streamWriter = new StreamWriter(file, Encoding.UTF8))
{
streamWriter.WriteAsync(stringBuilder.ToString());
}
}
}
You might want to specify how exactly the numbers shall be printed with a certain precision like e.g.
(Mathf.Round(tData[x, y] * 100) / 100).ToString("0.00000000");
I'm trying to create a game in Unity where each frame is rendered into a texture and then put together into a video using FFmpeg. The output created by FFmpeg should eventually be sent over the network to a client UI. However, I'm struggling mainly with the part where a frame is caught, and passed to an unsafe method as a byte array where it should be processed further by FFmpeg. The wrapper I'm using is FFmpeg.AutoGen.
The render to texture method:
private IEnumerator CaptureFrame()
{
yield return new WaitForEndOfFrame();
RenderTexture.active = rt;
frame.ReadPixels(rect, 0, 0);
frame.Apply();
bytes = frame.GetRawTextureData();
EncodeAndWrite(bytes, bytes.Length);
}
The unsafe encoding method so far:
private unsafe void EncodeAndWrite(byte[] bytes, int size)
{
GCHandle pinned = GCHandle.Alloc(bytes, GCHandleType.Pinned);
IntPtr address = pinned.AddrOfPinnedObject();
sbyte** inData = (sbyte**)address;
fixed(int* lineSize = new int[1])
{
lineSize[0] = 4 * textureWidth;
// Convert RGBA to YUV420P
ffmpeg.sws_scale(sws, inData, lineSize, 0, codecContext->width, inputFrame->extended_data, inputFrame->linesize);
}
inputFrame->pts = frameCounter++;
if(ffmpeg.avcodec_send_frame(codecContext, inputFrame) < 0)
throw new ApplicationException("Error sending a frame for encoding!");
pkt = new AVPacket();
fixed(AVPacket* packet = &pkt)
ffmpeg.av_init_packet(packet);
pkt.data = null;
pkt.size = 0;
pinned.Free();
...
}
sws_scale takes a sbyte** as the second parameter, therefore I'm trying to convert the input byte array to sbyte** by first pinning it with GCHandle and doing an explicit type conversion afterwards. I don't know if that's the correct way, though.
Moreover, the condition if(ffmpeg.avcodec_send_frame(codecContext, inputFrame) < 0) alwasy throws an ApplicationException, where I also really don't know why this happens. codecContext and inputFrame are my AVCodecContext and AVFrame objects, respectively, and the fields are defined as the following:
codecContext
codecContext = ffmpeg.avcodec_alloc_context3(codec);
codecContext->bit_rate = 400000;
codecContext->width = textureWidth;
codecContext->height = textureHeight;
AVRational timeBase = new AVRational();
timeBase.num = 1;
timeBase.den = (int)fps;
codecContext->time_base = timeBase;
videoAVStream->time_base = timeBase;
AVRational frameRate = new AVRational();
frameRate.num = (int)fps;
frameRate.den = 1;
codecContext->framerate = frameRate;
codecContext->gop_size = 10;
codecContext->max_b_frames = 1;
codecContext->pix_fmt = AVPixelFormat.AV_PIX_FMT_YUV420P;
inputFrame
inputFrame = ffmpeg.av_frame_alloc();
inputFrame->format = (int)codecContext->pix_fmt;
inputFrame->width = textureWidth;
inputFrame->height = textureHeight;
inputFrame->linesize[0] = inputFrame->width;
Any help in fixing the issue would be greatly appreciated :)
Check examples on here: https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples
Especially scaling_video.c. In FFmpeg scaling and pixel format conversion is same operation (keep the size parameters same for just pixel format conversion).
These examples very easy to follow. Give it a try.
I think your casting is incorrect sbyte** inData = (sbyte**)address;
because address is IntPtr object, so the correct casting probably should be
sbyte* pinData = (sbyte *)address.ToPointer(); sbyte** ppInData = &pinData;
I open with epplus an excel file.
After reading some data, I would like to close the package:
pck.Stream.Close()
pck.Dispose()
Unfortunatelly the excel file is still blocked. I need to close the whole application to get the excel file unlocked.
I have googled, but found nothing useful except the above.
How are you opening the file? The following creates, saves, reopens, prints, and finally deletes all withing the same thread without issue. I can even set a breakpoint anywhere and delete the file. Reading the file this way should not lock the file since it is pulled into memory:
[TestMethod]
public void OpenReopenPrintDeleteTest()
{
//Create some data
var existingFile = new FileInfo(#"c:\temp\temp.xlsx");
if (existingFile.Exists)
existingFile.Delete();
using (var package = new ExcelPackage(existingFile))
{
var workbook = package.Workbook;
workbook.Worksheets.Add("newsheet");
package.Save();
}
using (var package = new ExcelPackage(existingFile))
{
var workbook = package.Workbook;
var worksheet = workbook.Worksheets.First();
//The data
worksheet.Cells["A1"].Value = "Col1";
worksheet.Cells["A2"].Value = "sdf";
worksheet.Cells["A3"].Value = "ghgh";
worksheet.Cells["B1"].Value = "Col2";
worksheet.Cells["B2"].Value = "Group B";
worksheet.Cells["B3"].Value = "Group A";
worksheet.Cells["C1"].Value = "Col3";
worksheet.Cells["C2"].Value = 634.5;
worksheet.Cells["C3"].Value = 274.5;
worksheet.Cells["D1"].Value = "Col4";
worksheet.Cells["D2"].Value = 996440;
worksheet.Cells["D3"].Value = 185780;
package.Save();
}
//Reopen the file
using (var package = new ExcelPackage(existingFile))
{
var workBook = package.Workbook;
if (workBook != null)
{
if (workBook.Worksheets.Count > 0)
{
var currentWorksheet = workBook.Worksheets.First();
var lastrow = currentWorksheet.Dimension.End.Row;
var lastcol = currentWorksheet.Dimension.End.Column;
for (var i = 1; i <= lastrow; i++)
for (var j = 1; j <= lastcol; j++)
Console.WriteLine(currentWorksheet.Cells[i, j].Value);
}
}
}
//Delete the file
existingFile.Delete();
}
I was having the same problem... But I found the solution:
During the "SaveAs" method, I was creating a FileStream that was not being disposed.
Before:
ExcelPackage excel_package = new ExcelPackage(new MemoryStream());
//...
//Do something here
//...
excel_package.SaveAs(new FileStream("filename.xlsx", FileMode.Create));
excel_package.Dispose();
After:
ExcelPackage excel_package = new ExcelPackage(new MemoryStream());
//...
//Do something here
//...
var file_stream = new FileStream("filename.xlsx", FileMode.Create);
excel_package.SaveAs(file_stream);
file_stream.Dispose();
excel_package.Dispose();
Note that the Memory Stream opened during the ExcelPackage declaration was not explicitly disposed, because the last command "excel_package.Dispose()" already does this internally.
Hope it help.
c# excel epplus
I would like to implement my own OPC DA client (versions 2.02, 2.05a, 3.00) from scratch but without using any third-party. Also I would like to make use of OPCEnum.exe service to get a list of installed OPC servers. Is there any kind of document that explains detailed and step by step the process to implement an OPC client?
I have a c# implementation but actually it's hard to fit it in here. I'll try to summarize the steps required.
Mostly you need to have OpcRcw.Comn.dll and OpcRcw.Da.dll from the OPC Core Components Redistributable package downloable for free from Opcfoundation.org. Once installed, the files are located in C:\Windows\assembly\GAC_MSIL. Create a reference in your project.
About coding, this is what you should do (there are three objects you want to implement, Server, Group and Item):
Let's start with server:
Type typeofOPCserver = Type.GetTypeFromProgID(serverName, computerName, true);
m_opcServer = (IOPCServer)Activator.CreateInstance(typeofOPCserver);
m_opcCommon = (IOPCCommon)m_opcServer;
IConnectionPointContainer icpc = (IConnectionPointContainer)m_opcServer;
Guid sinkGUID = typeof(IOPCShutdown).GUID;
icpc.FindConnectionPoint(ref sinkGUID, out m_OPCCP);
m_OPCCP.Advise(this, out m_cookie_CP);
I've striped a LOT of checking to fit it in here, take it as a sample...
Then you need a method on server to add groups:
// Parameter as following:
// [in] active, so do OnDataChange callback
// [in] Request this Update Rate from Server
// [in] Client Handle, not necessary in this sample
// [in] No time interval to system UTC time
// [in] No Deadband, so all data changes are reported
// [in] Server uses english language to for text values
// [out] Server handle to identify this group in later calls
// [out] The answer from Server to the requested Update Rate
// [in] requested interface type of the group object
// [out] pointer to the requested interface
m_opcServer.AddGroup(m_groupName, Convert.ToInt32(m_isActive), m_reqUpdateRate, m_clientHandle, pTimeBias, pDeadband, m_LocaleID, out m_serverHandle, out m_revUpdateRate, ref iid, out objGroup);
// Get our reference from the created group
m_OPCGroupStateMgt = (IOPCGroupStateMgt)objGroup;
Finally you need to create items:
m_OPCItem = (IOPCItemMgt)m_OPCGroupStateMgt;
m_OPCItem.AddItems(itemList.Length, GetAllItemDefs(itemList), out ppResults, out ppErrors);
Where itemlist is an array of OPCITEMDEF[]. I build the above using GetAllItemDefs from a structure of mine.
private static OPCITEMDEF[] GetAllItemDefs(params OpcItem[] opcItemList)
{
OPCITEMDEF[] opcItemDefs = new OPCITEMDEF[opcItemList.Length];
for (int i = 0; i < opcItemList.Length; i++)
{
OpcItem opcItem = opcItemList[i];
opcItemDefs[i].szAccessPath = "";
opcItemDefs[i].bActive = Convert.ToInt32(opcItem.IsActive);
opcItemDefs[i].vtRequestedDataType = Convert.ToInt16(opcItem.ItemType, CultureInfo.InvariantCulture);
opcItemDefs[i].dwBlobSize = 0;
opcItemDefs[i].pBlob = IntPtr.Zero;
opcItemDefs[i].hClient = opcItem.ClientHandle;
opcItemDefs[i].szItemID = opcItem.Id;
}
return opcItemDefs;
}
Finally, about enumerating Servers, I use this two functions:
/// <summary>
/// Enumerates hosts that may be accessed for server discovery.
/// </summary>
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
public string[] EnumerateHosts()
{
IntPtr pInfo;
int entriesRead = 0;
int totalEntries = 0;
int result = NetServerEnum(
IntPtr.Zero,
LEVEL_SERVER_INFO_100,
out pInfo,
MAX_PREFERRED_LENGTH,
out entriesRead,
out totalEntries,
SV_TYPE_WORKSTATION | SV_TYPE_SERVER,
IntPtr.Zero,
IntPtr.Zero);
if (result != 0)
throw new ApplicationException("NetApi Error = " + String.Format("0x{0,0:X}", result));
string[] computers = new string[entriesRead];
IntPtr pos = pInfo;
for (int ii = 0; ii < entriesRead; ii++)
{
SERVER_INFO_100 info = (SERVER_INFO_100)Marshal.PtrToStructure(pos, typeof(SERVER_INFO_100));
computers[ii] = info.sv100_name;
pos = (IntPtr)(pos.ToInt32() + Marshal.SizeOf(typeof(SERVER_INFO_100)));
}
NetApiBufferFree(pInfo);
return computers;
}
/// <summary>
/// Returns a list of servers that support the specified specification on the specified host.
/// </summary>
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
public string[] GetAvailableServers(Specification specification)
{
lock (this)
{
// connect to the server.
ArrayList servers = new ArrayList();
MULTI_QI[] results = new MULTI_QI[1];
GCHandle hIID = GCHandle.Alloc(IID_IUnknown, GCHandleType.Pinned);
results[0].iid = hIID.AddrOfPinnedObject();
results[0].pItf = null;
results[0].hr = 0;
try
{
// create an instance.
Guid srvid = CLSID;
CoCreateInstanceEx(srvid, null, CLSCTX.CLSCTX_LOCAL_SERVER, IntPtr.Zero, 1, results);
m_server = (IOPCServerList2)results[0].pItf;
// convert the interface version to a guid.
Guid catid = new Guid(specification.ID);
// get list of servers in the specified specification.
IOPCEnumGUID enumerator = null;
m_server.EnumClassesOfCategories(1, new Guid[] { catid }, 0, null, out enumerator);
// read clsids.
Guid[] clsids = ReadClasses(enumerator);
// release enumerator
if (enumerator != null && enumerator.GetType().IsCOMObject)
Marshal.ReleaseComObject(enumerator);
// fetch class descriptions.
foreach (Guid clsid in clsids)
{
try
{
string url = CreateUrl(specification, clsid);
servers.Add(url);
}
catch (Exception) { }
}
}
catch
{
}
finally
{
if (hIID.IsAllocated) hIID.Free();
if (m_server != null && m_server.GetType().IsCOMObject)
Marshal.ReleaseComObject(m_server);
}
return (string[])servers.ToArray(typeof(string));
}
}
I know I've striped a lot but maybe it can still help you ;)
Please mark the answer as correct if you think I've been clear ;)
Kind Regards,
D.
I'm using Firefox + searchbastard addon to do a multi-search on shopping search engines.The pages are part of a frame. This works just fine for all sites I tried so far except for shopmania.com.
If I use noscript to forbid scripts from the shopmania domain name then everything stays in place but the part of the website elements become nonresponsive. I know there is an option in Firefox to force links that open in a new window to open in a new tab. Is there something similar to prevent websites from popping out of frame? Maybe a Firefox addon that blocks these requests?
Or at least can someone please tell me what is causing only this website to act like this?
EDIT: What tool can i use to pause firefox OR javascript and stepthrough code like in c++ ? I tried a javascript debugger and firebug. They don't help but i'm probably not using them right..
EDIT2: I tried this greasemonkey script : https://userscripts.org/scripts/show/92424. It does not work so i guess it isn't because of 'target' attribute
This is wrong. I'm guessing you're using a plugin to capture and override the output some site gives you. I'm pretty sure this violates their ToS and it's not a very nice thing to do in general.
JavaScript is not designed to allow this kind of meddling. It's patchy at best.
If you want to use the data from a website, to aggregate or display in some manner, use their public API. If they don't have a public API they probably don't want you to use their service in such a manner.
The solution : I took the script from Stop execution of Javascript function (client side) or tweak it and modified it to search for the tag that has in it top.location = location and then appended a new script with the if (top != self) {top.location = location;} line commented . Being a js total newbie i don't know if it's the most elegant choice but it soves the prob. Special thanks to Tim Fountain.
I will leave this open just in case someone else will suggest a better solution, for my and others's education. Again thanks for the help.
Below is the code:
// ==UserScript==
// #name _Replace evil Javascript
// #run-at document-start
// ==/UserScript==
/****** New "init" function that we will use
instead of the old, bad "init" function.
*/
function init () {
/* //changing stuff around here
var newParagraph = document.createElement ('p');
newParagraph.textContent = "I was added by the new, good init() function!";
document.body.appendChild (newParagraph); */
<!--//--><![CDATA[//><!--
document.getElementsByTagName("html")[0].className+=" js "+(navigator.userAgent.toLowerCase().indexOf("webkit")>=0?"webkit":navigator.userAgent.toLowerCase().indexOf("opera")>=0?"opera":"");
for(i in css3_tags="abbr|header|footer".split("|")){document.createElement(css3_tags[i]);}
var PATH = "http://www.shopmania.com";
var PATH_STATIC = "http://im4.shopmania.org";
var PATH_SELF = "http://www.shopmania.com/";
var RETURN = "http%3A%2F%2Fwww.shopmania.com%2F";
var DOMAIN_BASE = "shopmania.com";
var SUBDOMAINS_FORCE_FILES_JS = "aff.remote,biz.remote,my.remote,cp.remote,cp.register_quick,cp.account_details,partner.remote,site.recommend,site.remote,site.feedback,site.report_problem,site.report,site.cropper";
var URL_REWRITE_MAPPING_JS = "cmd,section,do,option|feed,mode,option|forgot,section|info,page|login,section|logout,section|new_password,section,code|settings,section|shopping,param_main,param_sec|site,store_str_key|register,section|unsubscribe,section|agentie,store_str_key,id|brand,manuf_str_key|brands,letter|build,type,param_main,param_sec|compare,online|confirm,section|edit,section|deal,deal|dictionary,online|home,section|link_accounts,section|profile,user|reactivate,section|searches,letter|signup,section|rs_agent,store_str_key|rs_list,param_main,param_sec|rs_view,ad|agents,state|complex_list,param_main|complex_view,complex|list,cat|ad,a|map,option|my_ads,section|my_alerts,section";
var SVR_SITE_ID = "us";
var CONTEXT = "c5b27de70340c97a94092a43bd34b2b8";
var link_close = "Close";
var txt_loading = "Loading...";
var form_is_submitted = 0;
var search_is_focused = 0;
// Overlay object
var OL;
var DB;
var iframe_cnt = "";
// Facebook post to user's Wall action
var FACEBOOK_WALL_FEED_SIGNUP = "";
var SITENAME = "ShopMania";
//if (top != self) {top.location = location;} // SIT!
var comps = new Array(); comps['all'] = 0;var comps_cat_titles = new Array(); var views = new Array(); views['auto'] = 0; views['prod'] = 0; views['realestate'] = 0; views['classifieds'] = 0; views['all'] = 0; var search = new Array(); search['all'] = 0; search['prod'] = 0;
var favs = new Array(); favs['all'] = 0; favs['prod'] = 0; favs['store'] = 0; favs['manuf'] = 0; favs['other'] = 0; favs['realestate'] = 0; favs['auto'] = 0;
function addCss(c){var b=document.getElementsByTagName("head")[0];var a=document.createElement("style");a.setAttribute("type","text/css");if(a.styleSheet){a.styleSheet.cssText=c}else{a.appendChild(document.createTextNode(c))}b.appendChild(a)};
addCss(".lzl {visibility: hidden;}");
var RecaptchaOptions = { theme : 'clean' };
//--><!]]>
}
/*--- Check for bad scripts to intercept and specify any actions to take.
*/
checkForBadJavascripts ( [
[false, /top.location = location/, function () {addJS_Node (init);} ]
] );
function checkForBadJavascripts (controlArray) {
/*--- Note that this is a self-initializing function. The controlArray
parameter is only active for the FIRST call. After that, it is an
event listener.
The control array row is defines like so:
[bSearchSrcAttr, identifyingRegex, callbackFunction]
Where:
bSearchSrcAttr True to search the SRC attribute of a script tag
false to search the TEXT content of a script tag.
identifyingRegex A valid regular expression that should be unique
to that particular script tag.
callbackFunction An optional function to execute when the script is
found. Use null if not needed.
*/
if ( ! controlArray.length) return null;
checkForBadJavascripts = function (zEvent) {
for (var J = controlArray.length - 1; J >= 0; --J) {
var bSearchSrcAttr = controlArray[J][0];
var identifyingRegex = controlArray[J][1];
if (bSearchSrcAttr) {
if (identifyingRegex.test (zEvent.target.src) ) {
stopBadJavascript (J);
return false;
}
}
else {
if (identifyingRegex.test (zEvent.target.textContent) ) {
stopBadJavascript (J);
return false;
}
}
}
function stopBadJavascript (controlIndex) {
zEvent.stopPropagation ();
zEvent.preventDefault ();
var callbackFunction = controlArray[J][2];
if (typeof callbackFunction == "function")
callbackFunction ();
//--- Remove the node just to clear clutter from Firebug inspection.
zEvent.target.parentNode.removeChild (zEvent.target);
//--- Script is intercepted, remove it from the list.
controlArray.splice (J, 1);
if ( ! controlArray.length) {
//--- All done, remove the listener.
window.removeEventListener (
'beforescriptexecute', checkForBadJavascripts, true
);
}
}
}
/*--- Use the "beforescriptexecute" event to monitor scipts as they are loaded.
See https://developer.mozilla.org/en/DOM/element.onbeforescriptexecute
Note that it does not work on acripts that are dynamically created.
*/
window.addEventListener ('beforescriptexecute', checkForBadJavascripts, true);
return checkForBadJavascripts;
}
function addJS_Node (text, s_URL, funcToRun) {
var D = document;
var scriptNode = D.createElement ('script');
scriptNode.type = "text/javascript";
if (text) scriptNode.textContent = text;
if (s_URL) scriptNode.src = s_URL;
if (funcToRun) scriptNode.textContent = '(' + funcToRun.toString() + ')()';
var targ = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
//--- Don't error check here. if DOM not available, should throw error.
targ.appendChild (scriptNode);
}
there are some escaping issues with the cdata part in the code.So SO does not allow me to post the code.
EDIT: fixed