..and of course 2 minutes after the post I found the simple solution.
Needed to copy: $HFS\houdini\pdg\plugins\PDGDeadline to: C:\DeadlineRepository10\plugins
rtfm
Found 68 posts.
Search results Show results as topic list.
PDG/TOPs » Deadline scheduler and AWS
- fabriciochamon
- 68 posts
- Online
PDG/TOPs » Deadline scheduler and AWS
- fabriciochamon
- 68 posts
- Online
Hi there.
I'm trying to send a pdg graph to run on aws (deadline scheduler). Have been reading docs and the farm troubleshooting page, but still didn't find a way to make it work.
Background info:
- Amazon instances runs Houdini 18.0.416 (linux)
- Submitter machine runs Houdini 18.0.416 (windows)
- .hip is a simple scene with a box and a topnet(2 workitems). they get rendered with a ropfetch node (v-ray)
- I can render normally using the deadline's own rop node (not pdg), so cloud instances installation look good.
When running the scheduler in the “regular” mode (not submitting graph as job), it errors on the instances (socket.gaierror) as they are not able to reach the submitter machine to report back pdg progress, makes sense.
When submitting graph as job, it errors on the instances with the following message:
2020-04-24 08:20:50: >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
2020-04-24 08:20:50: Exception Details
2020-04-24 08:20:50: RenderPluginException – Failed after four attempts to copy “PDGDeadline.param”. Please make sure that the file exists in the plugin directory.
2020-04-24 08:20:50: RenderPluginException.Cause: JobError (2)
2020-04-24 08:20:50: RenderPluginException.Level: Major (1)
2020-04-24 08:20:50: RenderPluginException.HasSlaveLog: True
2020-04-24 08:20:50: RenderPluginException.SlaveLogFileName: /var/log/Thinkbox/Deadline10/deadlineslave_renderthread_0-ip-10-128-22-17-0000.log
2020-04-24 08:20:50: Exception.Data: ( )
2020-04-24 08:20:50: Exception.TargetSite: Deadline.Slaves.Messaging.PluginResponseMemento d(Deadline.Net.DeadlineMessage, System.Threading.CancellationToken)
2020-04-24 08:20:50: Exception.Source: deadline
2020-04-24 08:20:50: Exception.HResult: -2146233088
2020-04-24 08:20:50: Exception.StackTrace:
2020-04-24 08:20:50: at Deadline.Plugins.SandboxedPlugin.d(DeadlineMessage bbm, CancellationToken bbn
2020-04-24 08:20:50: at Deadline.Plugins.SandboxedPlugin.SyncFilesForJob(Job job, Boolean cleanup, String& message, CancellationToken cancellationToken
2020-04-24 08:20:50: at Deadline.Slaves.SlaveRenderThread.e(String ady, Job adz, CancellationToken aea
2020-04-24 08:20:50: at Deadline.Slaves.SlaveRenderThread.b(TaskLogWriter adu, CancellationToken adv)
2020-04-24 08:20:50: <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
…I'm not sure this PDGDeadline.param issue is something related to Houdini or Deadline itself, but I have been stressing out many combinations, also tried setting PDG_USE_PDGNET=1 on my houdini.env file, but I always get this error.
any suggestions ?
thank you.
I'm trying to send a pdg graph to run on aws (deadline scheduler). Have been reading docs and the farm troubleshooting page, but still didn't find a way to make it work.
Background info:
- Amazon instances runs Houdini 18.0.416 (linux)
- Submitter machine runs Houdini 18.0.416 (windows)
- .hip is a simple scene with a box and a topnet(2 workitems). they get rendered with a ropfetch node (v-ray)
- I can render normally using the deadline's own rop node (not pdg), so cloud instances installation look good.
When running the scheduler in the “regular” mode (not submitting graph as job), it errors on the instances (socket.gaierror) as they are not able to reach the submitter machine to report back pdg progress, makes sense.
When submitting graph as job, it errors on the instances with the following message:
2020-04-24 08:20:50: >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
2020-04-24 08:20:50: Exception Details
2020-04-24 08:20:50: RenderPluginException – Failed after four attempts to copy “PDGDeadline.param”. Please make sure that the file exists in the plugin directory.
2020-04-24 08:20:50: RenderPluginException.Cause: JobError (2)
2020-04-24 08:20:50: RenderPluginException.Level: Major (1)
2020-04-24 08:20:50: RenderPluginException.HasSlaveLog: True
2020-04-24 08:20:50: RenderPluginException.SlaveLogFileName: /var/log/Thinkbox/Deadline10/deadlineslave_renderthread_0-ip-10-128-22-17-0000.log
2020-04-24 08:20:50: Exception.Data: ( )
2020-04-24 08:20:50: Exception.TargetSite: Deadline.Slaves.Messaging.PluginResponseMemento d(Deadline.Net.DeadlineMessage, System.Threading.CancellationToken)
2020-04-24 08:20:50: Exception.Source: deadline
2020-04-24 08:20:50: Exception.HResult: -2146233088
2020-04-24 08:20:50: Exception.StackTrace:
2020-04-24 08:20:50: at Deadline.Plugins.SandboxedPlugin.d(DeadlineMessage bbm, CancellationToken bbn
2020-04-24 08:20:50: at Deadline.Plugins.SandboxedPlugin.SyncFilesForJob(Job job, Boolean cleanup, String& message, CancellationToken cancellationToken
2020-04-24 08:20:50: at Deadline.Slaves.SlaveRenderThread.e(String ady, Job adz, CancellationToken aea
2020-04-24 08:20:50: at Deadline.Slaves.SlaveRenderThread.b(TaskLogWriter adu, CancellationToken adv)
2020-04-24 08:20:50: <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
…I'm not sure this PDGDeadline.param issue is something related to Houdini or Deadline itself, but I have been stressing out many combinations, also tried setting PDG_USE_PDGNET=1 on my houdini.env file, but I always get this error.
any suggestions ?
thank you.
PDG/TOPs » python processor vs. python script - execution time
- fabriciochamon
- 68 posts
- Online
Eric, that's exactly what I need. thanks a lot for the reply!
A small correction: the argument name is “inProcess” and not “isInProcess”, for anybody else reading it.
thanks.
A small correction: the argument name is “inProcess” and not “isInProcess”, for anybody else reading it.
thanks.
PDG/TOPs » python processor vs. python script - execution time
- fabriciochamon
- 68 posts
- Online
Hi,
I have this big material node, that was saved with “node.asCode()”.
Now I want to reload it using “execfile()”.
The file has 60k+ lines, but it loads in a matter of seconds when I run inside a python script node. On the other hand it takes about 2 minutes to load when running inside a python processor node.
For this specific task I'd need to run inside a processor, since the file loading is tied to workitem generation.
What could be the cause for such a big difference in the execution times ?
thanks.
I have this big material node, that was saved with “node.asCode()”.
Now I want to reload it using “execfile()”.
The file has 60k+ lines, but it loads in a matter of seconds when I run inside a python script node. On the other hand it takes about 2 minutes to load when running inside a python processor node.
For this specific task I'd need to run inside a processor, since the file loading is tied to workitem generation.
What could be the cause for such a big difference in the execution times ?
thanks.
Technical Discussion » HQueue and PDG - a couple questions
- fabriciochamon
- 68 posts
- Online
any thoughts on this? I'm mainly concerned about the parent job locking resources on the farm.
thanks.
thanks.
PDG/TOPs » ROP fetch not evaluating pdg attribute
- fabriciochamon
- 68 posts
- Online
PDG/TOPs » ROP fetch not evaluating pdg attribute
- fabriciochamon
- 68 posts
- Online
PDG/TOPs » ROP fetch not evaluating pdg attribute
- fabriciochamon
- 68 posts
- Online
Hi,
I have this ROP Fetch node where I need to point to a rop defined by a pdg attribute. like this:
ROP Path = “/obj/ropnet1/`@rop_name`”
while it runs just fine, if I now check the “Output Parm Name” parameter, it errors with message: “Unable to find parm ‘vray’ on node ‘/obj/ropnet1/’”. That is clearly not evaluating the pdg attribute when I use “Output Parm Name”.
I need to use that parm because I'm rendering on v-ray, and want to properly have Expected Outputs from this node, thus allowing me to skip rendered frames if need be.
any workarounds for this ?
thanks
PS: I've attached a simple file showing the same issue with a mantra rop.
I have this ROP Fetch node where I need to point to a rop defined by a pdg attribute. like this:
ROP Path = “/obj/ropnet1/`@rop_name`”
while it runs just fine, if I now check the “Output Parm Name” parameter, it errors with message: “Unable to find parm ‘vray’ on node ‘/obj/ropnet1/’”. That is clearly not evaluating the pdg attribute when I use “Output Parm Name”.
I need to use that parm because I'm rendering on v-ray, and want to properly have Expected Outputs from this node, thus allowing me to skip rendered frames if need be.
any workarounds for this ?
thanks
PS: I've attached a simple file showing the same issue with a mantra rop.
Technical Discussion » HQueue and PDG - a couple questions
- fabriciochamon
- 68 posts
- Online
Hi,
QUESTION 1:
———–
I think I'm having a misconception about how a PDG graph is supposed to run on HQueue. I have this scene where I need to send a single ROP Fetch node to the farm (rendering multiple frames). For now I have small testing environment with 2 render nodes only, and want to split renders between these machines. I also want to use the “Submit Graph as Job” section, so I can close and disconnect the current Houdini session from pdg.
The HQueue job hierarchy is created like this:
(parent) Top cook
(child) render frame 1
(child) render frame 2
(child) render frame 3
…
First client(A) gets assigned to the parent job, the machine is now locked to that job, waiting for all child jobs to terminate. All child jobs get assigned to second client(B). This is obviously wasting all power resources from (A).
I can make both clients work together by changing the number of CPUs per job on the “Job Parms” tab, but then I can't properly set a reasonable number of CPUs without having a portion of that locked to that parent job (which is, in theory, doing nothing but waiting on child jobs to finish).
So my question is: do that parent job really needs to lock resources while waiting for the child items to complete ? Any way to circumvent that ?
QUESTION 2:
———–
Are there any ways to gain control over job names created from built-in TOP nodes. For example: sending a ROP fetch node to farm would create a series of jobs called “render_1” or “render_1_2” or names like these on HQueue. Can I somehow (python or whatever) overwrite these workitem names before sending them to the farm ?
thank you!
QUESTION 1:
———–
I think I'm having a misconception about how a PDG graph is supposed to run on HQueue. I have this scene where I need to send a single ROP Fetch node to the farm (rendering multiple frames). For now I have small testing environment with 2 render nodes only, and want to split renders between these machines. I also want to use the “Submit Graph as Job” section, so I can close and disconnect the current Houdini session from pdg.
The HQueue job hierarchy is created like this:
(parent) Top cook
(child) render frame 1
(child) render frame 2
(child) render frame 3
…
First client(A) gets assigned to the parent job, the machine is now locked to that job, waiting for all child jobs to terminate. All child jobs get assigned to second client(B). This is obviously wasting all power resources from (A).
I can make both clients work together by changing the number of CPUs per job on the “Job Parms” tab, but then I can't properly set a reasonable number of CPUs without having a portion of that locked to that parent job (which is, in theory, doing nothing but waiting on child jobs to finish).
So my question is: do that parent job really needs to lock resources while waiting for the child items to complete ? Any way to circumvent that ?
QUESTION 2:
———–
Are there any ways to gain control over job names created from built-in TOP nodes. For example: sending a ROP fetch node to farm would create a series of jobs called “render_1” or “render_1_2” or names like these on HQueue. Can I somehow (python or whatever) overwrite these workitem names before sending them to the farm ?
thank you!
Edited by fabriciochamon - 2020年2月17日 18:32:18
PDG/TOPs » Sending Python Script nodes to HQueue (not working)
- fabriciochamon
- 68 posts
- Online
Hi Taylor,
Thank you, this indeed works, sorry for the noise (Chris also helped me out on the Discord channel). Just for the records, my problem was that I was changing the python node (poiting the other scheduler) and trying to recook right away. Looks like I also need to regenerate the node, otherwise Hqueue would not pickup the changes. I took me a while to realize this.
thanks.
Thank you, this indeed works, sorry for the noise (Chris also helped me out on the Discord channel). Just for the records, my problem was that I was changing the python node (poiting the other scheduler) and trying to recook right away. Looks like I also need to regenerate the node, otherwise Hqueue would not pickup the changes. I took me a while to realize this.
thanks.
PDG/TOPs » Sending Python Script nodes to HQueue (not working)
- fabriciochamon
- 68 posts
- Online
Hi, I'm having trouble overriding the scheduler for a python script pdg node. The default for all nodes is a local scheduler, but for this specific node I want to send to the farm (hqueue scheduler). It looks like it is always executing locally, no mater what its scheduler parm is set to.
What am I missing here ?
I'm on Houdini 18.0.348 btw, seen a lot of updates related to HQueue/PDG on later versions, but I'm not sure I need to update to use this. (preferrably not, if possible)
thanks
What am I missing here ?
I'm on Houdini 18.0.348 btw, seen a lot of updates related to HQueue/PDG on later versions, but I'm not sure I need to update to use this. (preferrably not, if possible)
thanks
Edited by fabriciochamon - 2020年2月13日 01:37:48
PDG/TOPs » ropfetch not reading rendered files correctly
- fabriciochamon
- 68 posts
- Online
hi, apparently I'm running into the same issue here, while fetching a Vray rop. It does not generate any expected files, and renders all frames everytime.
To add to the problem, my “ROP Path” parm (in the ropfetch node)is also built from pdg attributes (it uses a different rop node depending on the workitem being processed), something like this:
ROP Path: /obj/ropnet1/`@rop_node_name`
May that be the cause for it not being able to generate the expected outputs? it also fails when I try to set the “Output Parm Name” parm, telling me that it can't find the node “/obj/ropnet1/” in the example above (clearly not resolving the pdg attribute).
Has it ever been addressed? or is it something I might have to ask for the v-ray devs ?
thank you
To add to the problem, my “ROP Path” parm (in the ropfetch node)is also built from pdg attributes (it uses a different rop node depending on the workitem being processed), something like this:
ROP Path: /obj/ropnet1/`@rop_node_name`
May that be the cause for it not being able to generate the expected outputs? it also fails when I try to set the “Output Parm Name” parm, telling me that it can't find the node “/obj/ropnet1/” in the example above (clearly not resolving the pdg attribute).
Has it ever been addressed? or is it something I might have to ask for the v-ray devs ?
thank you
Edited by fabriciochamon - 2020年1月30日 18:13:22
Technical Discussion » Python 3 - printing to console not working
- fabriciochamon
- 68 posts
- Online
thanks Manuel. yes, looks like it's still early days for Python 3, I just wanted to let the guys know, maybe it could be an easy fix
Technical Discussion » Python 3 - printing to console not working
- fabriciochamon
- 68 posts
- Online
Hi, I've downloaded Houdini 18.0.287 (Python 3), and for some reason I can't print to console when using a python node. Is this a known issue? any workarounds ?
thanks.
——-
EDIT: I'm actually getting some errors logged to console upon Houdini start, and middle-clicking nodes also don't show anything.
log:
Error running event handler:
File “opdef:/Sop/attribpaint?ViewerStateModule”, line 52
if basenode is not None:
^
TabError: inconsistent use of tabs and spaces in indentation
Error running event handler:
Traceback (most recent call last):
File “opdef:/Sop/attribpaint?ViewerStateInstall”, line 1, in <module>
File “C:/PROGRA~1/SIDEEF~1/HOUDIN~1.287/houdini/python3.7libs\viewerstate\utils.py”, line 948, in register_pystate_embedded
template = node_type.hdaViewerStateModule().createViewerStateTemplate()
File “C:/PROGRA~1/SIDEEF~1/HOUDIN~1.287/houdini/python3.7libs\hou.py”, line 44976, in __getattr__
return _hou.HDAViewerStateModule___getattr__(self, name)
AttributeError: ‘module’ object has no attribute ‘createViewerStateTemplate’
Qt Warn: Sub class of QObject not inheriting QObject!? Crash will happen when using BackgroundEventHandler.
Qt Warn: Sub class of QObject not inheriting QObject!? Crash will happen when using TaskGraphTableModel.
Qt Warn: Sub class of QObject not inheriting QObject!? Crash will happen when using PaginationHelper.
Qt Warn: Sub class of QObject not inheriting QObject!? Crash will happen when using WorkItemTableModel.
thanks.
——-
EDIT: I'm actually getting some errors logged to console upon Houdini start, and middle-clicking nodes also don't show anything.
log:
Error running event handler:
File “opdef:/Sop/attribpaint?ViewerStateModule”, line 52
if basenode is not None:
^
TabError: inconsistent use of tabs and spaces in indentation
Error running event handler:
Traceback (most recent call last):
File “opdef:/Sop/attribpaint?ViewerStateInstall”, line 1, in <module>
File “C:/PROGRA~1/SIDEEF~1/HOUDIN~1.287/houdini/python3.7libs\viewerstate\utils.py”, line 948, in register_pystate_embedded
template = node_type.hdaViewerStateModule().createViewerStateTemplate()
File “C:/PROGRA~1/SIDEEF~1/HOUDIN~1.287/houdini/python3.7libs\hou.py”, line 44976, in __getattr__
return _hou.HDAViewerStateModule___getattr__(self, name)
AttributeError: ‘module’ object has no attribute ‘createViewerStateTemplate’
Qt Warn: Sub class of QObject not inheriting QObject!? Crash will happen when using BackgroundEventHandler.
Qt Warn: Sub class of QObject not inheriting QObject!? Crash will happen when using TaskGraphTableModel.
Qt Warn: Sub class of QObject not inheriting QObject!? Crash will happen when using PaginationHelper.
Qt Warn: Sub class of QObject not inheriting QObject!? Crash will happen when using WorkItemTableModel.
Edited by fabriciochamon - 2019年11月29日 17:38:44
PDG/TOPs » Dynamic (expression driven) frame ranges on rop fetch
- fabriciochamon
- 68 posts
- Online
allright, I ended up going for the ROP geo approach and it worked, so I'll stick to that for the moment. Thanks for all the clarification Taylor.
PDG/TOPs » Dynamic (expression driven) frame ranges on rop fetch
- fabriciochamon
- 68 posts
- Online
wonderful Taylor, thank you for the in depth explanation! I now understand that this is a case for storing data on disk as an intermediary step, at least for Houdini 17.5. works great with the rop geo+geo import combo.
Now regarding H18, I tried your second sugestion, as it seems more efficient (no temp files). The invoke node needs houdini native input geometry, so my file pattern node reading .fbx of course errors: “Error loading geometry bla\bla\bla.fbx” - makes sense. to workaround this I created a dummy geo node at obj level and imported that into pdg using geometry import (I don't need actual geo, but only an attribute placeholder for it to be fed into the invoke). Now on the invoke node I point to a compile block end sop and finally another geo import to extract the attributes from the result of that invoke node. Basically this:
PDG:
file pattern (read *.fbx) -> geom. import (dummy geometry) -> invoke -> geom. import (extract attribs from invoke geo output)
SOPS:
geometry container -> compile begin -> add (1 point) -> attribute create (reads frame range from fbx chop node using chopl()) -> compile end
Unfortunatelly I'm not getting the correct endFrame attribute per workitem, it always have the same number for all items, so probably this is the wrong approach? I'd again appreciate if you could elaborate a bit more on this, as it looks like a better and smarter way of doing this.
big thanks.
Now regarding H18, I tried your second sugestion, as it seems more efficient (no temp files). The invoke node needs houdini native input geometry, so my file pattern node reading .fbx of course errors: “Error loading geometry bla\bla\bla.fbx” - makes sense. to workaround this I created a dummy geo node at obj level and imported that into pdg using geometry import (I don't need actual geo, but only an attribute placeholder for it to be fed into the invoke). Now on the invoke node I point to a compile block end sop and finally another geo import to extract the attributes from the result of that invoke node. Basically this:
PDG:
file pattern (read *.fbx) -> geom. import (dummy geometry) -> invoke -> geom. import (extract attribs from invoke geo output)
SOPS:
geometry container -> compile begin -> add (1 point) -> attribute create (reads frame range from fbx chop node using chopl()) -> compile end
Unfortunatelly I'm not getting the correct endFrame attribute per workitem, it always have the same number for all items, so probably this is the wrong approach? I'd again appreciate if you could elaborate a bit more on this, as it looks like a better and smarter way of doing this.
big thanks.
PDG/TOPs » Dynamic (expression driven) frame ranges on rop fetch
- fabriciochamon
- 68 posts
- Online
Hi, sorry to bring this old topic back again.. months later and I'm still struggling with this. What is the proper way to have a dynamic frame range (different for each work item) inside a PDG graph ? The example usecase would be the same from intial post: say you have a bunch of mocap files inside a folder, I want to load/process(in chops)/export all of them, each one with its corresponding frame ranges. I can access the fbx animation ranges in any context through expressions, python and whatnot, but how to make pdg follow this range per workitem ? An example would be much appreciated!
thanks.
thanks.
PDG/TOPs » Dynamic (expression driven) frame ranges on rop fetch
- fabriciochamon
- 68 posts
- Online
Hi Taylor, thanks for looking into that. Not sure if we are talking the same here, but I think the problem is that the animation end frame is not known until we load the fbx file, so the “endFrame” attribute must be dynamically created. In tops, I tried using a geometry import node to query a sop geo that has a detail attribute created with chopl() expression, and although the value changes inside the sop attribute, it does not update in the workitem. I didn't have a look at jujoe's scene, but might be the same case?
Here's a simple scene attached. Inside the zip you have a .hip + 2 fbx mocap files. if you cook the filepattern node on the topnet you can select each workitem and see the animation playing(both animations are the same, I only changed end frames. So mocap_1.fbx ends at frame 90, mocap_2.fbx ends at 24). Now if you cook the geometry import node, you can see the workitems' “endFrame” value are always the same, while the attribute inside “read_animation_end_frame” geo container updates.
hope that makes sense, I'm just diving into pdg so bare with me.
Here's a simple scene attached. Inside the zip you have a .hip + 2 fbx mocap files. if you cook the filepattern node on the topnet you can select each workitem and see the animation playing(both animations are the same, I only changed end frames. So mocap_1.fbx ends at frame 90, mocap_2.fbx ends at 24). Now if you cook the geometry import node, you can see the workitems' “endFrame” value are always the same, while the attribute inside “read_animation_end_frame” geo container updates.
hope that makes sense, I'm just diving into pdg so bare with me.
Edited by fabriciochamon - 2019年5月27日 12:16:48
PDG/TOPs » Dynamic (expression driven) frame ranges on rop fetch
- fabriciochamon
- 68 posts
- Online
Hi. I'm trying to drive the frame range inside a rop fetch TOP node with expressions, it seems that it's not possible yet?
My .hip setup is like this: I have a template mocap rig (subnet) that gets its animations from a chopnet. The chopnet loads a FBX file from disk (fbx node). There's also a topnet that would serve as batch processor for reading/modifying/exporting all animations inside a folder.
My pdg graph has only 2 nodes: file pattern > rop fetch, and I wanted the end frame of the rop fetch node to be set to the length of each animation(workitem), so my initial guess was reading the length of the chop fbx input node with chopl(“path/to/node”)
While this seems to work on the UI (when previewing different workitems), all the exported animations get the same frame range when I cook the rop fetch node.
I also tried to read the animation length from a geometry node, store it as detail attribute, and query that back inside pdg using geometry import, but that crashes houdini.
What is the proper way to do this ?
thanks
My .hip setup is like this: I have a template mocap rig (subnet) that gets its animations from a chopnet. The chopnet loads a FBX file from disk (fbx node). There's also a topnet that would serve as batch processor for reading/modifying/exporting all animations inside a folder.
My pdg graph has only 2 nodes: file pattern > rop fetch, and I wanted the end frame of the rop fetch node to be set to the length of each animation(workitem), so my initial guess was reading the length of the chop fbx input node with chopl(“path/to/node”)
While this seems to work on the UI (when previewing different workitems), all the exported animations get the same frame range when I cook the rop fetch node.
I also tried to read the animation length from a geometry node, store it as detail attribute, and query that back inside pdg using geometry import, but that crashes houdini.
What is the proper way to do this ?
thanks
Technical Discussion » quadruped autorig
- fabriciochamon
- 68 posts
- Online
-
- Quick Links