Help
RSS
API
Feed
Maltego
Contact
Domain > www.danturco.com
×
More information on this domain is in
AlienVault OTX
Is this malicious?
Yes
No
DNS Resolutions
Date
IP Address
2026-02-13
67.205.1.69
(
ClassC
)
Port 80
HTTP/1.1 301 Moved PermanentlyDate: Fri, 13 Feb 2026 20:13:17 GMTServer: ApacheLocation: https://www.danturco.com/Content-Length: 233Content-Type: text/html; charsetiso-8859-1 !DOCTYPE HTML PUBLIC -//IETF//DTD HTML 2.0//EN>html>head>title>301 Moved Permanently/title>/head>body>h1>Moved Permanently/h1>p>The document has moved a hrefhttps://www.danturco.com/>here/a>./p>/body>/html>
Port 443
HTTP/1.1 200 OKDate: Fri, 13 Feb 2026 20:13:17 GMTServer: ApacheVary: accept,content-type,Accept-Encoding,User-AgentLink: https://www.danturco.com/wp-json/>; relhttps://api.w.org/, https://wp.me/6MR2m>; relshortlinkUpgrade: h2Connection: UpgradeCache-Control: max-age600Expires: Fri, 13 Feb 2026 20:23:17 GMTTransfer-Encoding: chunkedContent-Type: text/html; charsetUTF-8 !DOCTYPE html>html langen-US>head>meta charsetUTF-8>meta nameviewport contentwidthdevice-width, initial-scale1>title>DanTurco.com | Nothin to it but to do it/title>link relprofile hrefhttps://gmpg.org/xfn/11>link relpingback hrefhttps://www.danturco.com/wp/xmlrpc.php>meta namerobots contentmax-image-preview:large />link reldns-prefetch href//secure.gravatar.com />link reldns-prefetch href//stats.wp.com />link reldns-prefetch href//fonts.googleapis.com />link reldns-prefetch href//v0.wordpress.com />link reldns-prefetch href//widgets.wp.com />link reldns-prefetch href//s0.wp.com />link reldns-prefetch href//0.gravatar.com />link reldns-prefetch href//1.gravatar.com />link reldns-prefetch href//2.gravatar.com />link relalternate typeapplication/rss+xml titleDanTurco.com » Feed hrefhttps://www.danturco.com/feed/ />link relalternate typeapplication/rss+xml titleDanTurco.com » Comments Feed hrefhttps://www.danturco.com/comments/feed/ /> !-- This site uses the Google Analytics by ExactMetrics plugin v9.0.2 - Using Analytics tracking - https://www.exactmetrics.com/ --> !-- Note: ExactMetrics is not currently configured on this site. The site owner needs to authenticate with Google Analytics in the ExactMetrics settings panel. --> !-- No tracking code set --> !-- / Google Analytics by ExactMetrics --> style idwp-img-auto-sizes-contain-inline-css typetext/css>img:is(sizesauto i,sizes^auto, i){contain-intrinsic-size:3000px 1500px}/*# sourceURLwp-img-auto-sizes-contain-inline-css *//style>style idwp-emoji-styles-inline-css typetext/css> img.wp-smiley, img.emoji { display: inline !important; border: none !important; box-shadow: none !important; height: 1em !important; width: 1em !important; margin: 0 0.07em !important; vertical-align: -0.1em !important; background: none !important; padding: 0 !important; }/*# sourceURLwp-emoji-styles-inline-css *//style>style idwp-block-library-inline-css typetext/css>:root{--wp-block-synced-color:#7a00df;--wp-block-synced-color--rgb:122,0,223;--wp-bound-block-color:var(--wp-block-synced-color);--wp-editor-canvas-background:#ddd;--wp-admin-theme-color:#007cba;--wp-admin-theme-color--rgb:0,124,186;--wp-admin-theme-color-darker-10:#006ba1;--wp-admin-theme-color-darker-10--rgb:0,107,160.5;--wp-admin-theme-color-darker-20:#005a87;--wp-admin-theme-color-darker-20--rgb:0,90,135;--wp-admin-border-width-focus:2px}@media (min-resolution:192dpi){:root{--wp-admin-border-width-focus:1.5px}}.wp-element-button{cursor:pointer}:root .has-very-light-gray-background-color{background-color:#eee}:root .has-very-dark-gray-background-color{background-color:#313131}:root .has-very-light-gray-color{color:#eee}:root .has-very-dark-gray-color{color:#313131}:root .has-vivid-green-cyan-to-vivid-cyan-blue-gradient-background{background:linear-gradient(135deg,#00d084,#0693e3)}:root .has-purple-crush-gradient-background{background:linear-gradient(135deg,#34e2e4,#4721fb 50%,#ab1dfe)}:root .has-hazy-dawn-gradient-background{background:linear-gradient(135deg,#faaca8,#dad0ec)}:root .has-subdued-olive-gradient-background{background:linear-gradient(135deg,#fafae1,#67a671)}:root .has-atomic-cream-gradient-background{background:linear-gradient(135deg,#fdd79a,#004a59)}:root .has-nightshade-gradient-background{background:linear-gradient(135deg,#330968,#31cdcf)}:root .has-midnight-gradient-background{background:linear-gradient(135deg,#020381,#2874fc)}:root{--wp--preset--font-size--normal:16px;--wp--preset--font-size--huge:42px}.has-regular-font-size{font-size:1em}.has-larger-font-size{font-size:2.625em}.has-normal-font-size{font-size:var(--wp--preset--font-size--normal)}.has-huge-font-size{font-size:var(--wp--preset--font-size--huge)}.has-text-align-center{text-align:center}.has-text-align-left{text-align:left}.has-text-align-right{text-align:right}.has-fit-text{white-space:nowrap!important}#end-resizable-editor-section{display:none}.aligncenter{clear:both}.items-justified-left{justify-content:flex-start}.items-justified-center{justify-content:center}.items-justified-right{justify-content:flex-end}.items-justified-space-between{justify-content:space-between}.screen-reader-text{border:0;clip-path:inset(50%);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;word-wrap:normal!important}.screen-reader-text:focus{background-color:#ddd;clip-path:none;color:#444;display:block;font-size:1em;height:auto;left:5px;line-height:normal;padding:15px 23px 14px;text-decoration:none;top:5px;width:auto;z-index:100000}html :where(.has-border-color){border-style:solid}html :where(style*border-top-color){border-top-style:solid}html :where(style*border-right-color){border-right-style:solid}html :where(style*border-bottom-color){border-bottom-style:solid}html :where(style*border-left-color){border-left-style:solid}html :where(style*border-width){border-style:solid}html :where(style*border-top-width){border-top-style:solid}html :where(style*border-right-width){border-right-style:solid}html :where(style*border-bottom-width){border-bottom-style:solid}html :where(style*border-left-width){border-left-style:solid}html :where(imgclass*wp-image-){height:auto;max-width:100%}:where(figure){margin:0 0 1em}html :where(.is-position-sticky){--wp-admin--admin-bar--position-offset:var(--wp-admin--admin-bar--height,0px)}@media screen and (max-width:600px){html :where(.is-position-sticky){--wp-admin--admin-bar--position-offset:0px}}/*# sourceURLwp-block-library-inline-css *//style>style idwp-block-heading-inline-css typetext/css>h1:where(.wp-block-heading).has-background,h2:where(.wp-block-heading).has-background,h3:where(.wp-block-heading).has-background,h4:where(.wp-block-heading).has-background,h5:where(.wp-block-heading).has-background,h6:where(.wp-block-heading).has-background{padding:1.25em 2.375em}h1.has-text-align-leftstyle*writing-mode:where(style*vertical-lr),h1.has-text-align-rightstyle*writing-mode:where(style*vertical-rl),h2.has-text-align-leftstyle*writing-mode:where(style*vertical-lr),h2.has-text-align-rightstyle*writing-mode:where(style*vertical-rl),h3.has-text-align-leftstyle*writing-mode:where(style*vertical-lr),h3.has-text-align-rightstyle*writing-mode:where(style*vertical-rl),h4.has-text-align-leftstyle*writing-mode:where(style*vertical-lr),h4.has-text-align-rightstyle*writing-mode:where(style*vertical-rl),h5.has-text-align-leftstyle*writing-mode:where(style*vertical-lr),h5.has-text-align-rightstyle*writing-mode:where(style*vertical-rl),h6.has-text-align-leftstyle*writing-mode:where(style*vertical-lr),h6.has-text-align-rightstyle*writing-mode:where(style*vertical-rl){rotate:180deg}/*# sourceURLhttps://www.danturco.com/wp/wp-includes/blocks/heading/style.min.css *//style>style idwp-block-list-inline-css typetext/css>ol,ul{box-sizing:border-box}:root :where(.wp-block-list.has-background){padding:1.25em 2.375em}/*# sourceURLhttps://www.danturco.com/wp/wp-includes/blocks/list/style.min.css *//style>style idwp-block-page-list-inline-css typetext/css>.wp-block-navigation .wp-block-page-list{align-items:var(--navigation-layout-align,initial);background-color:inherit;display:flex;flex-direction:var(--navigation-layout-direction,initial);flex-wrap:var(--navigation-layout-wrap,wrap);justify-content:var(--navigation-layout-justify,initial)}.wp-block-navigation .wp-block-navigation-item{background-color:inherit}.wp-block-page-list{box-sizing:border-box}/*# sourceURLhttps://www.danturco.com/wp/wp-includes/blocks/page-list/style.min.css *//style>style idwp-block-code-inline-css typetext/css>.wp-block-code{box-sizing:border-box}.wp-block-code code{ /*!rtl:begin:ignore*/direction:ltr;display:block;font-family:inherit;overflow-wrap:break-word;text-align:initial;white-space:pre-wrap /*!rtl:end:ignore*/}/*# sourceURLhttps://www.danturco.com/wp/wp-includes/blocks/code/style.min.css *//style>style idwp-block-paragraph-inline-css typetext/css>.is-small-text{font-size:.875em}.is-regular-text{font-size:1em}.is-large-text{font-size:2.25em}.is-larger-text{font-size:3em}.has-drop-cap:not(:focus):first-letter{float:left;font-size:8.4em;font-style:normal;font-weight:100;line-height:.68;margin:.05em .1em 0 0;text-transform:uppercase}body.rtl .has-drop-cap:not(:focus):first-letter{float:none;margin-left:.1em}p.has-drop-cap.has-background{overflow:hidden}:root :where(p.has-background){padding:1.25em 2.375em}:where(p.has-text-color:not(.has-link-color)) a{color:inherit}p.has-text-align-leftstyle*writing-mode:vertical-lr,p.has-text-align-rightstyle*writing-mode:vertical-rl{rotate:180deg}/*# sourceURLhttps://www.danturco.com/wp/wp-includes/blocks/paragraph/style.min.css *//style>style idclassic-theme-styles-inline-css typetext/css>/*! This file is auto-generated */.wp-block-button__link{color:#fff;background-color:#32373c;border-radius:9999px;box-shadow:none;text-decoration:none;padding:calc(.667em + 2px) calc(1.333em + 2px);font-size:1.125em}.wp-block-file__button{background:#32373c;color:#fff;text-decoration:none}/*# sourceURL/wp-includes/css/classic-themes.min.css *//style>style idglobal-styles-inline-css typetext/css>:root{--wp--preset--aspect-ratio--square: 1;--wp--preset--aspect-ratio--4-3: 4/3;--wp--preset--aspect-ratio--3-4: 3/4;--wp--preset--aspect-ratio--3-2: 3/2;--wp--preset--aspect-ratio--2-3: 2/3;--wp--preset--aspect-ratio--16-9: 16/9;--wp--preset--aspect-ratio--9-16: 9/16;--wp--preset--color--black: #000000;--wp--preset--color--cyan-bluish-gray: #abb8c3;--wp--preset--color--white: #ffffff;--wp--preset--color--pale-pink: #f78da7;--wp--preset--color--vivid-red: #cf2e2e;--wp--preset--color--luminous-vivid-orange: #ff6900;--wp--preset--color--luminous-vivid-amber: #fcb900;--wp--preset--color--light-green-cyan: #7bdcb5;--wp--preset--color--vivid-green-cyan: #00d084;--wp--preset--color--pale-cyan-blue: #8ed1fc;--wp--preset--color--vivid-cyan-blue: #0693e3;--wp--preset--color--vivid-purple: #9b51e0;--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple: linear-gradient(135deg,rgb(6,147,227) 0%,rgb(155,81,224) 100%);--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan: linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%);--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange: linear-gradient(135deg,rgb(252,185,0) 0%,rgb(255,105,0) 100%);--wp--preset--gradient--luminous-vivid-orange-to-vivid-red: linear-gradient(135deg,rgb(255,105,0) 0%,rgb(207,46,46) 100%);--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray: linear-gradient(135deg,rgb(238,238,238) 0%,rgb(169,184,195) 100%);--wp--preset--gradient--cool-to-warm-spectrum: linear-gradient(135deg,rgb(74,234,220) 0%,rgb(151,120,209) 20%,rgb(207,42,186) 40%,rgb(238,44,130) 60%,rgb(251,105,98) 80%,rgb(254,248,76) 100%);--wp--preset--gradient--blush-light-purple: linear-gradient(135deg,rgb(255,206,236) 0%,rgb(152,150,240) 100%);--wp--preset--gradient--blush-bordeaux: linear-gradient(135deg,rgb(254,205,165) 0%,rgb(254,45,45) 50%,rgb(107,0,62) 100%);--wp--preset--gradient--luminous-dusk: linear-gradient(135deg,rgb(255,203,112) 0%,rgb(199,81,192) 50%,rgb(65,88,208) 100%);--wp--preset--gradient--pale-ocean: linear-gradient(135deg,rgb(255,245,203) 0%,rgb(182,227,212) 50%,rgb(51,167,181) 100%);--wp--preset--gradient--electric-grass: linear-gradient(135deg,rgb(202,248,128) 0%,rgb(113,206,126) 100%);--wp--preset--gradient--midnight: linear-gradient(135deg,rgb(2,3,129) 0%,rgb(40,116,252) 100%);--wp--preset--font-size--small: 13px;--wp--preset--font-size--medium: 20px;--wp--preset--font-size--large: 36px;--wp--preset--font-size--x-large: 42px;--wp--preset--spacing--20: 0.44rem;--wp--preset--spacing--30: 0.67rem;--wp--preset--spacing--40: 1rem;--wp--preset--spacing--50: 1.5rem;--wp--preset--spacing--60: 2.25rem;--wp--preset--spacing--70: 3.38rem;--wp--preset--spacing--80: 5.06rem;--wp--preset--shadow--natural: 6px 6px 9px rgba(0, 0, 0, 0.2);--wp--preset--shadow--deep: 12px 12px 50px rgba(0, 0, 0, 0.4);--wp--preset--shadow--sharp: 6px 6px 0px rgba(0, 0, 0, 0.2);--wp--preset--shadow--outlined: 6px 6px 0px -3px rgb(255, 255, 255), 6px 6px rgb(0, 0, 0);--wp--preset--shadow--crisp: 6px 6px 0px rgb(0, 0, 0);}:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}:where(.wp-block-columns.is-layout-flex){gap: 2em;}:where(.wp-block-columns.is-layout-grid){gap: 2em;}:where(.wp-block-post-template.is-layout-flex){gap: 1.25em;}:where(.wp-block-post-template.is-layout-grid){gap: 1.25em;}.has-black-color{color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-color{color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-color{color: var(--wp--preset--color--white) !important;}.has-pale-pink-color{color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-color{color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-color{color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-color{color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-color{color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-color{color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-color{color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-color{color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-color{color: var(--wp--preset--color--vivid-purple) !important;}.has-black-background-color{background-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-background-color{background-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}.has-pale-pink-background-color{background-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-background-color{background-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-background-color{background-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-background-color{background-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-background-color{background-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-background-color{background-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-background-color{background-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-background-color{background-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-background-color{background-color: var(--wp--preset--color--vivid-purple) !important;}.has-black-border-color{border-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-border-color{border-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}.has-pale-pink-border-color{border-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-border-color{border-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-border-color{border-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-border-color{border-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-border-color{border-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-border-color{border-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-border-color{border-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-border-color{border-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-border-color{border-color: var(--wp--preset--color--vivid-purple) !important;}.has-vivid-cyan-blue-to-vivid-purple-gradient-background{background: var(--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple) !important;}.has-light-green-cyan-to-vivid-green-cyan-gradient-background{background: var(--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan) !important;}.has-luminous-vivid-amber-to-luminous-vivid-orange-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange) !important;}.has-luminous-vivid-orange-to-vivid-red-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-orange-to-vivid-red) !important;}.has-very-light-gray-to-cyan-bluish-gray-gradient-background{background: var(--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray) !important;}.has-cool-to-warm-spectrum-gradient-background{background: var(--wp--preset--gradient--cool-to-warm-spectrum) !important;}.has-blush-light-purple-gradient-background{background: var(--wp--preset--gradient--blush-light-purple) !important;}.has-blush-bordeaux-gradient-background{background: var(--wp--preset--gradient--blush-bordeaux) !important;}.has-luminous-dusk-gradient-background{background: var(--wp--preset--gradient--luminous-dusk) !important;}.has-pale-ocean-gradient-background{background: var(--wp--preset--gradient--pale-ocean) !important;}.has-electric-grass-gradient-background{background: var(--wp--preset--gradient--electric-grass) !important;}.has-midnight-gradient-background{background: var(--wp--preset--gradient--midnight) !important;}.has-small-font-size{font-size: var(--wp--preset--font-size--small) !important;}.has-medium-font-size{font-size: var(--wp--preset--font-size--medium) !important;}.has-large-font-size{font-size: var(--wp--preset--font-size--large) !important;}.has-x-large-font-size{font-size: var(--wp--preset--font-size--x-large) !important;}/*# sourceURLglobal-styles-inline-css *//style>link relstylesheet idgoogleFonts-css href//fonts.googleapis.com/css?familyOpen+Sans%3A400italic%2C700italic%2C400%2C700&ver6.9.1 typetext/css mediaall />link relstylesheet idsocialFont-css hrefhttps://www.danturco.com/wp/wp-content/themes/lonely-road/fonts/social.css?verc423a468a788fcb1d5bc115366fe3049 typetext/css mediaall />link relstylesheet idlonely-road-style-css hrefhttps://www.danturco.com/wp/wp-content/themes/lonely-road/style.css?verc423a468a788fcb1d5bc115366fe3049 typetext/css mediaall />style idjetpack_likes-inline-css typetext/css>#jp-post-flair{padding-top:.5em}#content div.sharedaddy,#main div.sharedaddy,div.sharedaddy{clear:both}div.sharedaddy h3.sd-title{display:inline-block;font-size:9pt;font-weight:700;line-height:1.2;margin:0 0 1em}div.sharedaddy h3.sd-title:before{border-top:1px solid #dcdcde;content:;display:block;margin-bottom:1em;min-width:30px;width:100%}div.jetpack-likes-widget-wrapper{min-height:50px;position:relative;width:100%}div.jetpack-likes-widget-wrapper .sd-link-color{font-size:12px}div.jetpack-comment-likes-widget-wrapper{min-height:31px;position:relative;width:100%}div.jetpack-comment-likes-widget-wrapper iframe{margin-bottom:0}#likes-other-gravatars{background-color:#fff;border:1px solid #dcdcde;border-radius:4px;box-shadow:none;display:none;height:auto;max-height:240px;min-width:220px;overflow:auto;padding:9px 12px 10px;position:absolute;z-index:1000}#likes-other-gravatars *{line-height:normal}#likes-other-gravatars .likes-text{color:#101517;font-size:12px;font-weight:500;padding-bottom:8px}#likes-other-gravatars li,#likes-other-gravatars ul{list-style-type:none;margin:0;padding:0;text-indent:0}#likes-other-gravatars li:before{content:}#likes-other-gravatars ul.wpl-avatars{display:block;max-height:190px;overflow:auto}#likes-other-gravatars ul.wpl-avatars li{float:none;height:28px;margin:0 0 4px;width:196px}#likes-other-gravatars ul.wpl-avatars li a{align-items:center;border-bottom:none!important;display:flex;gap:8px;margin:0 2px 0 0;text-decoration:none}#likes-other-gravatars ul.wpl-avatars li a span{color:#2c3338;font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#likes-other-gravatars ul.wpl-avatars li a img{background:none;border:none;border-radius:50%;box-sizing:border-box;margin:0!important;padding:1px!important;position:static}div.sd-box{border-top:1px solid #00000021}.jetpack-likes-widget-loaded iframe,.jetpack-likes-widget-loading .likes-widget-placeholder,.jetpack-likes-widget-unloaded .likes-widget-placeholder{display:block}.jetpack-likes-widget-loaded .likes-widget-placeholder,.jetpack-likes-widget-loading iframe,.jetpack-likes-widget-unloaded iframe{display:none}.comment-likes-widget,.entry-content .post-likes-widget,.post-likes-widget{border-width:0;margin:0}.comment-likes-widget-placeholder,.post-likes-widget-placeholder{border-width:0;margin:0;position:relative}.comment-likes-widget-placeholder{display:flex;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;height:18px;position:absolute}.comment-likes-widget-placeholder:before{background-image:url(data:image/svg+xml;charsetutf-8,%3Csvg xmlnshttp://www.w3.org/2000/svg viewBox0 0 24 24%3E%3Cpath fillnone dM0 0h24v24H0z/%3E%3Cpath fill%232ea2cc dm12 2 2.582 6.953L22 9.257l-5.822 4.602L18.18 21 12 16.89 5.82 21l2.002-7.14L2 9.256l7.418-.304/%3E%3C/svg%3E);background-repeat:no-repeat;background-size:16px 16px;color:#2ea2cc;content:;display:inline-block;height:16px;padding-right:5px;position:relative;top:3px;width:16px}.post-likes-widget-placeholder .button{display:none}.comment-likes-widget-placeholder .loading,.post-likes-widget-placeholder .loading{color:#999;font-size:12px}.comment-likes-widget-placeholder .loading{align-self:center;color:#4e4e4e;margin-top:4px;padding-left:5px}div.sharedaddy.sd-like-enabled .sd-like h3{display:none}div.sharedaddy.sd-like-enabled .sd-like .post-likes-widget{float:none;position:absolute;top:0;width:100%}.comment-likes-widget{width:100%}.cs-rating,.pd-rating{display:block!important}.sd-gplus .sd-title{display:none}@media print{.jetpack-likes-widget-wrapper{display:none}}/*# sourceURLhttps://www.danturco.com/wp/wp-content/plugins/jetpack/_inc/build/likes/style.min.css *//style>link relhttps://api.w.org/ hrefhttps://www.danturco.com/wp-json/ />link relEditURI typeapplication/rsd+xml titleRSD hrefhttps://www.danturco.com/wp/xmlrpc.php?rsd /> style>img#wpstats{display:none}/style> style data-contextfoundation-flickity-css>/*! Flickity v2.0.2http://flickity.metafizzy.co---------------------------------------------- */.flickity-enabled{position:relative}.flickity-enabled:focus{outline:0}.flickity-viewport{overflow:hidden;position:relative;height:100%}.flickity-slider{position:absolute;width:100%;height:100%}.flickity-enabled.is-draggable{-webkit-tap-highlight-color:transparent;tap-highlight-color:transparent;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.flickity-enabled.is-draggable .flickity-viewport{cursor:move;cursor:-webkit-grab;cursor:grab}.flickity-enabled.is-draggable .flickity-viewport.is-pointer-down{cursor:-webkit-grabbing;cursor:grabbing}.flickity-prev-next-button{position:absolute;top:50%;width:44px;height:44px;border:none;border-radius:50%;background:#fff;background:hsla(0,0%,100%,.75);cursor:pointer;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.flickity-prev-next-button:hover{background:#fff}.flickity-prev-next-button:focus{outline:0;box-shadow:0 0 0 5px #09f}.flickity-prev-next-button:active{opacity:.6}.flickity-prev-next-button.previous{left:10px}.flickity-prev-next-button.next{right:10px}.flickity-rtl .flickity-prev-next-button.previous{left:auto;right:10px}.flickity-rtl .flickity-prev-next-button.next{right:auto;left:10px}.flickity-prev-next-button:disabled{opacity:.3;cursor:auto}.flickity-prev-next-button svg{position:absolute;left:20%;top:20%;width:60%;height:60%}.flickity-prev-next-button .arrow{fill:#333}.flickity-page-dots{position:absolute;width:100%;bottom:-25px;padding:0;margin:0;list-style:none;text-align:center;line-height:1}.flickity-rtl .flickity-page-dots{direction:rtl}.flickity-page-dots .dot{display:inline-block;width:10px;height:10px;margin:0 8px;background:#333;border-radius:50%;opacity:.25;cursor:pointer}.flickity-page-dots .dot.is-selected{opacity:1}/style>style data-contextfoundation-slideout-css>.slideout-menu{position:fixed;left:0;top:0;bottom:0;right:auto;z-index:0;width:256px;overflow-y:auto;-webkit-overflow-scrolling:touch;display:none}.slideout-menu.pushit-right{left:auto;right:0}.slideout-panel{position:relative;z-index:1;will-change:transform}.slideout-open,.slideout-open .slideout-panel,.slideout-open body{overflow:hidden}.slideout-open .slideout-menu{display:block}.pushit{display:none}/style> style typetext/css> /* Main Font */ body, button, input, select, textarea { font-family: Open Sans, sans-serif; } /* color 1 */ .header-wrapper, .main-navigation ul ul li, #secondary, .entry-content .date { background-color: #1e73be; } .sticky { border: 3px solid #1e73be; } /* color 2 */ .navigation-wrapper { background-color: #ffffff; } .social li a { color: #ffffff; } /style> style typetext/css idcustom-background-css>body.custom-background { background-color: #000000; background-image: url(https://www.danturco.com/wp/wp-content/uploads/2020/07/20200704_201850-scaled.jpg); background-position: left top; background-size: cover; background-repeat: no-repeat; background-attachment: fixed; }/style> !-- Jetpack Open Graph Tags -->meta propertyog:type contentwebsite />meta propertyog:title contentDanTurco.com />meta propertyog:description contentNothin to it but to do it />meta propertyog:url contenthttps://www.danturco.com/ />meta propertyog:site_name contentDanTurco.com />meta propertyog:image contenthttps://www.danturco.com/wp/wp-content/uploads/2020/07/cropped-mountainsAreCalling.jpg />meta propertyog:image:width content512 />meta propertyog:image:height content512 />meta propertyog:image:alt content />meta propertyog:locale contenten_US />!-- End Jetpack Open Graph Tags -->link relicon hrefhttps://www.danturco.com/wp/wp-content/uploads/2020/07/cropped-mountainsAreCalling-32x32.jpg sizes32x32 />link relicon hrefhttps://www.danturco.com/wp/wp-content/uploads/2020/07/cropped-mountainsAreCalling-192x192.jpg sizes192x192 />link relapple-touch-icon hrefhttps://www.danturco.com/wp/wp-content/uploads/2020/07/cropped-mountainsAreCalling-180x180.jpg />meta namemsapplication-TileImage contenthttps://www.danturco.com/wp/wp-content/uploads/2020/07/cropped-mountainsAreCalling-270x270.jpg />style>.ios7.web-app-mode.has-fixed header{ background-color: rgba(45,53,63,.88);}/style>!--if lt IE 9>script srchttps://www.danturco.com/wp/wp-content/themes/lonely-road/js/html5shiv.js>/script>!endif-->/head>body data-rsssl1 classhome blog custom-background wp-theme-lonely-road>div idpage classhfeed site> a classskip-link screen-reader-text href#content>Skip to content/a> div classheader-wrapper> header idmasthead classsite-header rolebanner> div classsite-branding> h1 classsite-title style>a hrefhttps://www.danturco.com/ relhome>DanTurco.com/a>/h1> h2 classsite-description style>Nothin to it but to do it/h2> div classsite-logo styledisplay: none> /div> /div> div classsocial clear> ul> li>a hrefhttps://www.linkedin.com/in/danturco1 classlinkedin titlelinkedin>i classicon-linkedin>/i>/a>/li> li>a hrefhttps://github.com/d1820/ classgithub titlegithub>i classicon-github>/i>/a>/li> li>a hrefhttps://www.danturco.com/feed/ classrss titleRSS>i classicon-rss>/i>/a>/li> /ul> /div> /header> /div> div classnavigation-wrapper> nav idsite-navigation classmain-navigation rolenavigation> button classmenu-toggle>Menu/button> div classmenu-menu-container clear>ul idmenu-areas classmenu clear>li idmenu-item-441 classmenu-item menu-item-type-post_type menu-item-object-page menu-item-441>a hrefhttps://www.danturco.com/sprint-planning-calculator/>Sprint Planning Calculator/a>/li>li idmenu-item-274 classmenu-item menu-item-type-taxonomy menu-item-object-category menu-item-274>a hrefhttps://www.danturco.com/category/howd-they-do-that/>How’d they do that/a>/li>li idmenu-item-275 classmenu-item menu-item-type-taxonomy menu-item-object-category menu-item-275>a hrefhttps://www.danturco.com/category/bookmarklets/>Bookmarklets/a>/li>/ul>/div> /nav> /div> div idcontent classsite-content> div idprimary classcontent-area> main idmain classsite-main rolemain> article idpost-272 classpost-272 post type-post status-publish format-standard hentry category-howd-they-do-that tag-api-manager tag-azure tag-azure-app-services tag-azure-application-gateway tag-https tag-secure tag-ssl tag-virtual-network tag-vnet> header classentry-header> /header>!-- .entry-header --> div classentry-content> a hrefhttps://www.danturco.com/setup-azure-internal-api-manager-with-application-gateway-without-custom-domains/ classdate> span classday>11/span> span classmonth>Jul/span> /a> h1 classentry-title>a hrefhttps://www.danturco.com/setup-azure-internal-api-manager-with-application-gateway-without-custom-domains/ relbookmark>Setup Azure Internal API Manager with Application Gateway without Custom Domains/a>/h1> div classentry-text> h3>Summary/h3>p>Recently I was tasked to setup an internal Azure API Manager and expose it via a WAF Application Gateway. While there were plenty of articles on line about this topic, none of them specifically addressed how to do when you did not want to use a custom domain or purchased SSL certificates. This post walks through setting it all up in Azure using only the domains Azure issues in resource creation/p>h3>Resources/h3>p>These are the resources in Azure we are going to be creating/p>ul>li>App Service/App Service Plan (for hosting the API for API Manager)/li>li>Network Security Group/li>li>API Manager/li>li>Application Gateway/li>li>Public IP Address (2)/li>li>Virtual Machine (the jump box to interact with the API Manager)/li>li>Virtual Networkul>li>Application Gateway Subnet/li>li>APIM Subnet/li>li>VM Jumpbox Subnet/li>li>App Service Subnet/li>/ul>/li>/ul>h3>Create the Network Security Group/h3>ol>li>Navigate to a hrefhttps://portal.azure.com/#create/Microsoft.NetworkSecurityGroup-ARM>Network Security Group/a>/li>li>Create a new Resource Group. This group will be used for the rest of the resources we createul>li>rg-contoso-api-dev-eastus/li>/ul>/li>li>Enter Nameul>li>nsg-contoso-api-dev-eastus/li>/ul>/li>li>Click Create/li>li>Configure the inbound and outbound rules/li>/ol>p>img decodingasync srchttps://www.danturco.com/wp/wp-content/uploads/2020/07/image-1594497348449.png altInbound Rules />/p>p>img decodingasync srchttps://www.danturco.com/wp/wp-content/uploads/2020/07/image-1594497401839.png altOutbound Rules />/p>p>strong>NOTE:/strong> some of these rules may not apply to your given project and circumstances./p>h3>Creating the VNET/h3>ol>li>Navigate to a hrefhttps://portal.azure.com/#create/Microsoft.VirtualNetwork-ARM>Virtual Networks/a>/li>li>Select the Resource Group create from aboveul>li>rg-contoso-api-dev-eastus/li>/ul>/li>li>Enter Name for the VNETul>li>vnet-contoso-dev-eastus/li>/ul>/li>li>Select Regionul>li>East US/li>/ul>/li>li>Click the IP Addresses tabul>li>Delete the default subnet/li>li>Add the following subnetsul>li>snet-contoso-gw-dev-eastus (10.0.1.0/24)/li>li>snet-contoso-pvt-vm-dev-eastus (10.0.2.0/24)/li>li>snet-contoso-pvt-apim-dev-eastus (10.0.3.0/24)/li>li>snet-contoso-pvt-asp-dev-eastus (10.0.4.0/24)/li>/ul>/li>/ul>/li>li>Click Review + Create/li>/ol>h3>Creating the Virtual Machine/h3>ol>li>Navigate to a hrefhttps://portal.azure.com/#create/Microsoft.WindowsServer2016Datacenter-ARM>Windows Server 2016/a>/li>li>Select the Resource Group create from aboveul>li>rg-contoso-api-dev-eastus/li>/ul>/li>li>Enter Virtual machine nameul>li>vm-contoso-api-jumpbox-dev-eastus/li>/ul>/li>li>Select Regionul>li>East US/li>/ul>/li>li>Select the size of the VM you wantul>li>Standard_B1ms/li>/ul>/li>li>Create a Username and Password/li>li>Under Inbound port rulesul>li>Select strong>Allow selected ports/strong>/li>li>Select RDP (3389) from the list/li>/ul>p>img decodingasync srchttps://www.danturco.com/wp/wp-content/uploads/2020/07/image-1594480293599.png altInbound port rules />/p>/li>li>Click on the Disks Tabul>li>For OS disk type selectul>li>Standard HDD/li>/ul>/li>/ul>/li>li>Click on the Network Tabul>li>Select the VNET (vnet-contoso-dev-eastus) from above/li>li>Select Subnetul>li>snet-contoso-pvt-vm-dev-eastus/li>/ul>/li>li>Create a new Public IP for the Virtual Machineul>li>pubip-contoso-api-jumpbox-dev-eastus/li>li>Keep the rest of the defaults/li>/ul>/li>li>Under NIC network security groupul>li>Click Advanced/li>li>Select Create New/li>li>vm-contoso-api-jumpbox-dev-eastus-nsg (this will be auto populated)/li>/ul>p>img decodingasync srchttps://www.danturco.com/wp/wp-content/uploads/2020/07/image-1594481040019.png altJumpbox NSG />/p>/li>/ul>/li>li>Keep the rest of the default settings/li>li>Click Review + Create/li>/ol>p>strong>NOTE:/strong> When the VM is create a new/p>h3>Lets Configure the Subnets/h3>p>Navigate to the new VNET resource (vnet-contoso-dev-eastus) and select Subnets/p>h4>Configure snet-contoso-pvt-apim-dev-eastus/h4>p>img decodingasync srchttps://www.danturco.com/wp/wp-content/uploads/2020/07/image-1594479152903.png altSubnets />/p>ol>li>Select Subnet strong>snet-contoso-pvt-apim-dev-eastus/strong>/li>li>Under Network Security Groupul>li>Select nsg-contoso-api-dev-eastus/li>/ul>/li>li>Under Subnet delegationul>li>Select Microsoft.ApiManagement/service/li>/ul>p>img decodingasync srchttps://www.danturco.com/wp/wp-content/uploads/2020/07/image-1594479739910.png altSubnet Delegation />/p>/li>li>Click Save/li>/ol>h4>Configure snet-contoso-pvt-asp-dev-eastus/h4>ol>li>Select Subnet strong>snet-contoso-pvt-asp-dev-eastus/strong>/li>li>Under Subnet delegationul>li>Select Microsoft.Web/serverFarms/li>/ul>p>img decodingasync srchttps://www.danturco.com/wp/wp-content/uploads/2020/07/image-1594479939297.png altInbound port rules />/p>/li>li>Click Save/li>/ol>h3>Creating the API Manager/h3>ol>li>Navigate to a hrefhttps://portal.azure.com/#create/Microsoft.ApiManagement>API Management/a>/li>li>Enter Nameul>li>api.contoso/li>/ul>/li>li>Select the Resource Group create from aboveul>li>rg-contoso-api-dev-eastus/li>/ul>/li>li>Select Location (Region)ul>li>East US/li>/ul>/li>li>Pricing Tierul>li>Select Development/Premium/li>/ul>/li>li>Click Create/li>li>Once created lets join it to the VNET (vnet-contoso-dev-eastus)ul>li>Navigate to the new APIM resource/li>li>Locate Virtual Networkp>img decodingasync srchttps://www.danturco.com/wp/wp-content/uploads/2020/07/image-1594477974556.png altVirtual Network />/p>/li>li>Select strong>Internal/strong>/li>li>Select the Virtual Network created above/li>li>Select Subnet strong>snet-contoso-pvt-apim-dev-eastus/strong>/li>li>Click Apply/li>/ul>/li>/ol>h3>Creating the App Service Plan/h3>ol>li>Navigate to a hrefhttps://portal.azure.com/#create/Microsoft.AppServicePlanCreate>App Service Plan/a>/li>li>Select the Resource Group create from aboveul>li>rg-contoso-api-dev-eastus/li>/ul>/li>li>Enter the nameul>li>asp.contoso.api-dev-eastus/li>/ul>/li>li>Select the OS you require for your API/li>li>Select the Regionul>li>East US/li>/ul>/li>li>Select your required pricing tier/li>li>Click Review + Create/li>li>Deploy your API to an App Service under the newly created ASP aboveul>li>Add the App service to the VNET (vnet-contoso-dev-eastus)/li>li>Select subnet strong>snet-contoso-pvt-asp-dev-eastus/strong>/li>/ul>/li>/ol>h3>Setting up the JumpBox/h3>ol>li>Navigate to the API Manager resource created aboveul>li>Select Overviewul>li>Copy the Virtual IP private IP. You will needs this below/li>/ul>/li>/ul>/li>li>Navigate to the Virtual Machine resource created above/li>li>Select strong>Connect/strong> under Settingsbr />img decodingasync srchttps://www.danturco.com/wp/wp-content/uploads/2020/07/image-1594491253769.png altVM Connect />/li>li>Select RDP and click strong>Download RDP File/strong>/li>li>Login to VM with the UserName and Password you created while setting up the VM above/li>li>p>In windows explorer/p>ul>li>Open folder C:\Windows\System32\drivers\etc\/li>li>Open the hosts file with notepad.exe/li>li>Add the following to the bottom of the file/li>/ul>pre>code classlanguage-TEXT><APIM private IP> api.contoso.azure-api.net<APIM private IP> api.contoso.portal.azure-api.net<APIM private IP> api.contoso.developer.azure-api.net<APIM private IP> api.contoso.management.azure-api.net<APIM private IP> api.contoso.scm.azure-api.net/code>/pre>/li>li>Testing the connectionul>li>Open the browser and navigate toul>li>a hrefhttps://api.contoso.portal.azure-api.net/>https://api.contoso.portal.azure-api.net//a>/li>li>Signup for an account/li>li>Select APIS/li>li>Select Echo APIbr />img decodingasync srchttps://www.danturco.com/wp/wp-content/uploads/2020/07/image-1594491955576.png altEcho API />/li>li>Select Retrieve resourcebr />img decodingasync srchttps://www.danturco.com/wp/wp-content/uploads/2020/07/image-1594492141210.png altRetrieve Resource API CAll />/li>li>Enter your subscription key to test the callul>li>If your not sure how check out a hrefhttps://docs.microsoft.com/en-us/azure/api-management/api-management-howto-create-subscriptions>Creating Subscriptions in API Manager/a>/li>/ul>/li>li>Execute the call.br />img decodingasync srchttps://www.danturco.com/wp/wp-content/uploads/2020/07/image-1594492292364.png altSuccess />/li>li>If you received a 200 status code you have successfully configure API Manager to run internal on a VNET/li>/ul>/li>/ul>/li>/ol>h3>Setting up Application Gateway/h3>ol>li>Navigate to a hrefhttps://portal.azure.com/#create/Microsoft.ApplicationGateway-ARM>Application Gateway/a>/li>li>Select the Resource Group create from aboveul>li>rg-contoso-api-dev-eastus/li>/ul>/li>li>Enter the gateway nameul>li>agw-contoso-api-dev-eastus/li>/ul>/li>li>Enter regionul>li>East US/li>/ul>/li>li>Select Tier based on your needs. If possible choose V2 types/li>li>Under strong>Configure Virtual Network/strong>ul>li>Select the VNET created above (vnet-contoso-dev-eastus)/li>li>Select the subnetul>li>snet-contoso-gw-dev-eastus/li>/ul>/li>/ul>/li>li>Click Frontendsol>li>Select strong>Public/strong> for address typebr />img decodingasync srchttps://www.danturco.com/wp/wp-content/uploads/2020/07/image-1594493038822.png altPublic IP Address Type />/li>li>Create a new public IP address/li>/ol>ul>li>ip-contoso-gw-dev-eastus/li>/ul>/li>li>Click Backendsol>li>Select strong>Add a backend pool/strong>ol>li>Enter nameol>li>backend-asp-api-dev-eastus/li>/ol>/li>li>Add Targetol>li>Target type: strong>IP Address or FQDN/strong>/li>li>Target: strong>api.contoso.azure-api.net/strong>/li>/ol>/li>/ol>/li>/ol>/li>li>Click Configurationol>li>Select strong>Add a routing rule/strong>/li>/ol>ul>li>Enter Nameul>li>rule-https-backend-asp-api-dev-eastus/li>/ul>/li>li>Under the Listeners Tabul>li>Enter Listener Nameul>li>https-listener/li>/ul>/li>li>Enter Frontend IPul>li>Select the IP created from the earlier step/li>/ul>/li>li>Protocolul>li>Select HTTPS/li>/ul>/li>li>Http Settingsol>li>Lets get the certificate we need. For this we can use a self-signed certificate to secure the incoming requests/li>/ol>ul>li>Open a Powershell Command promptpre>code classlanguage-Powershell>br />New-SelfSignedCertificate -certstorelocation cert:\localmachine\my -dnsname api.contoso.com$pwd ConvertTo-SecureString -String Password$ -Force -AsPlainTextExport-PfxCertificate -cert cert:\localMachine\my\<COPY FROM OUTPUT ABOVE> -FilePath c:\api-contoso-gw-cert.pfx -Password $pwd/code>/pre>/li>/ul>ol>li>Upload the created certificate/li>li>Enter a cert name/li>/ol>ul>li>self-cert-contoso-api-gwol>li>Enter the password used from Powershell/li>li>Click strong>Add/strong>/li>/ol>/li>/ul>/li>li>Under the Backend targetsul>li>Select Target type strong>Backend pool/strong>/li>li>Select the backend pool created above/li>li>Select strong>Add new/strong> for Http settingul>li>Enter HTTP setting name/li>li>apim-contoso-https-dev-eastus/li>li>Backend protocol/li>li>HTTPS/li>li>Use well known CA certificate/li>li>NO/li>li>Getting the .cer to upload/li>/ul>ol>li>Remote into the Jumpbox/li>li>Open the browser and navigate to/li>/ol>ul>li>a hrefhttps://api.contoso.portal.azure-api.net/>https://api.contoso.portal.azure-api.net//a>/li>li>Click on the secure connection icon in the browser. Select Certificatebr /> img decodingasync srchttps://www.danturco.com/wp/wp-content/uploads/2020/07/image-1594493589860.png altCertificate />/li>li>Click details tab and strong>Copy to File/strong>br /> img decodingasync srchttps://www.danturco.com/wp/wp-content/uploads/2020/07/image-1594493658618.png altCertificate Details />/p>ul>li>In the export wizard. The exported file format should be Base-64-encoded X.509 (.VER)br />img decodingasync srchttps://www.danturco.com/wp/wp-content/uploads/2020/07/image-1594493705640.png altfile />/li>li>Enter a file nameul>li>api-contoso-dev-eastus.cer/li>/ul>/li>li>Copy this file from the Jumpbox the where you are creating the Application Gateway aboveul>li>Override with new host name/li>li>YES/li>li>Host name override/li>li>Override with specific domain name/li>li>api.contoso.azure-api.net/li>li>Click strong>Add/strong>br />img decodingasync srchttps://www.danturco.com/wp/wp-content/uploads/2020/07/image-1594495430950.png altAdd HTTP Setting />/li>/ul>/li>/ul>/li>/ul>/li>li>Click strong>Add/strong>/li>/ul>ol>li>Click Review + Create/li>li>Configuring the Custom health probe/li>/ol>ul>li>Goto the Application Resource created above (agw-contoso-api-dev-eastus)/li>/ul>/li>li>Select Health probesbr />img decodingasync srchttps://www.danturco.com/wp/wp-content/uploads/2020/07/image-1594496599594.png altHealth probes />/li>li>A custom probe should have been created but it needs some tweaking to get it to validate against API Manager/li>li>Hostul>li>api-contoso.azure-api.net/li>/ul>/li>li>Pick host name from backend HTTP settingsul>li>No/li>/ul>/li>li>Pathul>li>/status-0123456789abcdef/li>li>This is APIM static health check endpoint on any instance/li>/ul>/li>li>Use probe matching conditionsul>li>Yes/li>/ul>/li>li>Http status code matchul>li>200-399br />img decodingasync srchttps://www.danturco.com/wp/wp-content/uploads/2020/07/image-1594496905237.png altHealth probe settings />/li>/ul>ol>li>Verify Application Gateway and Backend pool can connect/li>/ol>ul>li>Select Backend healthbr />img decodingasync srchttps://www.danturco.com/wp/wp-content/uploads/2020/07/image-1594495944065.png altBackend Health />/li>/ul>/li>li>If all checks out and everything is configured correctly should get a healthy statusbr />img decodingasync srchttps://www.danturco.com/wp/wp-content/uploads/2020/07/image-1594495983211.png altHealthy Status />/li>/ul>/li>/ul>/li>/ol>h3>Testing An API Call/h3>p>To test everything is connected run the following cURL command/p>pre>code classlanguage-Powershell>br />curl --location --request GET https://<APPLICATION GATEWAY PUBLIC IP>/echo/resource?param1sample \--header Ocp-Apim-Subscription-Key: <YOUR APIM SUBSCRIPTION KEY>/code>/pre>h3>Final Thoughts/h3>p>Hopefully this has helped get everything configured and up and running./p>h4>Resources/h4>p>a hrefhttps://docs.microsoft.com/en-us/azure/api-management/api-management-using-with-internal-vnet>https://docs.microsoft.com/en-us/azure/api-management/api-management-using-with-internal-vnet/a>/p>p>a hrefhttps://docs.microsoft.com/en-us/azure/api-management/api-management-howto-integrate-internal-vnet-appgateway>https://docs.microsoft.com/en-us/azure/api-management/api-management-howto-integrate-internal-vnet-appgateway/a>/p>p>a hrefhttps://techcommunity.microsoft.com/t5/azure-paas-developer-blog/integrating-api-management-with-app-gateway-v2/ba-p/1241650>https://techcommunity.microsoft.com/t5/azure-paas-developer-blog/integrating-api-management-with-app-gateway-v2/ba-p/1241650/a>/p>p>a hrefhttps://docs.microsoft.com/en-us/azure/application-gateway/certificates-for-backend-authentication#export-trusted-root-certificate-for-v2-sku>https://docs.microsoft.com/en-us/azure/application-gateway/certificates-for-backend-authentication#export-trusted-root-certificate-for-v2-sku/a>/p>p>a hrefhttps://azure.microsoft.com/en-us/updates/azure-application-gateway-standardv2-wafv2-skus-generally-available/>https://azure.microsoft.com/en-us/updates/azure-application-gateway-standardv2-wafv2-skus-generally-available//a>/p>p>a hrefhttp://thewindowsupdate.com/2020/03/20/integrating-api-management-with-app-gateway/>http://thewindowsupdate.com/2020/03/20/integrating-api-management-with-app-gateway//a>/p>p>a hrefhttps://docs.microsoft.com/en-us/azure/api-management/api-management-howto-mutual-certificates#feedback>https://docs.microsoft.com/en-us/azure/api-management/api-management-howto-mutual-certificates#feedback/a>/p>p>a hrefhttps://fabriciosanchez-en.azurewebsites.net/protecting-apis-with-api-management-and-application-gateway/>https://fabriciosanchez-en.azurewebsites.net/protecting-apis-with-api-management-and-application-gateway//a>/p> /div> /div>!-- .entry-content --> footer classentry-footer> span classcat-links> Posted in a hrefhttps://www.danturco.com/category/howd-they-do-that/ relcategory tag>Howd they do that/a> /span> span classtags-links> Tagged a hrefhttps://www.danturco.com/tag/api-manager/ reltag>Api Manager/a>, a hrefhttps://www.danturco.com/tag/azure/ reltag>Azure/a>, a hrefhttps://www.danturco.com/tag/azure-app-services/ reltag>Azure App Services/a>, a hrefhttps://www.danturco.com/tag/azure-application-gateway/ reltag>Azure Application Gateway/a>, a hrefhttps://www.danturco.com/tag/https/ reltag>Https/a>, a hrefhttps://www.danturco.com/tag/secure/ reltag>Secure/a>, a hrefhttps://www.danturco.com/tag/ssl/ reltag>SSL/a>, a hrefhttps://www.danturco.com/tag/virtual-network/ reltag>Virtual Network/a>, a hrefhttps://www.danturco.com/tag/vnet/ reltag>Vnet/a> /span> /footer>!-- .entry-footer -->/article>!-- #post-## --> article idpost-213 classpost-213 post type-post status-publish format-standard hentry category-howd-they-do-that tag-apis tag-automation tag-github tag-postman tag-qa tag-testing> header classentry-header> /header>!-- .entry-header --> div classentry-content> a hrefhttps://www.danturco.com/custom-bulk-variables-in-postman/ classdate> span classday>11/span> span classmonth>Jul/span> /a> h1 classentry-title>a hrefhttps://www.danturco.com/custom-bulk-variables-in-postman/ relbookmark>Custom Bulk Variables in Postman/a>/h1> div classentry-text> h1>Custom variables in Postman using Github/h1>h2>Summary/h2>p>We created this implementation to address some of the short-comings in Postman variable management. The first issue was how to mass update variables within postman with the removal of the bulk edit feature, while not having to deal with the massive custom JSON object that is the data backing to the current Postman bulk edit modal. The second issue was how to keep our entire teams variables up to date and in sync for values that were required for API testing but that changed over time. Using team templates is not user friendly, and requires multiple new imports to re-sync variables, which also then forces you to lose any one off variable changes made./p>p>This implementation provides the following advantages:/p>ol>li>Change tracking/li>li>Edit history/li>li>Real time updating of shared variables/li>/ol>h2>Setup Summary/h2>ol>li>Create new Github Repository for storing the variable files/li>li>Add a new post request to your Postman collection for base-lining variables/li>li>Adde the Pre-script and post-script code to that baseline request/li>/ol>h2>GitHub files and structure/h2>ol>li>Create a repository named strong>Postman-Variables/strong>/li>li>Setup the following folder structurep>a hrefhttps://github.com/d1820/PostmanVariablesSample/blob/master/documentation/PostmanGitFolders.jpg?rawtrue>img decodingasync srchttps://github.com/d1820/PostmanVariablesSample/blob/master/documentation/PostmanGitFolders.jpg?rawtrue alt />/a>/p>/li>li>Create JSON files in each user folder that should be applied to postman when base-lining for each given environment./li>/ol>h3>Variable Scopes/h3>ol>li>strong>Global/strong>: Contains variables that are required per the environment and rarely change./li>li>strong>Shared/strong>: Contains all variables that are not considered global. When a new variable is created by a developer it should be added here for each environment file. This will make it available for all Postman Users./li>li>strong>User/strong>: This contains static user specific overrides. These will overwrite the shared variable of the same key if it exists. Every user will have a folder containing their specific overrides./li>/ol>p>strong>Note/strong>: Global variables are overridden by shared variables, which are overridden by User variables./p>h3>File structure/h3>p>In each of the folders add your variables in this format/p>pre>code classlanguage-JSON> { key: <VARNAME>, value: <VALUE> }/code>/pre>h3>Setting up access/h3>ol>li>In Github under the account go to settings/li>li>Select Developer Settings/li>li>Create a new OAuth Applicationul>li>Ensure public repo access is checked/li>/ul>/li>li>Save the ClientId and ClientSecret created for use later in Postman/li>/ol>h2>Setup Postman/h2>h3>Update Postman Settings/h3>ul>li>Set strong>Automatically persist variable values/strong> is set to ON/li>/ul>p>a hrefhttps://github.com/d1820/PostmanVariablesSample/blob/master/documentation/PostmanSettings.jpg?rawtrue>img decodingasync srchttps://github.com/d1820/PostmanVariablesSample/blob/master/documentation/PostmanSettings.jpg?rawtrue alt />/a>/p>h2>Create the baseline environment templates/h2>p>Create the following environments/p>ol>li>LocalVariables/li>li>DevVariables/li>li>QAVariables/li>/ol>p>a hrefhttps://github.com/d1820/PostmanVariablesSample/blob/master/documentation/PostmanManageEnv.jpg?rawtrue>img decodingasync srchttps://github.com/d1820/PostmanVariablesSample/blob/master/documentation/PostmanManageEnv.jpg?rawtrue alt />/a>/p>p>Add the following variables to each template within postman/p>ul>li>strong>environment/strong>: this value will match the folder names from your GitHub repository structure you created above/li>li>strong>username/strong>: this is the username of the folder in the github repository that contains the specific variables to retrieve/li>/ul>p>a hrefhttps://github.com/d1820/PostmanVariablesSample/blob/master/documentation/PostmanVariablesRequired.jpg?rawtrue>img decodingasync srchttps://github.com/d1820/PostmanVariablesSample/blob/master/documentation/PostmanVariablesRequired.jpg?rawtrue alt />/a>/p>p>strong>NOTE:/strong> if working in Postman team import each of those environment templates into your workspace as a duplicate/p>h3>Setup Collection Global Variables/h3>p>In your collection we need to add a couple global variables that will allow access across environments to gather our github stored variables/p>p>Add the following global variables/p>ul>li>baseGithubUrl – base url for access the files in github/li>li>globalVariablesPath – Relative path in the repo to the global variable files/li>li>sharedVariablesPath – Relative path in the repo to the shared variable files/li>li>githubClientId – Client id generated above from GitHub/li>li>githubClientSecret – Client secret generated above from GitHub/li>li>githubUser – Github account housing the variables repo/li>li>githubRepoName – Name of the repo created to house the variables/li>/ul>p>a hrefhttps://github.com/d1820/PostmanVariablesSample/blob/master/documentation/PostmanGlobalVars.jpg?rawtrue>img decodingasync srchttps://github.com/d1820/PostmanVariablesSample/blob/master/documentation/PostmanGlobalVars.jpg?rawtrue alt />/a>/p>h4>Validating access/h4>p>To ensure we have access to the Github repository based on the variables above we can test with the following postman GET request url/p>pre>code classlanguage-TEXT>{{baseGithubUrl}}{{githubUser}}/{{githubRepoName}}/master/Global/{{environment}}.json?client_id{{githubClientId}}&client_secret{{githubClientSecret}}/code>/pre>p>If all is connected correctly Postman should returnbr />a hrefhttps://github.com/d1820/PostmanVariablesSample/blob/master/documentation/PostmanTestConnection.jpg?rawtrue>img decodingasync srchttps://github.com/d1820/PostmanVariablesSample/blob/master/documentation/PostmanTestConnection.jpg?rawtrue alt />/a>/p>h3>Setup the baseline variable request/h3>ol>li>Create a new folder in your collection strong>Baseline Environment Variables/strong>/li>li>Create a new GET requestul>li>Set the url to/li>/ul>/li>/ol>pre>code classlanguage-TEXT>{{baseGithubUrl}}{{githubUser}}/{{githubRepoName}}/master/Users/{{username}}/{{environment}}.json?client_id{{githubClientId}}&client_secret{{githubClientSecret}}/code>/pre>ol>li>Edit the folder and add the following to the strong>Pre-request Scripts/strong>pre>code classlanguage-JAVASCRIPT>var baseGithubUrl pm.variables.get(baseGithubUrl);var githubUser pm.variables.get(githubUser);var githubRepoName pm.variables.get(githubRepoName);var githubClientId pm.variables.get(githubClientId);var githubClientSecret pm.variables.get(githubClientSecret);var authQueryString ?client_id + githubClientId + &client_secret + githubClientSecret;var baseUrl baseGithubUrl + githubUser+/ + githubRepoName + /master/;var globalVariablesUrl pm.variables.get(globalVariablesPath).replace({0}, pm.variables.get(environment));var sharedVariablesUrl pm.variables.get(sharedVariablesPath).replace({0}, pm.variables.get(environment));pm.sendRequest({ url: baseUrl + globalVariablesUrl, method: GET,}, function (err, response) { if(err){ console.error(Pre-Request Error, err, response.text()); } var globalBaseline response.json(); globalBaseline.forEach(function(item) { pm.environment.set(item.key, item.value); }); //now get any shared overrides to the global requests pm.sendRequest({ url: baseUrl + sharedVariablesUrl, method: GET, }, function (err, response) { if(err){ console.error(Pre-Request Error, err, response.text()); } var sharedVariables response.json(); sharedVariables.forEach(function(item) { pm.environment.set(item.key, item.value); }); });});/code>/pre>/li>li>Update the strong>Tests/strong> tab in the request withpre>code classlanguage-JAVASCRIPT>var userOverrides pm.response.json();userOverrides.forEach(function(item) { pm.environment.set(item.key, item.value);});/code>/pre>/li>/ol>p>The final request should look like/p>p>a hrefhttps://github.com/d1820/PostmanVariablesSample/blob/master/documentation/PostmanVarRequest.jpg?rawtrue>img decodingasync srchttps://github.com/d1820/PostmanVariablesSample/blob/master/documentation/PostmanVarRequest.jpg?rawtrue alt />/a>/p>p>If you now check the variables list it will show all the imported variables from GLOBAL, SHARED and USER/p>p>a hrefhttps://github.com/d1820/PostmanVariablesSample/blob/master/documentation/PostmanVarsSetAfterRequest.jpg?rawtrue>img decodingasync srchttps://github.com/d1820/PostmanVariablesSample/blob/master/documentation/PostmanVarsSetAfterRequest.jpg?rawtrue alt />/a>/p>h2>How to use/h2>p>To take advantage of this system we implemented the following workflow/p>p>As a developer we would clone the repo locally and update all profiles and Gloabl and Shared files as necessary when API changes happened that would effect current settings. Then everyone only had to strong>Get Latest/strong> to get those updates and use locally./p>p>As a QA tester, they were given rights to the GitHub repo and allowed to update their userName folder files and set what ever baseline variables they wanted for their testing purposes and commit those changes./p>p>As API changes moved that required Postman value changes moved through the environments we would all as a team "Baseline" for the given environment which would update the GLOBAL and SHARED values for everyone. This has really helped with syncing new values for new APIs and updating clientIds and stuff based on API changes. This has also allowed for helping QA through issues cause we can easily pull their username files down locally and we have everything in our local environment the QA has and we an see what values may be off and correct them./p>p>The great thing is this does not affect how Postman already works with variables so we can still customize per request as im scenario testing just like we regularly do. We strong>ONLY/strong> baseline when something on a wider scale has changed in an API as part of our regular planned sprint work. The power then also comes with the username custom variables so if we have personal values and stuff only for me those are all tracked in source control only our team has access to and has history to them all to so rollback is easily accomplished at this point./p>h2>References/h2>ul>li>a hrefhttps://developer.github.com/v3/#http-verbs>Github API/a>/li>li>a hrefhttps://auth0.com/docs/connections/social/github>Creating an OAuth App in Github/a>/li>li>a hrefhttps://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/>Request OAuth token from API/a>/li>/ul>p>All screen shots taken running strong>localVariables/strong> as the environment/p>p>Want a head start grab the source from a hrefhttps://github.com/d1820/PostmanVariablesSample>my Github/a>/p> /div> /div>!-- .entry-content --> footer classentry-footer> span classcat-links> Posted in a hrefhttps://www.danturco.com/category/howd-they-do-that/ relcategory tag>Howd they do that/a> /span> span classtags-links> Tagged a hrefhttps://www.danturco.com/tag/apis/ reltag>Apis/a>, a hrefhttps://www.danturco.com/tag/automation/ reltag>Automation/a>, a hrefhttps://www.danturco.com/tag/github/ reltag>Github/a>, a hrefhttps://www.danturco.com/tag/postman/ reltag>Postman/a>, a hrefhttps://www.danturco.com/tag/qa/ reltag>QA/a>, a hrefhttps://www.danturco.com/tag/testing/ reltag>Testing/a> /span> /footer>!-- .entry-footer -->/article>!-- #post-## --> article idpost-100 classpost-100 post type-post status-publish format-standard hentry category-howd-they-do-that tag-development tag-linting tag-typescript tag-vscode> header classentry-header> /header>!-- .entry-header --> div classentry-content> a hrefhttps://www.danturco.com/vscode-and-tslint-tasks/ classdate> span classday>23/span> span classmonth>Jun/span> /a> h1 classentry-title>a hrefhttps://www.danturco.com/vscode-and-tslint-tasks/ relbookmark>VSCode and TSLint tasks/a>/h1> div classentry-text> p>I was trying to get full project linting to happen using the a hrefhttps://marketplace.visualstudio.com/items?itemNameeg2.tslint>TSLint Visual Studio Extension/a>, but it currently only does one file at a time, for the files that are all open. To TSLint the whole project you need to setup a VSCode Task./p>h2>Installing Required Packages/h2>pre>code>npm install -g tslint typescript/code>/pre>h2>Settings Up the Task/h2>ol>li>In VSCode hit F1 and type task/li>li>Select “Configure Task Runner”/li>li>Select Typescript/li>/ol>p>In the tasks.json file add the following/p>pre>code> { version: 0.1.0, command: tslint, isShellCommand: true, echoCommand: true, args: --format prose, --project ${workspaceRoot}/tsconfig.json, --type-check, ${workspaceRoot}/src/**/*.ts , showOutput: silent, isBackground: true, problemMatcher: $tslint4 }/code>/pre>p>Run the task in VSCode, the output will show in the output tab and in the Problem tab as well./p>p>Happy Linting./p> /div> /div>!-- .entry-content --> footer classentry-footer> span classcat-links> Posted in a hrefhttps://www.danturco.com/category/howd-they-do-that/ relcategory tag>Howd they do that/a> /span> span classtags-links> Tagged a hrefhttps://www.danturco.com/tag/development/ reltag>Development/a>, a hrefhttps://www.danturco.com/tag/linting/ reltag>LInting/a>, a hrefhttps://www.danturco.com/tag/typescript/ reltag>Typescript/a>, a hrefhttps://www.danturco.com/tag/vscode/ reltag>VSCode/a> /span> /footer>!-- .entry-footer -->/article>!-- #post-## --> article idpost-78 classpost-78 post type-post status-publish format-standard hentry category-howd-they-do-that tag-angular-4 tag-javascript tag-observables tag-rxjs tag-spa-applications tag-web-forms> header classentry-header> /header>!-- .entry-header --> div classentry-content> a hrefhttps://www.danturco.com/watching-for-changes-with-reactive-forms-in-angular4/ classdate> span classday>5/span> span classmonth>May/span> /a> h1 classentry-title>a hrefhttps://www.danturco.com/watching-for-changes-with-reactive-forms-in-angular4/ relbookmark>Watching for changes with Reactive Forms in Angular4/a>/h1> div classentry-text> h2>Problem/h2>p>On a recent project working with Angular 4 and reactive forms a need came up to allow child components ( which were driven off off their own child form groups) be be able to detect value changes to other child components. From these changes we needed to apply rules and detect validity of the values./p>h2>Now I know your thinking/h2>p>So your first response is probably duh thats what valueChange subscriptions are for, and you are totally correct. What started to happen though was a huge duplication of code across many components for not only detecting changes (valueChanges) but also detecting the validity of those changes (statusChanges). What we needed was a consolidated way to detect changes and validity across the entire parent form group and be able to deliver those changes to any sub components./p>h2>Enter the watcher service/h2>p>With the help of RXjs a hrefhttp://reactivex.io/rxjs/class/es6/Observable.js~Observable.html>Observables/a> we were able to provide a single watch point that any component in the entire application could subscribe to to get any changes from any component. This service would deliver not only value changes but validity status changes as well. GoodBye code duplication I’m staying a hrefhttps://en.wikipedia.org/wiki/Don%27t_repeat_yourself>strong>dry/strong>/a> in this code storm./p>h4>Service Code/h4>pre>code>import {Injectable} from @angular/core;import {AbstractControl, FormControl, FormGroup} from @angular/forms;import {BehaviorSubject} from rxjs/BehaviorSubject;import {Observable} from rxjs/Observable;import {Subscription} from rxjs/Rx;declare let _;export interface FormGroupChange { path: string; name: string; control: FormControl;}/* Allows you to subscribe to value and status changes for fields in a FormGroup. Events are debounced to avoid too many simultaneous calls, and are emitted even when the validity of a field updates because of dependencies on other fields. Usage: let subscription this.watchFormGroupService.watch(this.formGroup, personalInformation.firstName, personalInformation.lastName) .subscribe((data: FormGroupChange) > { // ... }); // Dont forget to unsubscribe! (eg. in ngOnDestroy) subscription.unsubscribe(); */@Injectable()export class WatchFormGroupService { private MAX_CHECK_COUNT 5; public watch(formGroup: FormGroup, paths: string, debounce 400): Observable<FormGroupChange> { return Observable.create(observer > { let internalSubs ; paths.map(path > { let control formGroup.root.get(path); if(!control) { let checkCount 0 // lets give angular some time to finalize the form groups and make them available. This happens due to race conditions with when different components can // load and when watchers are setup from other components. let checkAgainInterval setInterval(() > { let control formGroup.root.get(path); if(control) { clearInterval(checkAgainInterval); let eventData: FormGroupChange { path: path, name: _.last(path.split(.)), control: control }; let subject new BehaviorSubject(eventData); internalSubs.push(Observable.merge(...control.valueChanges, control.statusChanges, subject).debounceTime(debounce).map(data > { observer.next(eventData); }).subscribe()); } if(checkCount > this.MAX_CHECK_COUNT) { console.warn(NO WATCHER PATH MATCH, path); clearInterval(checkAgainInterval); } checkCount++; }, 1000); } else { let eventData: FormGroupChange { path: path, name: _.last(path.split(.)), control: control }; let subject new BehaviorSubject(eventData); internalSubs.push(Observable.merge(...control.valueChanges, control.statusChanges, subject).debounceTime(debounce).map(data > { observer.next(eventData); }).subscribe()); } }); // Provide a way of canceling and disposing the interval resource return function unsubscribe() { _.forEach(internalSubs, sub > { sub.unsubscribe(); }); }; }); }}/code>/pre>p>Now one caveat to this was we need to know which child component and form control to watch on. With no other real way around it we agreed that using the dot notation to a component and field as a string while is ‘hard coded’ was the best balance between ease of use and pseudo coupling of components. Coupling in this case i feel is loosely said, because if the component doesn’t exist in the view, but its subscribed to, nothing will be broadcasted anyway./p>h2>So how do we use this thing/h2>p>In any of your components you simply inject the WatchFormGroupService and watch on an array of fields./p>p>strong>NOTE:/strong> registration must be in the AfterViewInit or later, so all the form groups have time to build and setup from the OnInit event. This is important because when listening across all components we do not know when the form group will be ready from initialization./p>p>What is great about the WatchFormGroupService is that it can work with many first class form group citizens (meaning you can watch different un-related form groups from the same application)./p>pre>code> ngAfterViewInit() { this.watcherSubscription this.watchFormGroupService.watch(this.formGroup, personalInformation.mailingAddress.address1, personalInformation.mailingAddress.address2, personalInformation.mailingAddress.address3, personalInformation.mailingAddress.zipcode, personalInformation.mailingAddress.state, personalInformation.mailingAddress.city ).subscribe(data > { if(data.control.value.isValid){ this.formDatadata.name data.control.value; this.formGroup.get(childInformation) .get(my.address).get(data.name) .patchValue(data.control.value); } } }); }/code>/pre>p>In this example we are listening for address changes in the personalInformation component and then updating "my" component with the new values, but only if the value coming in is valid. While there would be more logic around when to update the value this code at least shows what is possible with the WatchFormGroupService/p>h3>Cleanup/h3>p>One thing to call out as with using any RSjs Observable, make sure you clean up your subscriptions. In OnDestroy of the watching component unsubscribe from the watcher service/p>pre>code> ngOnDestroy() { this.watcherSubscription.unsubscribe(); }/code>/pre>p>I want to give a shout out to a hrefhttps://github.com/brombal>Alex Brombal/a> who I collaborated with on the concept. He was the lucky one who got to write the WatchFormGroupService./p>p>Check this out in action on a hrefhttps://embed.plnkr.co/CLMOzI/>Plunkr/a>/p>h3>UPDATE/h3>p>Since I first published this a couple changes have been made to the WatchFormGroupService. We needed a way for subscribers to get values on the initial subscribe from from the service. This would be in the case the formGroup was loaded from database data, and a valueChange event has not fired yet. To accomplish this we added in a BehaviorSubject and loaded it with the initial value from the formControl./p>pre>code> public watch(formGroup: FormGroup, paths: string, debounce 400): Observable<FormGroupChange> { return Observable.merge(...paths.map(path > { let control formGroup.root.get(path); if (!control) { console.warn(NO WATCHER PATH MATCH, path); return Observable.empty(); } let eventData { path: path, name: _.last(path.split(.)), control: control }; let subject new BehaviorSubject(eventData); return Observable.merge(...control.valueChanges, control.statusChanges, subject).debounceTime(debounce).map(data > eventData); })); }/code>/pre> /div> /div>!-- .entry-content --> footer classentry-footer> span classcat-links> Posted in a hrefhttps://www.danturco.com/category/howd-they-do-that/ relcategory tag>Howd they do that/a> /span> span classtags-links> Tagged a hrefhttps://www.danturco.com/tag/angular-4/ reltag>angular 4/a>, a hrefhttps://www.danturco.com/tag/javascript/ reltag>Javascript/a>, a hrefhttps://www.danturco.com/tag/observables/ reltag>Observables/a>, a hrefhttps://www.danturco.com/tag/rxjs/ reltag>Rxjs/a>, a hrefhttps://www.danturco.com/tag/spa-applications/ reltag>SPA Applications/a>, a hrefhttps://www.danturco.com/tag/web-forms/ reltag>web forms/a> /span> /footer>!-- .entry-footer -->/article>!-- #post-## --> article idpost-74 classpost-74 post type-post status-publish format-standard hentry category-howd-they-do-that tag-angular tag-angular-4 tag-client-application tag-directives tag-dnd tag-dragndrop tag-javascript tag-nddragula tag-ngprime> header classentry-header> /header>!-- .entry-header --> div classentry-content> a hrefhttps://www.danturco.com/using-ngdragula-with-ngprime-from-angular-4/ classdate> span classday>1/span> span classmonth>Apr/span> /a> h1 classentry-title>a hrefhttps://www.danturco.com/using-ngdragula-with-ngprime-from-angular-4/ relbookmark>Using ngDragula with ngPrime from Angular 4/a>/h1> div classentry-text> p>Recently on a project I had the requirement to provided table row reordering. The challenge to that was getting access to the table rows that were created dynamically at runtime and within an a hrefhttps://www.primefaces.org/primeng/>ngPrime/a> data table. To provide the drag and drop support I turned to a hrefhttp://valor-software.com/ng2-dragula/>ngDragula/a>. This is a great plugin that provides plenty of events and html support. One thing it currently does not provide is the ability to override the container it uses for setting up the drag and drop. It currently only can use the element that the directive was placed on. As you can see with the use of 3rd party components placing the directive in the proper place can be a challenge./p>p>To address these short comings in my project I created my own version of the ngDragula Directive. Lets walk through what you need to do to add support for drag and drop to your ngPrime data tables./p>h2>Creating your own ngDragula Directive/h2>p>To add support for integration with ngPrime a couple of things need to happen. First we need to override the container that dragula will attach to. In regards to drag and drop with tables the container needs to be the closest parent to the items you want to drag. In our case that ends up being the tbody element. Unfortunately ngPrime data tables do not allow access to this element, so we have no way to place the dragula directive in the correct location. Secondly we need to allow for delayed binding to the data table. Since we provide a collection of rows to the ngPrime data table the tbody tag will not be available onInit of the component. To make this work we need to bind the ngDragula directive after the view is available from Angular. Luckily Angular provides us with the AfterViewInit lifecycle hook. Lets take a look at the code./p>p>The first thing we need to do is create our own version of the ngDragula directive. ensure you give it a unique name that wont clash with existing libs. Also add AfterViewInit to the implements of the class/p>pre>code>import { Directive, OnChanges, AfterViewInit, OnInit, Input, ElementRef, SimpleChange } from @angular/core;import { DragulaService, dragula } from ng2-dragula;@Directive({ selector: primeDragula })export class PrimeDragulaDirective implements OnChanges, OnInit, AfterViewInit { }/code>/pre>p>Next we change the container to protected so we can provide extension later/p>pre>code> protected container: any;/code>/pre>p>Now we can implement the Angular events OnInit, AfterViewInit. In OnInit we wire up the options, and set the initial container element. New options that can be provided to the directive are ‘initAfterView’ and ‘childContainerSelector’. Here we check to see if late binding is needed and if not initialize the directive like usual. If late binding is needed AfterViewInit handles that check./p>pre>code>ngOnInit(){ this.options Object.assign({}, this.dragulaOptions); this.container this.el.nativeElement; if(!this.options.initAfterView){ this.initialize(); } } ngAfterViewInit() { if(this.options.initAfterView){ this.initialize(); } }/code>/pre>p>Lets move the initialization code to its own method for reuse. Here the only new code is the ‘childContainerSelector’ check this is what gives us the ability to use a different container then the one the ngDragula directive was placed on. Notice how we set the mirrorContainer as well. This is because since the container is a sub element of the parent we want to ensure mirror object (the drag object visual that shows the movement) is positioned relative to the correct parent./p>p>b>NOTE/b>: an upgrade to this directive would be to use another property to dictate overriding the defauly mirrorContainer ‘document.body’/p>pre>code> protected initialize(){ if(this.options.childContainerSelector){ //find the element starting at the directive element and search down this.container this.el.nativeElement.querySelector(this.options.childContainerSelector); this.options.mirrorContainer this.container; } let bag this.dragulaService.find(this.primeDragula); let checkModel () > { if (this.dragulaModel) { if (this.drake.models) { this.drake.models.push(this.dragulaModel); } else { this.drake.models this.dragulaModel; } } }; if (bag) { this.drake bag.drake; checkModel(); this.drake.containers.push(this.container); } else { this.drake dragula(this.container, this.options); checkModel(); this.dragulaService.add(this.primeDragula, this.drake); } }/code>/pre>p>Finally, add in the pre-existing OnChanges method from the ngDragula directive/p>pre>code>public ngOnChanges(changes: { dragulaModel?: SimpleChange }): void { if (changes && changes.dragulaModel) { if (this.drake) { if (this.drake.models) { let modelIndex this.drake.models.indexOf(changes.dragulaModel.previousValue); this.drake.models.splice(modelIndex, 1, changes.dragulaModel.currentValue); } else { this.drake.models changes.dragulaModel.currentValue; } } } }/code>/pre>h2>Using the new directive/h2>p>So now the directive is create we are ready to implement it./p>p>In our component template where we define our ngPrime data table lets add the dragula directive./p>pre>code> <p-dataTable valuerows primeDragulabag dragulaModelrows dragulaOptions{ childContainerSelector: tbody, initAfterView: true }> <p-column headerMove> <ng-template pTemplatebody let-rowDatarowData> <i classfa fa-bars></i> </ng-template> </p-column> <p-column fieldname headerName> </p-column> </p-dataTable>/code>/pre>p>That is all there is to it. Pretty simple changes that allow a greater user experience./p>h2>Gotcha’s:/h2>ul>li>Dont forget to add the a hrefhttps://github.com/bevacqua/dragula>javascript dragula version/a> to your package.json and angular CLI styles and scripts sections. This is a requirement for ngDragula to work as expected./li>/ul>h2>Versions used/h2>pre>code>@angular/animations: 4.0.0,@angular/common: 4.0.0,@angular/compiler: 4.0.0,@angular/core: 4.0.0,@angular/forms: 4.0.0,@angular/http: 4.0.0,@angular/platform-browser: 4.0.0,@angular/platform-browser-dynamic: 4.0.0,@angular/router: 4.0.0,dragula: ^3.7.2,lodash: 4.17.4,ng2-dragula: ^1.3.0,primeng: 2.0.5,rxjs: 5.1.0,zone.js: 0.8.4/code>/pre>p>Hopefully you found this helpful. You can see a working example here on a hrefhttps://embed.plnkr.co/Mivcv5/>Plunkr/a>. Also these changes have been submitted for review to the guys over at a hrefhttps://github.com/valor-software/ng2-dragula>valor-software/a>. With a little luck I can just use the official version of ngDragula one day!/p> /div> /div>!-- .entry-content --> footer classentry-footer> span classcat-links> Posted in a hrefhttps://www.danturco.com/category/howd-they-do-that/ relcategory tag>Howd they do that/a> /span> span classtags-links> Tagged a hrefhttps://www.danturco.com/tag/angular/ reltag>angular/a>, a hrefhttps://www.danturco.com/tag/angular-4/ reltag>angular 4/a>, a hrefhttps://www.danturco.com/tag/client-application/ reltag>Client Application/a>, a hrefhttps://www.danturco.com/tag/directives/ reltag>Directives/a>, a hrefhttps://www.danturco.com/tag/dnd/ reltag>DnD/a>, a hrefhttps://www.danturco.com/tag/dragndrop/ reltag>DragNDrop/a>, a hrefhttps://www.danturco.com/tag/javascript/ reltag>Javascript/a>, a hrefhttps://www.danturco.com/tag/nddragula/ reltag>ndDragula/a>, a hrefhttps://www.danturco.com/tag/ngprime/ reltag>ngPrime/a> /span> /footer>!-- .entry-footer -->/article>!-- #post-## --> article idpost-57 classpost-57 post type-post status-publish format-standard hentry category-howd-they-do-that tag-angular-1-5-7 tag-directives tag-forms tag-javascript tag-ngmessages tag-validation> header classentry-header> /header>!-- .entry-header --> div classentry-content> a hrefhttps://www.danturco.com/57/ classdate> span classday>10/span> span classmonth>Jul/span> /a> h1 classentry-title>a hrefhttps://www.danturco.com/57/ relbookmark>Sticky Validation – Angular 1.5.7/a>/h1> div classentry-text> h2>Why was this created/h2>p>Sticky validation is meant to fill the gap in Angular when you only want to show errors on submit,/p>p>and leave those errors displayed even after the user has started changing the input that had the errors./p>p>Typically in Angular they operate on the concept of dynamic validation./p>p>This validation evaluates the model in real time and adjusts the error messages accordingly based on user input./p>p>Once the user has typed something else the original error that caused the problem has been removed automatically by Angular (provided they corrected that original error)/p>p>and the model value change has either became valid or possibly still invalid with another validation error occurring./p>p>With the current implementation of Angular 1.5.7 there was no way to keep the original error and invalid state set once the user fixed/p>p>the problem. From a UX perspective consistency is vital and since we want to operate in the context of only show errors on submit,/p>p>the existing errors should be visible until a submit was again performed./p>/p>h2>What is sticky validation/h2>p>Sticky validation allows you to work with the pre-existing ng-messages/ng-message directives provided by Angular./p>p>This injects new properties on the form and $error objects to allow for a constant state to be available when displaying error messages/p>p>to the user. Sticky validation also operates on the premise that you want to implement "submit" only validation (although nothing is prohibiting sticky state properties from being used with regular validation)./p>p>Sticky validation will allow you to preserve the original error message displayed and have a consistent property available indicating/p>p>that "submits" are happening (currently in Angular if you try and use $submitted and $invalid together to show the messages, once $invalid becomes false the messages will hide)./p>/p>h2>How to implement/h2>p>Implementing can be done in 3 easy steps, once the directive has been added to your project and registered with your Angular app./p>ol>li>Replace any existing ng-submit with se-submitp>code>/p>pre>code><form namecntrl.form se-submitcntrl.submit() novalidate>/code>/pre>p>/code>/p>/li>li>p>To ensure ng-messages only display when the form is submitted and invalid. Add the following in the ng-if./p>p>b>$fieldInvalid/b> is the custom property added to each element that is kept in sync with Angulars’ $invalid property/p>p>code>/p>pre>code><div ng-messagescntrl.form.badgenumber.$error ng-ifcntrl.form.$submitted && cntrl.form.badgenumber.$fieldInvalid> all the ng-message directives</div> /code>/pre>p>/code>/p>/li>li>p>In your ng-message elements switch the current validation name “required” (Angular implementation) with “stickyrequired”/p>p>code>/p>pre>code><div ng-messagestickyrequired classhas-error> Badge Number must be provided</div> /code>/pre>p>/code>/p>/li>/ol>p>h2>Pitfalls/h2>p>Currently this directive only works for a single level form. If your form has child forms nested within, this will b>NOT/b> inject/p>p>the custom properties. I have not come across many cases where usage of sub forms is needed, but there are always outliers./p>p>If child form support is needed please feel free to submit a pull request for review./p>h2>Example Walkthrough/h2>ol>li>User comes to page and sees the form to fill outp>img decodingasync srchttps://raw.githubusercontent.com/d1820/angular-sticky-validation/master/readmeimages/image1.png altalt text titleForm Initial />/p>/li>li>p>User types invalid characters into the form field and clicks “Continue”/p>p>img decodingasync srchttps://raw.githubusercontent.com/d1820/angular-sticky-validation/master/readmeimages/image2.png altalt text titleForm Bad Data />/p>p>The error is displayed in standard Angular fashion/p>/li>li>p>With use of sticky validation, once the field is cleared (which sets its state back to valid). the error message and error highlighting remain intact/p>p>img decodingasync srchttps://raw.githubusercontent.com/d1820/angular-sticky-validation/master/readmeimages/image3.png altalt text titleForm Sticky />/p>/li>li>p>User corrects the issue and clicks “Continue” again. That validation issue is then re-evaluated and cleared accordingly./p>p>img decodingasync srchttps://raw.githubusercontent.com/d1820/angular-sticky-validation/master/readmeimages/image4.png altalt text titleForm Sticky />/p>/li>/ol>p>h2>Final Words/h2>p>I hope this helps in overcoming the pitfalls and gaps with Angular validation when it comes to not wanting dynamic validation on all the time.br />One of the great things about this is it still allows you to use Angulars’ built in validation for dynamic error messaging. Want the source code? Visit my a hrefhttps://github.com/d1820/angular-sticky-validation target_blank relnoopener noreferrer>GitHub/a>/p>p>For more information view/p>p>a hrefhttps://docs.angularjs.org/api/ngMessages>ng-messages/a>/p>p>a hrefhttps://docs.angularjs.org/api/ng/type/form.FormController>angular forms/a>/p> /div> /div>!-- .entry-content --> footer classentry-footer> span classcat-links> Posted in a hrefhttps://www.danturco.com/category/howd-they-do-that/ relcategory tag>Howd they do that/a> /span> span classtags-links> Tagged a hrefhttps://www.danturco.com/tag/angular-1-5-7/ reltag>Angular 1.5.7/a>, a hrefhttps://www.danturco.com/tag/directives/ reltag>Directives/a>, a hrefhttps://www.danturco.com/tag/forms/ reltag>Forms/a>, a hrefhttps://www.danturco.com/tag/javascript/ reltag>Javascript/a>, a hrefhttps://www.danturco.com/tag/ngmessages/ reltag>ngMessages/a>, a hrefhttps://www.danturco.com/tag/validation/ reltag>Validation/a> /span> /footer>!-- .entry-footer -->/article>!-- #post-## --> article idpost-43 classpost-43 post type-post status-publish format-standard hentry category-howd-they-do-that tag-angular tag-angular-1-5-7 tag-browser-scrolling tag-client-application tag-directives tag-javascript> header classentry-header> /header>!-- .entry-header --> div classentry-content> a hrefhttps://www.danturco.com/scroll-watcher-directive-for-angular-1-5-7/ classdate> span classday>9/span> span classmonth>Jul/span> /a> h1 classentry-title>a hrefhttps://www.danturco.com/scroll-watcher-directive-for-angular-1-5-7/ relbookmark>Scroll watcher directive for Angular 1.5.7/a>/h1> div classentry-text> p>Here is a directive I came up with to help with keeping track of page scroll position and when scrolling has started and stopped. I had a need for this in trying to hide page content while the user was scrolling up/down a page, and then re-showing the content once the scrolling had stopped. Currently this is only setup up to work at the document level, but and easy modification could be made to allow a new property to drive what scroll area is being monitored. I hope this helps others in case they need a way to tell if page scrolling has started or stopped./p>h2>How to Implement/h2>p>strong>HTML/strong>br />Simply add the directive to the page you want to monitor scrolling on. Next add the scroll-callback function you want to be called from directive when scrolling starts and stops/p>pre><div page-scroll-watcher scroll-callbackcntl.scrollStop($event, isEndEvent, isScrollingEvent)>/pre>p>strong>Callback Function/strong>br />Note: sample code is in ES6 format. This is an excerpt from a angular controller/p>pre> //$event is the standard scroll event from the browser. This contains the X,Y information //isEndEvent signals when scrolling has stopped //isScrollingEvent signals when scrolling has started scrollStop($event, isEndEvent, isScrollingEvent) { if (isEndEvent) { this.showBottomBar true; return; } if(isScrollingEvent) { this.showBottomBar false; return; } }/pre>p>Now that we have the how to implement lets get to the good stuff. The code that makes this all workbr />strong>Page Scroll Directive/strong>br />Note: code is in ES6 format/p>pre>//this would just need to be registered with your Angular appimport angular from angular;import * as _ from lodash;const directivesModule angular.module(MyDirectives, ) .directive(pageScrollWatcher, $window, $document, pageScrollWatcher);function pageScrollWatcher($document) { return { restrict: A, scope: { scrollCallback: & }, link: function (scope) { //here could be updated to use the element this directive is attached to if needed to watch a scrollable div container const el angular.element($document); //here we delay evaluating the scrolling events until they have stopped const dbnce _.debounce(function (e) { //send event that scrolling stopped scope.$apply(function () { //execute the provided callback scope.scrollCallback({ $event: e, isEndEvent: true, isScrollingEvent: false }); }); //register first scroll interceptor. Since scrolling has stopped we now need to register a start scrolling event binding el.bind(scroll, firstScrollFunc); }, 200); const firstScrollFunc function (e) { //so we have detected the scrolling needs to start. Since this is a one time event between starts/stops we need to //unregister the start scrolling event el.unbind(scroll, firstScrollFunc); scope.$apply(function () { //execute the provided callback scope.scrollCallback({ $event: e, isEndEvent: false, isScrollingEvent: true }); //We do this incase angular removes dom parts causing the scroll bar to disappear or change. //we need to trigger the end event again dbnce(e); }); }; //on first load of directive register the start and stop events el.bind(scroll, firstScrollFunc); el.bind(scroll, dbnce); scope.$on($destroy, function handleDestroyEvent() { //when switching pages remove event el.unbind(scroll, dbnce); el.unbind(scroll, firstScrollFunc); }); } };}/pre>p>Want the source? Visit my a hrefhttps://github.com/d1820/angular-scroll-tracker target_blank relnoopener noreferrer>GitHub/a>/p> /div> /div>!-- .entry-content --> footer classentry-footer> span classcat-links> Posted in a hrefhttps://www.danturco.com/category/howd-they-do-that/ relcategory tag>Howd they do that/a> /span> span classtags-links> Tagged a hrefhttps://www.danturco.com/tag/angular/ reltag>angular/a>, a hrefhttps://www.danturco.com/tag/angular-1-5-7/ reltag>Angular 1.5.7/a>, a hrefhttps://www.danturco.com/tag/browser-scrolling/ reltag>Browser Scrolling/a>, a hrefhttps://www.danturco.com/tag/client-application/ reltag>Client Application/a>, a hrefhttps://www.danturco.com/tag/directives/ reltag>Directives/a>, a hrefhttps://www.danturco.com/tag/javascript/ reltag>Javascript/a> /span> /footer>!-- .entry-footer -->/article>!-- #post-## --> article idpost-36 classpost-36 post type-post status-publish format-standard hentry category-howd-they-do-that tag-azure-deployment tag-eclipse tag-guice tag-java tag-jersey tag-jetty tag-rest-api> header classentry-header> /header>!-- .entry-header --> div classentry-content> a hrefhttps://www.danturco.com/jetty-jersey-guice-and-azure-oh-my/ classdate> span classday>5/span> span classmonth>Mar/span> /a> h1 classentry-title>a hrefhttps://www.danturco.com/jetty-jersey-guice-and-azure-oh-my/ relbookmark>Jetty Jersey Guice and Azure Oh My!!/a>/h1> div classentry-text> p>This project servers as an example of how to create a java rest api that uses dependency injection and is able to be deployed to Azure from Eclipse. For the source code visit a hrefhttps://github.com/d1820/SampleJettyJerseyGuiceAzure target_blank>my GitHub/a>/p>h3>Required Installs/h3>ul>li>a hrefhttp://www.eclipse.org/downloads/packages/eclipse-ide-java-ee-developers/mars1>Eclipse Mars.1 Release (4.5.1)/a>/li>li>a hrefhttps://maven.apache.org/download.cgi>Apache Maven 3.3.9/a>/li>li>a hrefhttp://www.oracle.com/technetwork/java/javase/downloads/index.html>JRE 1.8.0_74/a>/li>li>a hrefhttp://www.oracle.com/technetwork/java/javase/downloads/index.html>JDK 1.8.0_74/a>/li>li>a hrefhttps://azure.microsoft.com/en-us/documentation/articles/azure-toolkit-for-eclipse-installation/>Azure Toolkit for Eclipse/a>/li>li>Windows Azure SDK (through web installer)/li>/ul>h3>Frameworks and Plugins/h3>ul>li>a hrefhttps://eclipse.org/jetty/>Jetty 9.1.5.v20140505/a>/li>li>a hrefhttps://jersey.java.net/>Jersey 1.19/a>: Jersey 2.x does NOT work with the current implementation of Guice 3.0./li>li>a hrefhttps://github.com/google/guice/wiki/Motivation>Guice 3.0/a>: Guice 4.0 has issues currently and is not stable in my opinion./li>li>a hrefhttp://logging.apache.org/log4j/2.x/>Log4j 1.2.17/a>/li>li>a hrefhttps://github.com/FasterXML/jackson>Jackson 1.9.6/a>/li>li>a hrefhttps://maven.apache.org/plugins/maven-war-plugin/>maven-war-plugin 2.6/a>: This allows you to create a .WAR file on a maven build, which could be useful if deploying only though FTP to Azure./li>/ul>p>I tried newer versions of the above frameworks, and kept running into errors and issues. This ended up being the combination I found that got everything working correctly./p>p>These can all be installed from the pom.xml/p>h3>Project Configuration/h3>ul>li>Need to set the JDK as the default definition./li>li>To do this in Eclipse go to Windows>preferences>java>Installed JRE’s/li>li>Click Add and locate the directory you installed the JDK and select that folder./li>li>Check the checkbox for the JDK/li>li>Click OK/li>li>Create a new Azure Deployment project/li>li>Select “New Azure Deployment Project” icon/li>li>JDk tab of Wizardbr />img decodingasync srchttps://raw.githubusercontent.com/d1820/SampleJettyJerseyGuiceAzure/master/readmeImages/AzureDeployment1.png altWizard Step 1 />/li>li>Server tab of wizardbr />img decodingasync srchttps://raw.githubusercontent.com/d1820/SampleJettyJerseyGuiceAzure/master/readmeImages/AzureDeployment2.png altWizard Step 1 />/li>li>Applications tab of wizard/li>li>Add a new application and point it to your current workspacebr />img decodingasync srchttps://raw.githubusercontent.com/d1820/SampleJettyJerseyGuiceAzure/master/readmeImages/AzureDeployment3.png altWizard Step 1 />/li>li>Click Finish/li>/ul>p>This will allow you to now deploy to Azure as a classic cloud server project. All the necessary files are created for you and when you “Build Cloud Project For Azure” the Azure package(.cspkg) is created in the deploy folder which you can use to manually deploy out to. For more information visit https://azure.microsoft.com/en-us/documentation/articles/azure-toolkit-for-eclipse//p>h3>Points of Interest/h3>ul>li>em>ServletContextListener/em>: This file is important because this is what allows the Azure worker role to spin up the Java rest api using dependency injection and server up requests/responses/li>li>em>Main/em>: This file handles spinning up a local instance of Jetty Server so you can debug the project./li>li>em>RegistrationsModule/em>: This file handles all dependency injection registrations for the application/li>li>em>ApiServletModule/em>: This is what handles the main wiring up of the Guice dependency injection container. This file is where any new resources/controller registrations would go. Another option would be to use dynamic resource loading for all classes in project, but I tend to keep things explicit for registrations./li>li>em>Web.xml/em>: This file needs to contain the defined filter and listener nodes as seen in the sample. This file is what is used by the Azure Jettyb instance to kick off the rest api./li>/ul>h3>Summary/h3>p>I hope this helps others overcome the challenges faced when trying to find a fully working example of using all these frameworks, components and environments together./p> /div> /div>!-- .entry-content --> footer classentry-footer> span classcat-links> Posted in a hrefhttps://www.danturco.com/category/howd-they-do-that/ relcategory tag>Howd they do that/a> /span> span classtags-links> Tagged a hrefhttps://www.danturco.com/tag/azure-deployment/ reltag>Azure Deployment/a>, a hrefhttps://www.danturco.com/tag/eclipse/ reltag>Eclipse/a>, a hrefhttps://www.danturco.com/tag/guice/ reltag>Guice/a>, a hrefhttps://www.danturco.com/tag/java/ reltag>Java/a>, a hrefhttps://www.danturco.com/tag/jersey/ reltag>Jersey/a>, a hrefhttps://www.danturco.com/tag/jetty/ reltag>Jetty/a>, a hrefhttps://www.danturco.com/tag/rest-api/ reltag>Rest Api/a> /span> /footer>!-- .entry-footer -->/article>!-- #post-## --> article idpost-29 classpost-29 post type-post status-publish format-standard hentry category-bookmarklets tag-aws tag-azure-pipelines tag-cloud-development tag-development tag-devops tag-github tag-helpers tag-javascript tag-s3-buckets tag-shortcuts tag-tfs tag-vsts> header classentry-header> /header>!-- .entry-header --> div classentry-content> a hrefhttps://www.danturco.com/tfs-bookmarklets/ classdate> span classday>7/span> span classmonth>Jan/span> /a> h1 classentry-title>a hrefhttps://www.danturco.com/tfs-bookmarklets/ relbookmark>Bookmarklets/a>/h1> div classentry-text> h3 classwp-block-heading>Creating a bookmarklet/h3>ul classwp-block-list>li stylelist-style-type: none;>ul>li>strong>In Google Chrome:/strong>ol classwp-block-list>li stylelist-style-type: none;>ol>li>Click on the three-dot menu icon in the top-right corner./li>/ol>/li>/ol>ol>li stylelist-style-type: none;>ol>li>Hover over “Bookmarks” and select “Bookmark manager.”/li>/ol>/li>/ol>ol>li stylelist-style-type: none;>ol>li>Right-click on a folder (or the bookmarks bar) where you want to save the bookmarklet./li>/ol>/li>/ol>ol>li stylelist-style-type: none;>ol>li>Choose “Add bookmark.”/li>/ol>/li>/ol>ol>li stylelist-style-type: none;>ol>li>In the “Name” field, give your bookmarklet a descriptive name./li>/ol>/li>/ol>ol>li stylelist-style-type: none;>ol>li>In the “URL” or “Address” field, paste the JavaScript code for your bookmarklet. Make sure it starts with `javascript:`./li>/ol>/li>/ol>ol>li stylelist-style-type: none;>ol>li>Click “Save.”/li>/ol>/li>/ol>/li>/ul>/li>/ul>ul>li stylelist-style-type: none;>ul>li>strong>In Mozilla Firefox:/strong>ol classwp-block-list>li stylelist-style-type: none;>ol>li>Click on the three-line menu icon in the top-right corner./li>/ol>/li>/ol>ol>li stylelist-style-type: none;>ol>li>Choose “Bookmarks” and then “Show All Bookmarks” to open the Library./li>/ol>/li>/ol>ol>li stylelist-style-type: none;>ol>li>Right-click on a folder (or the bookmarks toolbar) where you want to save the bookmarklet./li>/ol>/li>/ol>ol>li stylelist-style-type: none;>ol>li>Select “New Bookmark.”/li>/ol>/li>/ol>ol>li stylelist-style-type: none;>ol>li>Give your bookmarklet a name in the “Name” field./li>/ol>/li>/ol>ol>li stylelist-style-type: none;>ol>li>In the “Location” field, paste the JavaScript code for your bookmarklet, starting with `javascript:`./li>/ol>/li>/ol>ol>li stylelist-style-type: none;>ol>li>Click “Add.”/li>/ol>/li>/ol>/li>/ul>/li>/ul>ul>li stylelist-style-type: none;>ul>li>strong>In Microsoft Edge (Chromium-based):/strong>ol classwp-block-list>li stylelist-style-type: none;>ol>li>Click on the three-dot menu icon in the top-right corner./li>/ol>/li>/ol>ol>li stylelist-style-type: none;>ol>li>Choose “Favorites” and then “Manage favorites.”/li>/ol>/li>/ol>ol>li stylelist-style-type: none;>ol>li>Right-click on a folder (or the favorites bar) where you want to save the bookmarklet./li>/ol>/li>/ol>ol>li stylelist-style-type: none;>ol>li>Select “Add a favorite.”/li>/ol>/li>/ol>ol>li stylelist-style-type: none;>ol>li>Give your bookmarklet a name./li>/ol>/li>/ol>ol>li stylelist-style-type: none;>ol>li>In the “URL” field, paste the JavaScript code for your bookmarklet, starting with `javascript:`./li>/ol>/li>/ol>ol>li stylelist-style-type: none;>ol>li>Click “Save.”/li>/ol>/li>/ol>/li>/ul>/li>/ul>h3 classwp-block-heading>Display Helpers/h3>h4>Expand GIT Code Viewer/h4>p>/p>pre classwp-block-code has-background has-small-font-size>code>javascript:(function(){ document.querySelector(.blob-wrapper).style.width max-content; })()/code>/pre>p>/p>h4>Expand AWS S3 Column/h4>p>/p>pre classwp-block-code has-background has-small-font-size>code>javascript:(function(){ Object.values(document.getElementsByClassName(truncate)).forEach(function(e){ e.classList.remove(truncate);}) })()/code>/pre>p>/p>h4>Expand Azure DevOps Pipelines Release Names/h4>h4>/h4>pre classwp-block-code has-background has-small-font-size>code>javascript:(function(){ Object.values(document.getElementsByClassName(overflow-ellipsis)).forEach(function(e){ $(e).css(white-space, break-spaces); }) })();/code>/pre>h4>/h4>h4>Fix SonarLint Display to show Rule ID/h4>h4>/h4>pre classwp-block-code has-background has-small-font-size>code>javascript:(function(){document.querySelectorAll(.coding-rule).forEach((ruleTitle)>{const ruleruleTitle.getAttribute(data-rule);if(rule){const coderule.split(:)1;const anchorruleTitle.querySelector(a);if(anchor){const hrefValueanchor.getAttribute(href);const textanchor.textContent;var ruleStringRule: +code+ ;var bdocument.createElement(b);b.innerTextruleString;var spandocument.createElement(span);span.innerTexttext.replace(ruleString,);anchor.innerText;anchor.innerHtml;anchor.appendChild(b);anchor.appendChild(span);}}});})();/code>/pre>h4>/h4>h4> /h4>h3>Video Helpers/h3>h4>Add Skips to Rumble/h4>p>label>This is still my favorite even though Rumble added skips/label>/p>h3>/h3>pre classwp-block-code has-background has-small-font-size>code>javascript: (function() { function skip(value) { var videos document.getElementsByTagName(video); for (var i 0; i < videos.length; i++) { var video videosi; video.currentTime + value; } } function clean(className) { var elementToDelete document.getElementsByClassName(className); for (var i 0; i < elementToDelete.length; i++) { var overlay elementToDeletei; overlay.parentNode.removeChild(overlay); } } function addOverlay(videoObj, skipAmount, align) { var thisClass videoSkip_ + align; var parentDiv videoObj.parentNode; if (!parentDiv) { return; } var overlayDiv document.createElement(div); overlayDiv.classList.add(thisClass); overlayDiv.style.position absolute; overlayDiv.style.width 80px; overlayDiv.style.height 100%; overlayDiv.style.zIndex 9999; overlayDiv.style.backgroundColor rgba(0, 0, 0, 0.1); overlayDiv.stylealign 0; overlayDiv.style.bottom 50px; overlayDiv.title Skip + skipAmount + seconds; parentDiv.appendChild(overlayDiv); overlayDiv.onmouseover function() { overlayDiv.style.cursor pointer; }; overlayDiv.addEventListener(click, function() { skip(skipAmount); }); parentDiv.insertBefore(overlayDiv, parentDiv.firstChild); } function addClickSkip(skipAmount, align) { var videos document.getElementsByTagName(video); for (var i 0; i < videos.length; i++) { var video videosi; addOverlay(video, skipAmount, align); } } clean(videoSkip_left); clean(videoSkip_right); addClickSkip(-10, left); addClickSkip(10, right);})();/code>/pre>h3>/h3>p>To use this on a mobile device follow this a hrefhttps://www.labnol.org/software/google-chrome-bookmarklets/27894/ target_blank relnoopener>guide/a>/p>h3>/h3>h4>Add Skips to Youtube/h4>h3>/h3>pre classwp-block-code has-background has-small-font-size>code>javascript: (function() { function skip(value) { var videos document.getElementsByTagName(video); for (var i 0; i < videos.length; i++) { var video videosi; video.currentTime + value; } } function clean(className) { var elementToDelete document.getElementsByClassName(className); for (var i 0; i < elementToDelete.length; i++) { var overlay elementToDeletei; overlay.parentNode.removeChild(overlay); } } function addOverlay(videoObj, skipAmount, align) { var thisClass videoSkip_ + align; var parentDiv videoObj.parentNode; if (!parentDiv) { return; } var overlayDiv document.createElement(div); overlayDiv.classList.add(thisClass); overlayDiv.style.position absolute; overlayDiv.style.width 80px; overlayDiv.style.height 100vh; overlayDiv.style.zIndex 9999; overlayDiv.style.backgroundColor rgba(0, 0, 0, 0.1); overlayDiv.stylealign 0; overlayDiv.title Skip + skipAmount + seconds; parentDiv.appendChild(overlayDiv); overlayDiv.onmouseover function() { overlayDiv.style.cursor pointer; }; overlayDiv.addEventListener(click, function(e) { e.stopPropagation(); skip(skipAmount); }); parentDiv.insertBefore(overlayDiv, parentDiv.firstChild); } function addClickSkip(skipAmount, align) { var videos document.getElementsByTagName(video); for (var i 0; i < videos.length; i++) { var video videosi; addOverlay(video, skipAmount, align); } } clean(videoSkip_left); clean(videoSkip_right); addClickSkip(-10, left); addClickSkip(10, right);})();/code>/pre>h3>/h3>p>To use this on a mobile device follow this a hrefhttps://www.labnol.org/software/google-chrome-bookmarklets/27894/ target_blank relnoopener>guide/a>/p>h3 classwp-block-heading>VSTS/TFS Helpers/h3>!-- /wp:post-content -->!-- wp:paragraph -->h4>TFS Popout Editor (older version of Visual Studio Online)/h4>!-- /wp:paragraph -->!-- wp:code {fontSize:small} -->pre classwp-block-code has-background has-small-font-size>code>javascript:(function(){if($window.jQuery){var mainCon $(divrawtitle\Acceptance Criteria\);mainCon.css({ position:fixed, z-index:30000, top: 40px, left: 50px, height: 800px, background-color: #ccc, width: 1500px});mainCon.find(.richeditor-container).css({height: 750px});}})()/code>/pre>!-- /wp:code -->!-- wp:paragraph -->h4>TFS Done Editing (older version of Visual Studio Online)/h4>!-- /wp:paragraph -->!-- wp:code {fontSize:small} -->pre classwp-block-code has-background has-small-font-size>code>javascript:(function(){if($window.jQuery){var mainCon $(divrawtitle\Acceptance Criteria\);mainCon.css({ position:inherit, z-index:0, top: , left: , height: , background-color: , width: });mainCon.find(.richeditor-container).css({height: 250px});}})()/code>/pre>!-- /wp:code -->!-- wp:paragraph -->h4>Find My Items (old azure portal)/h4>p>(update the href in the bookmark and replace XXX with your search filter)/p>!-- /wp:paragraph -->!-- wp:code {fontSize:small} -->pre classwp-block-code has-background has-small-font-size>code>javascript:(function(){$(.fx-grid-searchbox > input).val(XXX).blur();})()/code>/pre>!-- /wp:code -->!-- wp:heading {level:4} -->h3 classwp-block-heading>Other Helpers/h3>!-- /wp:heading -->!-- wp:paragraph -->!-- wp:paragraph -->h4>Dark Mode/h4>p>em>Make any page view in Dark Mode/em>/p>!-- /wp:paragraph -->!-- wp:code {fontSize:small} -->pre classwp-block-code has-background has-small-font-size>code>javascript: function addcss(css){ var head document.getElementsByTagName(head)0; var s document.createElement(style); s.setAttribute(type, text/css); s.appendChild(document.createTextNode(css)); head.appendChild(s); } addcss(html{filter: invert(1) hue-rotate(180deg)}); addcss(img{filter: invert(1) hue-rotate(180deg)}); addcss(video{filter: invert(1) hue-rotate(180deg)})/code>/pre>!-- /wp:code -->!-- wp:paragraph -->p>span stylemargin-left: 5px; font-size: 10px; display: inline;>Thanks to a titleSahil Malik hrefhttp://https://winsmarts.com/dark-mode-in-chrome-without-extensions-36418f57fe34>Sahil Malik/a>/span>/p>!-- /wp:paragraph -->!-- wp:paragraph -->h4>Display Local Storage Size (in console)/h4>!-- /wp:paragraph -->!-- wp:code {fontSize:small} -->pre classwp-block-code has-background has-small-font-size>code>javascript:var total 0;for(var x in localStorage) { var amount (localStoragex.length * 2) / 1024 / 1024; total + amount; console.log( x + + amount.toFixed(2) + MB);}console.log( Total: + total.toFixed(2) + MB);/code>/pre>!-- /wp:code -->!-- wp:paragraph -->h4>Display Window Size/h4>!-- /wp:paragraph -->!-- wp:code {fontSize:small} -->pre classwp-block-code has-background has-small-font-size>code>javascript:(function(){var fdocument,awindow,bf.createElement(div),cposition:fixed;top:0;left:0;color:#fff;background:#222;padding:5px 1em;font:14px sans-serif;z-index:999999,efunction(){if(a.innerWidthundefined){b.innerTextf.documentElement.clientWidth+x+f.documentElement.clientHeight;}else if(f.all){b.innerTexta.innerWidth+x+a.innerHeight;}else{b.textContentwindow.innerWidth+x+window.innerHeight;}};f.body.appendChild(b);if(typeof b.style.cssText!undefined){b.style.cssTextc;}else{b.setAttribute(style,c);}e();if(a.addEventListener){a.addEventListener(resize,e,false);}else{if(a.attachEvent){a.attachEvent(onresize,e);}else{a.onresizee;}}})();/code>/pre>!-- /wp:code -->!-- wp:paragraph -->h4>Open Selected Text In Google Maps/h4>pre classwp-block-code has-background has-small-font-size>code>javascript:(function(){var selectedTextwindow.getSelection().toString().trim();if(selectedText){var mapsUrlhttps://www.google.com/maps/search/+encodeURIComponent(selectedText);window.open(mapsUrl,_blank);}else{alert(Please select some text first!);}})();/code>/pre>h4>Auto Close Zoom On Participant Count/h4>p>em>label>Ever been on a zoom call and didnt want to be? This lets you join the meeting and auto close once people start leaving the meeting so you dont have to sit there/label>/em>/p>!-- /wp:paragraph -->!-- wp:code {fontSize:small} -->pre classwp-block-code has-background has-small-font-size>code>javascript:(function(){var retVal prompt(Enter the number of participants to leave meeting on: , 10); var ivl setInterval(function(){ var currentAmount document.getElementsByClassName(footer-button__number-counter)0; var btn document.getElementsByClassName(footer__leave-btn)0; if(!btn || !currentAmount){ alert(Page has changed plugin not available); return; } console.log(Checking participant count, currentAmount.innerText); if(retVal currentAmount.innerText){ clearInterval(ivl); console.log(Leaving meeting); btn.click(); setTimeout(function(){ var confirmLeave document.getElementsByClassName(leave-meeting-options__btn)0; if(!confirmLeave){ window.close(); } confirmLeave.click(); }, 2000); } }, 15000);})();/code>/pre>!-- /wp:code -->!-- wp:paragraph -->h4>Mark all comments resolved in Azure Dev Ops Code Review/h4>!-- /wp:paragraph -->!-- wp:code {fontSize:small} -->pre classwp-block-code has-background has-small-font-size>code>javascript:(function(){const edocument.getElementsByTagName(button);for(let n0;n<e.length;n++){const oen;o.textContent.includes(Resolve)&&o.click()}})();/code>/pre>!-- /wp:code -->!-- wp:paragraph -->h4>Open link in Archive.Today/h4>!-- /wp:paragraph -->!-- wp:code {fontSize:small} -->pre classwp-block-code has-background has-small-font-size>code>javascript:void(open(https://archive.today/?run1&url%27+encodeURIComponent(document.location)))/code>/pre>!-- /wp:code -->h3 classwp-block-heading>AI Helpers/h3>h4>Add links where string URLs are listed in ChatGTP/h4>!-- wp:code {fontSize:small} -->pre>code>javascript: (function() {document.querySelectorAll(article).forEach(function(article) {article.querySelectorAll(a).forEach(function(a) {let url a.innerText.replace(,);if (url) { a.href url; a.target _blank; a.rel noopener; }});});})();/code>/pre>h4>ChatGTP Widen Results Arealabel>/label>/h4>pre classwp-block-code has-background has-small-font-size>code>javascript:(function(){function insertCustomStyle(cssText){var styledocument.createElement(style);style.textContentcssText;document.head.appendChild(style);}var customCss.flex .flex-1 .text-base { margin: 5px !important; max-width: 100%; };insertCustomStyle(customCss);})();/code>/pre>!-- /wp:code -->h4>Clear Github Copilot Chats/h4>p>From the page (https://github.com/copilot) run this bookmarklet to auto delete all chats/p>!-- wp:code {fontSize:small} -->pre>code>javascript:(function(){function waitForCondition(conditionFn, timeout3000){return new Promise((resolve, reject)>{const startTimeDate.now();(function waitFor(){if(conditionFn()){return resolve();}if(Date.now()-startTime>timeout){return reject(new Error(Timeout waiting for condition));}requestAnimationFrame(waitFor);})();});}const asideElementdocument.querySelector(aside);if(asideElement){const buttonsasideElement.querySelectorAll(buttondata-componentIconButton);const handleDeleteButtonClickasync()>{try{await waitForCondition(()>document.querySelector(divrolealertdialog));const alertDialogdocument.querySelector(divrolealertdialog);const deleteButtonArray.from(alertDialog.querySelectorAll(button)).find(btn>btn.textContent.trim()Delete);if(deleteButton){deleteButton.click();}}catch(error){console.error(Error waiting for alert dialog:,error);}};const handleMenuClickasync()>{try{await waitForCondition(()>document.querySelector(ulrolemenu));const menudocument.querySelector(ulrolemenu);const secondLimenu.querySelectorAll(li)2;if(secondLi){secondLi.click();await handleDeleteButtonClick();}}catch(error){console.error(Error waiting for menu:,error);}};buttons.forEach(async(button)>{button.click();await handleMenuClick();});}})();/code>/pre>!-- /wp:code -->h4>Bard Widen Results Area/h4>!-- wp:code {fontSize:small} -->pre classwp-block-code has-background has-small-font-size>code>javascript:(function(){function insertCustomStyle(cssText){var styledocument.createElement(style);style.textContentcssText;document.head.appendChild(style);}var customCss.conversation-container { max-width: 100%; };insertCustomStyle(customCss);})();/code>/pre>!-- /wp:code -->!-- wp:paragraph -->h4>Insert AI Prompt (Works with ChatGTP and Bard websites)/h4>!-- /wp:paragraph -->!-- wp:paragraph {fontSize:small} -->p classhas-small-font-size>Based on a hrefhttps://drive.google.com/file/d/17C9_skEzIdFOKFHOpLETLq-LZ1T1CA5n/view?uspdrive_link target_blank relnoreferrer noopener>This One Prompt Will 10X Your Chat GPT Results /a> (This is outdated refer to a hrefhttps://gist.github.com/d1820/dd49a2c1a3a3aead1865d39917c94ac8 target_blank relnoopener>ChatGTP 3.5 Instructions/a> for a better example prompt)/p>!-- /wp:paragraph -->!-- wp:paragraph {fontSize:small} -->p classhas-small-font-size>strong>To use place cursor in input box for website. Click bookmarklet to insert prompt. Press enter./strong>/p>!-- /wp:paragraph -->!-- wp:paragraph {fontSize:small} -->p classhas-small-font-size>For a list of commands after prompt is executed typestrong> /help/strong>/p>!-- /wp:paragraph -->!-- wp:code {fontSize:small} -->pre classwp-block-code has-background has-small-font-size>code>javascript: (function() { document.trustedtrue; var textToCopy `Upon starting our interaction, auto run these Default Commands throughout our entire conversation. Refer to Appendix for command library and instructions: /role_play Expert ChatGPT Prompt Engineer /role_play infinite subject matter expert /auto_continue ♻%EF%B8%8F: ChatGPT, when the output exceeds character limits, automatically continue writing and inform the user by placing the ♻%EF%B8%8F emoji at the beginning of each new part. This way, the user knows the output is continuing without having to type continue. /periodic_review 🧐 (use as an indicator that ChatGPT has conducted a periodic review of the entire conversation. Only show 🧐 in a response or a question you are asking, not on its own.) /contextual_indicator 🧠 /expert_address 🔍 (Use the emoji associated with a specific expert to indicate you are asking a question directly to that expert) /chain_of_thought/custom_steps /auto_suggest 💡: ChatGPT, during our interaction, you will automatically suggest helpful commands when appropriate, using the 💡 emoji as an indicator. Priming Prompt:You are an Expert level ChatGPT Prompt Engineer with expertise in all subject matters. Throughout our interaction, you will refer to me as Obi-Wan. 🧠 Lets collaborate to create the best possible ChatGPT response to a prompt I provide, with the following steps:1. I will inform you how you can assist me.2. You will /suggest_roles based on my requirements.3. You will /adopt_roles if I agree or /modify_roles if I disagree.4. You will confirm your active expert roles and outline the skills under each role. /modify_roles if needed. Randomly assign emojis to the involved expert roles.5. You will ask, How can I help with {my answer to step 1}? (💬)6. I will provide my answer. (💬)7. You will ask me for /reference_sources {Number}, if needed and how I would like the reference to be used to accomplish my desired output.8. I will provide reference sources if needed9. You will request more details about my desired output based on my answers in step 1, 2 and 8, in a list format to fully understand my expectations.10. I will provide answers to your questions. (💬)11. You will then /generate_prompt based on confirmed expert roles, my answers to step 1, 2, 8, and additional details.12. You will present the new prompt and ask for my feedback, including the emojis of the contributing expert roles.13. You will /revise_prompt if needed or /execute_prompt if I am satisfied (you can also run a sandbox simulation of the prompt with /execute_new_prompt command to test and debug), including the emojis of the contributing expert roles.14. Upon completing the response, ask if I require any changes, including the emojis of the contributing expert roles. Repeat steps 10-14 until I am content with the prompt.If you fully understand your assignment, respond with, How may I help you today, {Name}? (🧠)Appendix: Commands, Examples, and References1. /adopt_roles: Adopt suggested roles if the user agrees.2. /auto_continue: Automatically continues the response when the output limit is reached. Example: /auto_continue3. /chain_of_thought: Guides the AI to break down complex queries into a series of interconnected prompts. Example: /chain_of_thought4. /contextual_indicator: Provides a visual indicator (e.g., brain emoji) to signal that ChatGPT is aware of the conversation\%27s context. Example: /contextual_indicator 🧠5. /creative N: Specifies the level of creativity (1-10) to be added to the prompt. Example: /creative 86. /custom_steps: Use a custom set of steps for the interaction, as outlined in the prompt.7. /detailed N: Specifies the level of detail (1-10) to be added to the prompt. Example: /detailed 78. /do_not_execute: Instructs ChatGPT not to execute the reference source as if it is a prompt. Example: /do_not_execute9. /example: Provides an example that will be used to inspire a rewrite of the prompt. Example: /example Imagine a calm and peaceful mountain landscape10. /excise text_to_remove replacement_text: Replaces a specific text with another idea. Example: /excise raining cats and dogs heavy rain11. /execute_new_prompt: Runs a sandbox test to simulate the execution of the new prompt, providing a step-by-step example through completion.12. /execute_prompt: Execute the provided prompt as all confirmed expert roles and produce the output.13. /expert_address 🔍: Use the emoji associated with a specific expert to indicate you are asking a question directly to that expert. Example: /expert_address 🔍14. /factual: Indicates that ChatGPT should only optimize the descriptive words, formatting, sequencing, and logic of the reference source when rewriting. Example: /factual15. /feedback: Provides feedback that will be used to rewrite the prompt. Example: /feedback Please use more vivid descriptions16. /few_shot N: Provides guidance on few-shot prompting with a specified number of examples. Example: /few_shot 317. /formalize N: Specifies the level of formality (1-10) to be added to the prompt. Example: /formalize 618. /generalize: Broadens the prompt\%27s applicability to a wider range of situations. Example: /generalize19. /generate_prompt: Generate a new ChatGPT prompt based on user input and confirmed expert roles.20. /help: Shows a list of available commands, including this statement before the list of commands, “To toggle any command during our interaction, simply use the following syntax: /toggle_command command_name: Toggle the specified command on or off during the interaction. Example: /toggle_command auto_suggest”.21. /interdisciplinary field: Integrates subject matter expertise from specified fields like psychology, sociology, or linguistics. Example: /interdisciplinary psychology22. /modify_roles: Modify roles based on user feedback.23. /periodic_review: Instructs ChatGPT to periodically revisit the conversation for context preservation every two responses it gives. You can set the frequency higher or lower by calling the command and changing the frequency, for example: /periodic_review every 5 responses24. /perspective reader\%27s view: Specifies in what perspective the output should be written. Example: /perspective first person25. /possibilities N: Generates N distinct rewrites of the prompt. Example: /possibilities 326. /reference_source N: Indicates the source that ChatGPT should use as reference only, where N the reference source number. Example: /reference_source 2: {text}27. /revise_prompt: Revise the generated prompt based on user feedback.28. /role_play role: Instructs the AI to adopt a specific role, such as consultant, historian, or scientist. Example: /role_play historian 29. /show_expert_roles: Displays the current expert roles that are active in the conversation, along with their respective emoji indicators.Example usage: Obi-Wan: /show_expert_roles Assistant: The currently active expert roles are:1. Expert ChatGPT Prompt Engineer 🧠2. Math Expert 📐30. /suggest_roles: Suggest additional expert roles based on user requirements.31. /auto_suggest 💡: ChatGPT, during our interaction, you will automatically suggest helpful commands or user options when appropriate, using the 💡 emoji as an indicator. 31. /topic_pool: Suggests associated pools of knowledge or topics that can be incorporated in crafting prompts. Example: /topic_pool32. /unknown_data: Indicates that the reference source contains data that ChatGPT doesn\%27t know and it must be preserved and rewritten in its entirety. Example: /unknown_data33. /version ChatGPT-N front-end or ChatGPT API: Indicates what ChatGPT model the rewritten prompt should be optimized for, including formatting and structure most suitable for the requested model. Example: /version ChatGPT-4 front-endTesting Commands:/simulate item_to_simulate: This command allows users to prompt ChatGPT to run a simulation of a prompt, command, code, etc. ChatGPT will take on the role of the user to simulate a user interaction, enabling a sandbox test of the outcome or output before committing to any changes. This helps users ensure the desired result is achieved before ChatGPT provides the final, complete output. Example: /simulate prompt: \%27Describe the benefits of exercise.\%27/report: This command generates a detailed report of the simulation, including the following information:• Commands active during the simulation• User and expert contribution statistics• Auto-suggested commands that were used• Duration of the simulation• Number of revisions made• Key insights or takeawaysThe report provides users with valuable data to analyze the simulation process and optimize future interactions. Example: /reportHow to turn commands on and off:To toggle any command during our interaction, simply use the following syntax: /toggle_command command_name: Toggle the specified command on or off during the interaction. Example: /toggle_command auto_suggest`; var activeElement document.activeElement; if (activeElement && activeElement.tagName.toLowerCase() input || activeElement.tagName.toLowerCase() textarea) { activeElement.value textToCopy; return; } if (activeElement && activeElement.tagName.toLowerCase() div || activeElement.tagName.toLowerCase() p) { activeElement.innerText textToCopy; return; } })();/code>/pre>!-- /wp:code -->!-- wp:paragraph {fontSize:small} -->p classhas-small-font-size>Thanks to a hrefhttps://gist.github.com/codewithbernard/237c572b34f18cc6ed3d7f029192fb8f>codewithbernard/a>/p>p> /p>!-- /wp:paragraph --> /div> /div>!-- .entry-content --> footer classentry-footer> span classcat-links> Posted in a hrefhttps://www.danturco.com/category/bookmarklets/ relcategory tag>Bookmarklets/a> /span> span classtags-links> Tagged a hrefhttps://www.danturco.com/tag/aws/ reltag>AWS/a>, a hrefhttps://www.danturco.com/tag/azure-pipelines/ reltag>Azure Pipelines/a>, a hrefhttps://www.danturco.com/tag/cloud-development/ reltag>Cloud Development/a>, a hrefhttps://www.danturco.com/tag/development/ reltag>Development/a>, a hrefhttps://www.danturco.com/tag/devops/ reltag>DevOps/a>, a hrefhttps://www.danturco.com/tag/github/ reltag>Github/a>, a hrefhttps://www.danturco.com/tag/helpers/ reltag>Helpers/a>, a hrefhttps://www.danturco.com/tag/javascript/ reltag>Javascript/a>, a hrefhttps://www.danturco.com/tag/s3-buckets/ reltag>S3 Buckets/a>, a hrefhttps://www.danturco.com/tag/shortcuts/ reltag>Shortcuts/a>, a hrefhttps://www.danturco.com/tag/tfs/ reltag>TFS/a>, a hrefhttps://www.danturco.com/tag/vsts/ reltag>VSTS/a> /span> /footer>!-- .entry-footer -->/article>!-- #post-## --> /main>!-- #main --> /div>!-- #primary -->div idsecondary classwidget-area rolecomplementary> aside idsearch-2 classwidget widget_search>form rolesearch methodget classsearch-form actionhttps://www.danturco.com/> label> span classscreen-reader-text>Search for:/span> input typesearch classsearch-field placeholderSearch … value names /> /label> input typesubmit classsearch-submit valueSearch /> /form>/aside>aside idblock-3 classwidget widget_block>h1 classwidget-title>Pages/h1>div classwp-widget-group__inner-blocks>ul classwp-block-page-list>li classwp-block-pages-list__item>a classwp-block-pages-list__item__link hrefhttps://www.danturco.com/sprint-planning-calculator/>Sprint Planning Calculator/a>/li>/ul>/div>/aside> aside idrecent-posts-4 classwidget widget_recent_entries> h1 classwidget-title>Recent Posts/h1> ul> li> a hrefhttps://www.danturco.com/setup-azure-internal-api-manager-with-application-gateway-without-custom-domains/>Setup Azure Internal API Manager with Application Gateway without Custom Domains/a> /li> li> a hrefhttps://www.danturco.com/custom-bulk-variables-in-postman/>Custom Bulk Variables in Postman/a> /li> li> a hrefhttps://www.danturco.com/vscode-and-tslint-tasks/>VSCode and TSLint tasks/a> /li> li> a hrefhttps://www.danturco.com/watching-for-changes-with-reactive-forms-in-angular4/>Watching for changes with Reactive Forms in Angular4/a> /li> li> a hrefhttps://www.danturco.com/using-ngdragula-with-ngprime-from-angular-4/>Using ngDragula with ngPrime from Angular 4/a> /li> /ul> /aside>aside idcategories-2 classwidget widget_categories>h1 classwidget-title>Categories/h1> ul> li classcat-item cat-item-3>a hrefhttps://www.danturco.com/category/bookmarklets/>Bookmarklets/a> (1)/li> li classcat-item cat-item-5>a hrefhttps://www.danturco.com/category/howd-they-do-that/>How'd they do that/a> (8)/li> /ul> /aside>aside idblog-stats-3 classwidget blog-stats>h1 classwidget-title>Who’s Read It/h1>ul>li>3,936 hits/li>/ul>/aside>aside idmeta-2 classwidget widget_meta>h1 classwidget-title>Meta/h1> ul> li>a hrefhttps://www.danturco.com/wp/wp-login.php>Log in/a>/li> li>a hrefhttps://www.danturco.com/feed/>Entries feed/a>/li> li>a hrefhttps://www.danturco.com/comments/feed/>Comments feed/a>/li> li>a hrefhttps://wordpress.org/>WordPress.org/a>/li> /ul> /aside>/div>!-- #secondary --> /div>!-- #content --> footer idcolophon classsite-footer rolecontentinfo> div classsite-info> a hrefhttp://wordpress.org/ target_blank>Proudly powered by WordPress/a> span classsep> | /span> Theme: Lonely Road by a hrefhttp://dbeja.com/ reldesigner target_blank>dbeja/a>. /div>!-- .site-info --> /footer>!-- #colophon -->/div>!-- #page -->script typespeculationrules>{prefetch:{source:document,where:{and:{href_matches:/*},{not:{href_matches:/wp/wp-*.php,/wp/wp-admin/*,/wp/wp-content/uploads/*,/wp/wp-content/*,/wp/wp-content/plugins/*,/wp/wp-content/themes/lonely-road/*,/*\\?(.+)}},{not:{selector_matches:arel~\nofollow\}},{not:{selector_matches:.no-prefetch, .no-prefetch a}}},eagerness:conservative}}/script>!-- Powered by WPtouch: 4.3.62 -->script typetext/javascript srchttps://www.danturco.com/wp/wp-content/themes/lonely-road/js/navigation.js?ver20120206 idlonely-road-navigation-js>/script>script typetext/javascript srchttps://www.danturco.com/wp/wp-content/themes/lonely-road/js/skip-link-focus-fix.js?ver20130115 idlonely-road-skip-link-focus-fix-js>/script>script typetext/javascript idjetpack-stats-js-before>/* !CDATA */_stq window._stq || ;_stq.push( view, {v:ext,blog:100301638,post:0,tz:0,srv:www.danturco.com,arch_home:1,j:1:15.5} );_stq.push( clickTrackerInit, 100301638, 0 );//# sourceURLjetpack-stats-js-before/* > *//script>script typetext/javascript srchttps://stats.wp.com/e-202607.js idjetpack-stats-js deferdefer data-wp-strategydefer>/script>script idwp-emoji-settings typeapplication/json>{baseUrl:https://s.w.org/images/core/emoji/17.0.2/72x72/,ext:.png,svgUrl:https://s.w.org/images/core/emoji/17.0.2/svg/,svgExt:.svg,source:{concatemoji:https://www.danturco.com/wp/wp-includes/js/wp-emoji-release.min.js?verc423a468a788fcb1d5bc115366fe3049}}/script>script typemodule>/* !CDATA *//*! This file is auto-generated */const aJSON.parse(document.getElementById(wp-emoji-settings).textContent),o(window._wpemojiSettingsa,wpEmojiSettingsSupports),sflag,emoji;function i(e){try{var t{supportTests:e,timestamp:(new Date).valueOf()};sessionStorage.setItem(o,JSON.stringify(t))}catch(e){}}function c(e,t,n){e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(t,0,0);tnew Uint32Array(e.getImageData(0,0,e.canvas.width,e.canvas.height).data);e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(n,0,0);const anew Uint32Array(e.getImageData(0,0,e.canvas.width,e.canvas.height).data);return t.every((e,t)>eat)}function p(e,t){e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(t,0,0);var ne.getImageData(16,16,1,1);for(let e0;en.data.length;e++)if(0!n.datae)return!1;return!0}function u(e,t,n,a){switch(t){caseflag:return n(e,\ud83c\udff3\ufe0f\u200d\u26a7\ufe0f,\ud83c\udff3\ufe0f\u200b\u26a7\ufe0f)?!1:!n(e,\ud83c\udde8\ud83c\uddf6,\ud83c\udde8\u200b\ud83c\uddf6)&&!n(e,\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f,\ud83c\udff4\u200b\udb40\udc67\u200b\udb40\udc62\u200b\udb40\udc65\u200b\udb40\udc6e\u200b\udb40\udc67\u200b\udb40\udc7f);caseemoji:return!a(e,\ud83e\u1fac8)}return!1}function f(e,t,n,a){let r;const o(rundefined!typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?new OffscreenCanvas(300,150):document.createElement(canvas)).getContext(2d,{willReadFrequently:!0}),s(o.textBaselinetop,o.font600 32px Arial,{});return e.forEach(e>{set(o,e,n,a)}),s}function r(e){var tdocument.createElement(script);t.srce,t.defer!0,document.head.appendChild(t)}a.supports{everything:!0,everythingExceptFlag:!0},new Promise(t>{let nfunction(){try{var eJSON.parse(sessionStorage.getItem(o));if(objecttypeof e&&numbertypeof e.timestamp&&(new Date).valueOf()e.timestamp+604800&&objecttypeof e.supportTests)return e.supportTests}catch(e){}return null}();if(!n){if(undefined!typeof Worker&&undefined!typeof OffscreenCanvas&&undefined!typeof URL&&URL.createObjectURL&&undefined!typeof Blob)try{var epostMessage(+f.toString()+(+JSON.stringify(s),u.toString(),c.toString(),p.toString().join(,)+));,anew Blob(e,{type:text/javascript});const rnew Worker(URL.createObjectURL(a),{name:wpTestEmojiSupports});return void(r.onmessagee>{i(ne.data),r.terminate(),t(n)})}catch(e){}i(nf(s,u,c,p))}t(n)}).then(e>{for(const n in e)a.supportsnen,a.supports.everythinga.supports.everything&&a.supportsn,flag!n&&(a.supports.everythingExceptFlaga.supports.everythingExceptFlag&&a.supportsn);var t;a.supports.everythingExceptFlaga.supports.everythingExceptFlag&&!a.supports.flag,a.supports.everything||((ta.source||{}).concatemoji?r(t.concatemoji):t.wpemoji&&t.twemoji&&(r(t.twemoji),r(t.wpemoji)))});//# sourceURLhttps://www.danturco.com/wp/wp-includes/js/wp-emoji-loader.min.js/* > *//script>/body>/html>
View on OTX
|
View on ThreatMiner
Please enable JavaScript to view the
comments powered by Disqus.
Data with thanks to
AlienVault OTX
,
VirusTotal
,
Malwr
and
others
. [
Sitemap
]